Mozilla/mozilla/widget/src/qt/nsCommonWidget.cpp
cbiesinger%web.de fa7f9459be fixing qt bustage from bug 289940
r+sr=jst a=shaver not part of default build


git-svn-id: svn://10.0.0.236/trunk@172893 18797224-902f-48f8-a5cc-f745e15eee43
2005-04-29 22:29:54 +00:00

1607 lines
42 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Zack Rusin <zack@kde.org>.
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Lars Knoll <knoll@kde.org>
* Zack Rusin <zack@kde.org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsCommonWidget.h"
#include "nsGUIEvent.h"
#include "nsQtEventDispatcher.h"
#include "nsIRenderingContext.h"
#include "nsIServiceManager.h"
#include "nsGfxCIID.h"
#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
#include "mozqwidget.h"
#include <qapplication.h>
#include <qdesktopwidget.h>
#include <qwidget.h>
#include <qcursor.h>
#include <execinfo.h>
#include <stdlib.h>
#include <execinfo.h>
#include <stdlib.h>
static const int WHEEL_DELTA = 120;
static const int kWindowPositionSlop = 20;
struct nsKeyConverter
{
int vkCode; // Platform independent key code
int keysym; // Qt key code
};
static void backTrace()
{
int levels = -1;
QString s;
void* trace[256];
int n = backtrace(trace, 256);
if (!n)
return;
char** strings = backtrace_symbols (trace, n);
if ( levels != -1 )
n = QMIN( n, levels );
s = "[\n";
for (int i = 0; i < n; ++i)
s += QString::number(i) +
QString::fromLatin1(": ") +
QString::fromLatin1(strings[i]) + QString::fromLatin1("\n");
s += "]\n";
if (strings)
free (strings);
qDebug("stacktrace:\n%s", s.latin1());
}
static struct nsKeyConverter nsKeycodes[] =
{
// { NS_VK_CANCEL, Qt::Key_Cancel },
{ NS_VK_BACK, Qt::Key_BackSpace },
{ NS_VK_TAB, Qt::Key_Tab },
// { NS_VK_CLEAR, Qt::Key_Clear },
{ NS_VK_RETURN, Qt::Key_Return },
{ NS_VK_RETURN, Qt::Key_Enter },
{ NS_VK_SHIFT, Qt::Key_Shift },
{ NS_VK_CONTROL, Qt::Key_Control },
{ NS_VK_ALT, Qt::Key_Alt },
{ NS_VK_PAUSE, Qt::Key_Pause },
{ NS_VK_CAPS_LOCK, Qt::Key_CapsLock },
{ NS_VK_ESCAPE, Qt::Key_Escape },
{ NS_VK_SPACE, Qt::Key_Space },
{ NS_VK_PAGE_UP, Qt::Key_PageUp },
{ NS_VK_PAGE_DOWN, Qt::Key_PageDown },
{ NS_VK_END, Qt::Key_End },
{ NS_VK_HOME, Qt::Key_Home },
{ NS_VK_LEFT, Qt::Key_Left },
{ NS_VK_UP, Qt::Key_Up },
{ NS_VK_RIGHT, Qt::Key_Right },
{ NS_VK_DOWN, Qt::Key_Down },
{ NS_VK_PRINTSCREEN, Qt::Key_Print },
{ NS_VK_INSERT, Qt::Key_Insert },
{ NS_VK_DELETE, Qt::Key_Delete },
{ NS_VK_0, Qt::Key_0 },
{ NS_VK_1, Qt::Key_1 },
{ NS_VK_2, Qt::Key_2 },
{ NS_VK_3, Qt::Key_3 },
{ NS_VK_4, Qt::Key_4 },
{ NS_VK_5, Qt::Key_5 },
{ NS_VK_6, Qt::Key_6 },
{ NS_VK_7, Qt::Key_7 },
{ NS_VK_8, Qt::Key_8 },
{ NS_VK_9, Qt::Key_9 },
{ NS_VK_SEMICOLON, Qt::Key_Semicolon },
{ NS_VK_EQUALS, Qt::Key_Equal },
{ NS_VK_A, Qt::Key_A },
{ NS_VK_B, Qt::Key_B },
{ NS_VK_C, Qt::Key_C },
{ NS_VK_D, Qt::Key_D },
{ NS_VK_E, Qt::Key_E },
{ NS_VK_F, Qt::Key_F },
{ NS_VK_G, Qt::Key_G },
{ NS_VK_H, Qt::Key_H },
{ NS_VK_I, Qt::Key_I },
{ NS_VK_J, Qt::Key_J },
{ NS_VK_K, Qt::Key_K },
{ NS_VK_L, Qt::Key_L },
{ NS_VK_M, Qt::Key_M },
{ NS_VK_N, Qt::Key_N },
{ NS_VK_O, Qt::Key_O },
{ NS_VK_P, Qt::Key_P },
{ NS_VK_Q, Qt::Key_Q },
{ NS_VK_R, Qt::Key_R },
{ NS_VK_S, Qt::Key_S },
{ NS_VK_T, Qt::Key_T },
{ NS_VK_U, Qt::Key_U },
{ NS_VK_V, Qt::Key_V },
{ NS_VK_W, Qt::Key_W },
{ NS_VK_X, Qt::Key_X },
{ NS_VK_Y, Qt::Key_Y },
{ NS_VK_Z, Qt::Key_Z },
{ NS_VK_NUMPAD0, Qt::Key_0 },
{ NS_VK_NUMPAD1, Qt::Key_1 },
{ NS_VK_NUMPAD2, Qt::Key_2 },
{ NS_VK_NUMPAD3, Qt::Key_3 },
{ NS_VK_NUMPAD4, Qt::Key_4 },
{ NS_VK_NUMPAD5, Qt::Key_5 },
{ NS_VK_NUMPAD6, Qt::Key_6 },
{ NS_VK_NUMPAD7, Qt::Key_7 },
{ NS_VK_NUMPAD8, Qt::Key_8 },
{ NS_VK_NUMPAD9, Qt::Key_9 },
{ NS_VK_MULTIPLY, Qt::Key_Asterisk },
{ NS_VK_ADD, Qt::Key_Plus },
// { NS_VK_SEPARATOR, Qt::Key_Separator },
{ NS_VK_SUBTRACT, Qt::Key_Minus },
{ NS_VK_DECIMAL, Qt::Key_Period },
{ NS_VK_DIVIDE, Qt::Key_Slash },
{ NS_VK_F1, Qt::Key_F1 },
{ NS_VK_F2, Qt::Key_F2 },
{ NS_VK_F3, Qt::Key_F3 },
{ NS_VK_F4, Qt::Key_F4 },
{ NS_VK_F5, Qt::Key_F5 },
{ NS_VK_F6, Qt::Key_F6 },
{ NS_VK_F7, Qt::Key_F7 },
{ NS_VK_F8, Qt::Key_F8 },
{ NS_VK_F9, Qt::Key_F9 },
{ NS_VK_F10, Qt::Key_F10 },
{ NS_VK_F11, Qt::Key_F11 },
{ NS_VK_F12, Qt::Key_F12 },
{ NS_VK_F13, Qt::Key_F13 },
{ NS_VK_F14, Qt::Key_F14 },
{ NS_VK_F15, Qt::Key_F15 },
{ NS_VK_F16, Qt::Key_F16 },
{ NS_VK_F17, Qt::Key_F17 },
{ NS_VK_F18, Qt::Key_F18 },
{ NS_VK_F19, Qt::Key_F19 },
{ NS_VK_F20, Qt::Key_F20 },
{ NS_VK_F21, Qt::Key_F21 },
{ NS_VK_F22, Qt::Key_F22 },
{ NS_VK_F23, Qt::Key_F23 },
{ NS_VK_F24, Qt::Key_F24 },
{ NS_VK_NUM_LOCK, Qt::Key_NumLock },
{ NS_VK_SCROLL_LOCK, Qt::Key_ScrollLock },
{ NS_VK_COMMA, Qt::Key_Comma },
{ NS_VK_PERIOD, Qt::Key_Period },
{ NS_VK_SLASH, Qt::Key_Slash },
{ NS_VK_BACK_QUOTE, Qt::Key_QuoteLeft },
{ NS_VK_OPEN_BRACKET, Qt::Key_ParenLeft },
{ NS_VK_CLOSE_BRACKET, Qt::Key_ParenRight },
{ NS_VK_QUOTE, Qt::Key_QuoteDbl },
{ NS_VK_META, Qt::Key_Meta }
};
static PRInt32 NS_GetKey(PRInt32 aKey)
{
PRInt32 length = sizeof(nsKeycodes) / sizeof(nsKeyConverter);
for (PRInt32 i = 0; i < length; i++) {
if (nsKeycodes[i].keysym == aKey) {
return nsKeycodes[i].vkCode;
}
}
return 0;
}
static PRBool
isContextMenuKey(const nsKeyEvent &aKeyEvent)
{
return ((aKeyEvent.keyCode == NS_VK_F10 && aKeyEvent.isShift &&
!aKeyEvent.isControl && !aKeyEvent.isMeta && !aKeyEvent.isAlt) ||
(aKeyEvent.keyCode == NS_VK_CONTEXT_MENU && !aKeyEvent.isShift &&
!aKeyEvent.isControl && !aKeyEvent.isMeta && !aKeyEvent.isAlt));
}
static void
keyEventToContextMenuEvent(const nsKeyEvent* aKeyEvent,
nsMouseEvent* aCMEvent)
{
memcpy(aCMEvent, aKeyEvent, sizeof(nsInputEvent));
aCMEvent->message = NS_CONTEXTMENU_KEY;
aCMEvent->isShift = aCMEvent->isControl = PR_FALSE;
aCMEvent->isAlt = aCMEvent->isMeta = PR_FALSE;
aCMEvent->clickCount = 0;
aCMEvent->acceptActivation = PR_FALSE;
}
nsCommonWidget::nsCommonWidget()
: mContainer(0),
mWidget(0),
mListenForResizes(PR_FALSE),
mNeedsResize(PR_FALSE),
mNeedsShow(PR_FALSE),
mIsShown(PR_FALSE)
{
}
NS_IMPL_ISUPPORTS_INHERITED0(nsCommonWidget,nsBaseWidget)
nsCommonWidget::~nsCommonWidget()
{
mWidget->deleteLater();
mWidget = 0;
}
void
nsCommonWidget::Initialize(QWidget *widget)
{
Q_ASSERT(widget);
mWidget = widget;
mWidget->setMouseTracking(PR_TRUE);
mWidget->setFocusPolicy(QWidget::WheelFocus);
}
NS_IMETHODIMP
nsCommonWidget::Show(PRBool aState)
{
mIsShown = aState;
// Ok, someone called show on a window that isn't sized to a sane
// value. Mark this window as needing to have Show() called on it
// and return.
if ((aState && !AreBoundsSane()) || !mWidget) {
#ifdef DEBUG_WIDGETS
qWarning("XX Bounds are insane or window hasn't been created yet");
#endif
mNeedsShow = PR_TRUE;
return NS_OK;
}
// If someone is hiding this widget, clear any needing show flag.
if (!aState)
mNeedsShow = PR_FALSE;
// If someone is showing this window and it needs a resize then
// resize the widget.
if (aState && mNeedsResize) {
#ifdef DEBUG_WIDGETS
qDebug("\tresizing [%d, %d, %d, %d]", mBounds.x, mBounds.y,
mBounds.width, mBounds.height);
#endif
NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height,
PR_FALSE);
}
NativeShow(aState);
return NS_OK;
}
NS_IMETHODIMP
nsCommonWidget::IsVisible(PRBool &visible)
{
if (mWidget)
visible = mWidget->isVisible();
else
visible = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsCommonWidget::ConstrainPosition(PRBool aAllowSlop, PRInt32 *aX, PRInt32 *aY)
{
if (mContainer) {
PRInt32 screenWidth = QApplication::desktop()->width();
PRInt32 screenHeight = QApplication::desktop()->height();
if (aAllowSlop) {
if (*aX < (kWindowPositionSlop - mBounds.width))
*aX = kWindowPositionSlop - mBounds.width;
if (*aX > (screenWidth - kWindowPositionSlop))
*aX = screenWidth - kWindowPositionSlop;
if (*aY < (kWindowPositionSlop - mBounds.height))
*aY = kWindowPositionSlop - mBounds.height;
if (*aY > (screenHeight - kWindowPositionSlop))
*aY = screenHeight - kWindowPositionSlop;
} else {
if (*aX < 0)
*aX = 0;
if (*aX > (screenWidth - mBounds.width))
*aX = screenWidth - mBounds.width;
if (*aY < 0)
*aY = 0;
if (*aY > (screenHeight - mBounds.height))
*aY = screenHeight - mBounds.height;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsCommonWidget::Move(PRInt32 x, PRInt32 y)
{
bool popup = mWidget ? mWidget->isPopup() : false;
if (!mWidget || (x == mBounds.x && y == mBounds.y &&
!popup))
return NS_OK;
#ifdef DEBUG_WIDGETS
qDebug("Move [%d,%d] (%s)", x, y, popup?"popup":"widget");
#endif
if (!mWidget)
return NS_OK;
QPoint pos(x, y);
if (mContainer) {
if (mParent && mWidget->isPopup()) {
nsRect oldrect, newrect;
oldrect.x = x;
oldrect.y = y;
mParent->WidgetToScreen(oldrect, newrect);
pos = QPoint(newrect.x, newrect.y);
#ifdef DEBUG_WIDGETS
qDebug("pos is [%d,%d]", pos.x(), pos.y());
#endif
} else {
qDebug("Widget within another? (%p)", (void*)mWidget);
}
}
mBounds.x = pos.x();
mBounds.y = pos.y();
mWidget->move(pos);
return NS_OK;
}
NS_IMETHODIMP
nsCommonWidget::Resize(PRInt32 aWidth,
PRInt32 aHeight,
PRBool aRepaint)
{
mBounds.width = aWidth;
mBounds.height = aHeight;
if (!mWidget || (mWidget->width() == aWidth &&
mWidget->height() == aHeight))
return NS_OK;
// There are several cases here that we need to handle, based on a
// matrix of the visibility of the widget, the sanity of this resize
// and whether or not the widget was previously sane.
// Has this widget been set to visible?
if (mIsShown) {
// Are the bounds sane?
if (AreBoundsSane()) {
// Yep? Resize the window
//Maybe, the toplevel has moved
if (mContainer || mNeedsShow)
NativeResize(mBounds.x, mBounds.y,
mBounds.width, mBounds.height, aRepaint);
else
NativeResize(mBounds.width, mBounds.height, aRepaint);
// Does it need to be shown because it was previously insane?
if (mNeedsShow)
NativeShow(PR_TRUE);
}
else {
// If someone has set this so that the needs show flag is false
// and it needs to be hidden, update the flag and hide the
// window. This flag will be cleared the next time someone
// hides the window or shows it. It also prevents us from
// calling NativeShow(PR_FALSE) excessively on the window which
// causes unneeded X traffic.
if (!mNeedsShow) {
mNeedsShow = PR_TRUE;
NativeShow(PR_FALSE);
}
}
}
// If the widget hasn't been shown, mark the widget as needing to be
// resized before it is shown.
else {
if (AreBoundsSane() && mListenForResizes) {
// For widgets that we listen for resizes for (widgets created
// with native parents) we apparently _always_ have to resize. I
// dunno why, but apparently we're lame like that.
NativeResize(aWidth, aHeight, aRepaint);
}
else {
mNeedsResize = PR_TRUE;
}
}
// synthesize a resize event if this isn't a toplevel
if (mContainer || mListenForResizes) {
nsRect rect(mBounds.x, mBounds.y, aWidth, aHeight);
nsEventStatus status;
DispatchResizeEvent(rect, status);
}
return NS_OK;
}
/*
* XXXX: This sucks because it basically hardcore duplicates the
* code from the above function.
*/
NS_IMETHODIMP
nsCommonWidget::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight,
PRBool aRepaint)
{
#ifdef DEBUG_WIDGETS
qDebug("Resize : [%d,%d,%d,%d]", aX, aY, aWidth, aHeight);
#endif
if (!mWidget || (mWidget->x() == aX &&
mWidget->y() == aY &&
mWidget->height() == aHeight &&
mWidget->width() == aWidth))
return NS_OK;
mBounds.x = aX;
mBounds.y = aY;
mBounds.width = aWidth;
mBounds.height = aHeight;
// There are several cases here that we need to handle, based on a
// matrix of the visibility of the widget, the sanity of this resize
// and whether or not the widget was previously sane.
// Has this widget been set to visible?
if (mIsShown) {
// Are the bounds sane?
if (AreBoundsSane()) {
// Yep? Resize the window
NativeResize(aX, aY, aWidth, aHeight, aRepaint);
// Does it need to be shown because it was previously insane?
if (mNeedsShow)
NativeShow(PR_TRUE);
}
else {
// If someone has set this so that the needs show flag is false
// and it needs to be hidden, update the flag and hide the
// window. This flag will be cleared the next time someone
// hides the window or shows it. It also prevents us from
// calling NativeShow(PR_FALSE) excessively on the window which
// causes unneeded X traffic.
if (!mNeedsShow) {
mNeedsShow = PR_TRUE;
NativeShow(PR_FALSE);
}
}
}
// If the widget hasn't been shown, mark the widget as needing to be
// resized before it is shown
else {
if (AreBoundsSane() && mListenForResizes){
// For widgets that we listen for resizes for (widgets created
// with native parents) we apparently _always_ have to resize. I
// dunno why, but apparently we're lame like that.
NativeResize(aX, aY, aWidth, aHeight, aRepaint);
}
else {
mNeedsResize = PR_TRUE;
}
}
// synthesize a resize event if this isn't a toplevel
if (mContainer || mListenForResizes) {
nsRect rect(mBounds.x, mBounds.y, mBounds.width, mBounds.height);
nsEventStatus status;
DispatchResizeEvent(rect, status);
}
return NS_OK;
}
NS_IMETHODIMP
nsCommonWidget::Enable(PRBool aState)
{
if (mWidget)
mWidget->setEnabled(aState);
return NS_OK;
}
NS_IMETHODIMP
nsCommonWidget::IsEnabled(PRBool *aState)
{
if (mWidget)
*aState = mWidget->isEnabled();
return NS_OK;
}
NS_IMETHODIMP
nsCommonWidget::SetFocus(PRBool aRaise)
{
#ifdef DEBUG_WIDGETS
qDebug("SetFocus mWidget=%p, mContainer=%p, focuswidget=%p (%d)",
(void*)mWidget, (void*)mContainer, (void*)mWidget->focusWidget());
#endif
if (mWidget) {
if (aRaise)
mWidget->raise();
mWidget->setFocus();
DispatchGotFocusEvent();
}
return NS_OK;
}
nsIFontMetrics*
nsCommonWidget::GetFont()
{
#ifdef DEBUG_WIDGETS
qWarning("nsCommonWidget.cpp: GetFont not implemented");
#endif
return nsnull;
}
NS_IMETHODIMP
nsCommonWidget::SetFont(const nsFont&)
{
return NS_OK;
}
NS_IMETHODIMP
nsCommonWidget::Invalidate(PRBool aIsSynchronous)
{
#ifdef DEBUG_WIDGETS
qDebug("nsCommonWidget::Invalidate1 container=%p widget=%p", (void*)mContainer, (void*)mWidget);
#endif
if (!mWidget)
return NS_OK;
if (aIsSynchronous)
mWidget->repaint();
else
mWidget->update();
return NS_OK;
}
NS_IMETHODIMP
nsCommonWidget::Invalidate(const nsRect & aRect, PRBool aIsSynchronous)
{
#ifdef DEBUG_WIDGETS
qDebug("nsCommonWidget::Invalidate2 container=%p widget=%p", (void*)mContainer, (void*)mWidget);
#endif
if (!mWidget)
return NS_OK;
if (aIsSynchronous)
mWidget->repaint(aRect.x, aRect.y, aRect.width, aRect.height);
else
mWidget->update(aRect.x, aRect.y, aRect.width, aRect.height);
return NS_OK;
}
NS_IMETHODIMP
nsCommonWidget::Update()
{
#ifdef DEBUG_WIDGETS
qDebug("nsCommonWidget::Update container=%p widget=%p", (void*)mContainer, (void*)mWidget);
#endif
if (!mWidget)
return NS_OK;
mWidget->update();
return NS_OK;
}
NS_IMETHODIMP
nsCommonWidget::SetColorMap(nsColorMap*)
{
return NS_OK;
}
NS_IMETHODIMP
nsCommonWidget::Scroll(int aDx, int aDy, nsRect *aClipRect)
{
if (mWidget)
mWidget->scroll(aDx, aDy);
// Update bounds on our child windows
for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) {
nsRect bounds;
kid->GetBounds(bounds);
bounds.x += aDx;
bounds.y += aDy;
NS_STATIC_CAST(nsBaseWidget*, kid)->SetBounds(bounds);
}
return NS_OK;
}
NS_IMETHODIMP
nsCommonWidget::ScrollWidgets(PRInt32 aDx,
PRInt32 aDy)
{
if (mWidget)
mWidget->scroll(aDx, aDy);
return NS_OK;
}
void*
nsCommonWidget::GetNativeData(PRUint32 aDataType)
{
switch(aDataType) {
case NS_NATIVE_WINDOW:
return mWidget;
break;
case NS_NATIVE_DISPLAY:
if (mWidget)
return mWidget->x11Display();
break;
case NS_NATIVE_WIDGET:
return mWidget;
break;
case NS_NATIVE_PLUGIN_PORT:
if (mWidget)
return (void*)mWidget->winId();
break;
default:
break;
}
return nsnull;
}
NS_IMETHODIMP
nsCommonWidget::SetTitle(const nsAString &str)
{
nsAString::const_iterator it;
QString qStr = QString::fromUcs2(str.BeginReading(it).get());
if (mContainer)
mContainer->setCaption(qStr);
return NS_OK;
}
NS_IMETHODIMP
nsCommonWidget::SetMenuBar(nsIMenuBar*)
{
qWarning("XXXXX SetMenuBar");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCommonWidget::ShowMenuBar(int)
{
qWarning("XXXXX ShowMenuBar");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCommonWidget::WidgetToScreen(const nsRect &aOldRect, nsRect &aNewRect)
{
aNewRect.width = aOldRect.width;
aNewRect.height = aOldRect.height;
if (mWidget) {
PRInt32 x,y;
QPoint offset(0,0);
offset = mWidget->mapToGlobal(offset);
x = offset.x();
y = offset.y();
aNewRect.x = aOldRect.x + x;
aNewRect.y = aOldRect.y + y;
}
return NS_OK;
}
NS_IMETHODIMP
nsCommonWidget::ScreenToWidget(const nsRect &aOldRect, nsRect &aNewRect)
{
if (mWidget) {
PRInt32 X,Y;
QPoint offset(0,0);
offset = mWidget->mapFromGlobal(offset);
X = offset.x();
Y = offset.y();
aNewRect.x = aOldRect.x + X;
aNewRect.y = aOldRect.y + Y;
}
return NS_OK;
}
NS_IMETHODIMP
nsCommonWidget::BeginResizingChildren()
{
qWarning("XXXXXX BeginResizingChildren");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCommonWidget::EndResizingChildren()
{
qWarning("XXXXXXX EndResizingChildren");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCommonWidget::GetPreferredSize(PRInt32 &aWidth, PRInt32 &aHeight)
{
if (!mWidget)
return NS_ERROR_FAILURE;
QSize sh = mWidget->sizeHint();
aWidth = QMAX(0, sh.width());
aHeight = QMAX(0, sh.height());
return NS_OK;
}
NS_IMETHODIMP
nsCommonWidget::SetPreferredSize(int w, int h)
{
qWarning("XXX SetPreferredSize %d %d", w, h);
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCommonWidget::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus &aStatus)
{
aStatus = nsEventStatus_eIgnore;
// hold a widget reference while we dispatch this event
NS_ADDREF(aEvent->widget);
if (mEventCallback)
aStatus = (*mEventCallback)(aEvent);
// dispatch to event listener if event was not consumed
if ((aStatus != nsEventStatus_eIgnore) && mEventListener)
aStatus = mEventListener->ProcessEvent(*aEvent);
NS_IF_RELEASE(aEvent->widget);
return NS_OK;
}
NS_IMETHODIMP
nsCommonWidget::CaptureRollupEvents(nsIRollupListener*, PRBool, PRBool)
{
return NS_OK;
}
void
nsCommonWidget::DispatchGotFocusEvent(void)
{
nsGUIEvent event(PR_TRUE, NS_GOTFOCUS, this);
nsEventStatus status;
DispatchEvent(&event, status);
}
void
nsCommonWidget::DispatchLostFocusEvent(void)
{
nsGUIEvent event(PR_TRUE, NS_LOSTFOCUS, this);
nsEventStatus status;
DispatchEvent(&event, status);
}
void
nsCommonWidget::DispatchActivateEvent(void)
{
nsGUIEvent event(PR_TRUE, NS_ACTIVATE, this);
nsEventStatus status;
DispatchEvent(&event, status);
}
void
nsCommonWidget::DispatchDeactivateEvent(void)
{
nsGUIEvent event(PR_TRUE, NS_DEACTIVATE, this);
nsEventStatus status;
DispatchEvent(&event, status);
}
void
nsCommonWidget::DispatchResizeEvent(nsRect &aRect, nsEventStatus &aStatus)
{
nsSizeEvent event(PR_TRUE, NS_SIZE, this);
event.windowSize = &aRect;
event.point.x = aRect.x;
event.point.y = aRect.y;
event.mWinWidth = aRect.width;
event.mWinHeight = aRect.height;
DispatchEvent(&event, aStatus);
}
bool
nsCommonWidget::mousePressEvent(QMouseEvent *e)
{
//qDebug("mousePressEvent mWidget=%p", (void*)mWidget);
// backTrace();
PRUint32 eventType;
switch (e->button()) {
case Qt::MidButton:
eventType = NS_MOUSE_MIDDLE_BUTTON_DOWN;
break;
case Qt::RightButton:
eventType = NS_MOUSE_RIGHT_BUTTON_DOWN;
break;
default:
eventType = NS_MOUSE_LEFT_BUTTON_DOWN;
break;
}
nsMouseEvent event(PR_TRUE, eventType, this, nsMouseEvent::eReal);
InitMouseEvent(&event, e, 1);
nsEventStatus status;
DispatchEvent(&event, status);
// right menu click on linux should also pop up a context menu
if (eventType == NS_MOUSE_RIGHT_BUTTON_DOWN) {
nsMouseEvent contextMenuEvent(PR_TRUE, NS_CONTEXTMENU, this,
nsMouseEvent::eReal);
InitMouseEvent(&contextMenuEvent, e, 1);
DispatchEvent(&contextMenuEvent, status);
}
return ignoreEvent(status);
}
bool
nsCommonWidget::mouseReleaseEvent(QMouseEvent *e)
{
//qDebug("mouseReleaseEvent mWidget=%p", (void*)mWidget);
PRUint32 eventType;
switch (e->button()) {
case Qt::MidButton:
eventType = NS_MOUSE_MIDDLE_BUTTON_UP;
break;
case Qt::RightButton:
eventType = NS_MOUSE_RIGHT_BUTTON_UP;
break;
default:
eventType = NS_MOUSE_LEFT_BUTTON_UP;
break;
}
nsMouseEvent event(PR_TRUE, eventType, this, nsMouseEvent::eReal);
InitMouseEvent(&event, e, 1);
//not pressed
nsEventStatus status;
DispatchEvent(&event, status);
return ignoreEvent(status);
}
bool
nsCommonWidget::mouseDoubleClickEvent(QMouseEvent *e)
{
PRUint32 eventType;
switch (e->button()) {
case Qt::MidButton:
eventType = NS_MOUSE_MIDDLE_BUTTON_DOWN;
break;
case Qt::RightButton:
eventType = NS_MOUSE_RIGHT_BUTTON_DOWN;
break;
default:
eventType = NS_MOUSE_LEFT_BUTTON_DOWN;
break;
}
nsMouseEvent event(PR_TRUE, eventType, this, nsMouseEvent::eReal);
InitMouseEvent(&event, e, 2);
//pressed
nsEventStatus status;
DispatchEvent(&event, status);
return ignoreEvent(status);
}
bool
nsCommonWidget::mouseMoveEvent(QMouseEvent *e)
{
nsMouseEvent event(PR_TRUE, NS_MOUSE_MOVE, this, nsMouseEvent::eReal);
InitMouseEvent(&event, e, 0);
nsEventStatus status;
DispatchEvent(&event, status);
return ignoreEvent(status);
}
bool
nsCommonWidget::wheelEvent(QWheelEvent *e)
{
nsMouseScrollEvent nsEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
InitMouseWheelEvent(&nsEvent, e);
nsEventStatus status;
DispatchEvent(&nsEvent, status);
return ignoreEvent(status);
}
bool
nsCommonWidget::keyPressEvent(QKeyEvent *e)
{
//qDebug("keyPressEvent");
nsEventStatus status;
// If the key repeat flag isn't set then set it so we don't send
// another key down event on the next key press -- DOM events are
// key down, key press and key up. X only has key press and key
// release. gtk2 already filters the extra key release events for
// us.
nsKeyEvent pressEvent(PR_TRUE, NS_KEY_PRESS, this);
InitKeyEvent(&pressEvent, e);
pressEvent.charCode = (PRInt32)e->text()[0].unicode();
if (!e->isAutoRepeat()) {
// send the key down event
nsKeyEvent downEvent(PR_TRUE, NS_KEY_DOWN, this);
InitKeyEvent(&downEvent, e);
DispatchEvent(&downEvent, status);
if (ignoreEvent(status)) { // If prevent default on keydown, do same for keypress
pressEvent.flags |= NS_EVENT_FLAG_NO_DEFAULT;
}
}
// before we dispatch a key, check if it's the context menu key.
// If so, send a context menu key event instead.
if (isContextMenuKey(pressEvent)) {
nsMouseEvent contextMenuEvent(PR_TRUE, 0, nsnull, nsMouseEvent::eReal);
keyEventToContextMenuEvent(&pressEvent, &contextMenuEvent);
DispatchEvent(&contextMenuEvent, status);
}
else {
// send the key press event
DispatchEvent(&pressEvent, status);
}
return ignoreEvent(status);
}
bool
nsCommonWidget::keyReleaseEvent(QKeyEvent *e)
{
nsKeyEvent event(PR_TRUE, NS_KEY_UP, this);
InitKeyEvent(&event, e);
nsEventStatus status;
DispatchEvent(&event, status);
return ignoreEvent(status);
}
bool
nsCommonWidget::focusInEvent(QFocusEvent *)
{
if (!mWidget)
return FALSE;
#ifdef DEBUG_WIDGETS
qDebug("focusInEvent mWidget=%p, mContainer=%p", (void*)mWidget, (void*)mContainer);
#endif
DispatchGotFocusEvent();
DispatchActivateEvent();
return FALSE;
}
bool
nsCommonWidget::focusOutEvent(QFocusEvent *)
{
#ifdef DEBUG_WIDGETS
qDebug("focusOutEvent mWidget=%p,mContainer = %p", (void*)mWidget, (void*)mContainer);
#endif
DispatchLostFocusEvent();
if (mContainer)
DispatchDeactivateEvent();
return FALSE;
}
bool
nsCommonWidget::enterEvent(QEvent *)
{
nsMouseEvent event(PR_TRUE, NS_MOUSE_ENTER, this, nsMouseEvent::eReal);
QPoint pt = QCursor::pos();
event.point.x = nscoord(pt.x());
event.point.y = nscoord(pt.y());
nsEventStatus status;
DispatchEvent(&event, status);
return FALSE;
}
bool
nsCommonWidget::leaveEvent(QEvent *aEvent)
{
nsMouseEvent event(PR_TRUE, NS_MOUSE_EXIT, this, nsMouseEvent::eReal);
QPoint pt = QCursor::pos();
event.point.x = nscoord(pt.x());
event.point.y = nscoord(pt.y());
nsEventStatus status;
DispatchEvent(&event, status);
return FALSE;
}
bool
nsCommonWidget::paintEvent(QPaintEvent *e)
{
//qDebug("paintEvent: mWidget=%p x = %d, y = %d, width = %d, height = %d", (void*)mWidget,
//e->rect().x(), e->rect().y(), e->rect().width(), e->rect().height());
// qDebug("paintEvent: Widgetrect %d %d %d %d", mWidget->x(), mWidget->y(),
// mWidget->width(), mWidget->height());
QRect r = e->rect();
if (!r.isValid())
r = mWidget->rect();
nsRect rect(r.x(), r.y(), r.width(), r.height());
nsCOMPtr<nsIRenderingContext> rc = getter_AddRefs(GetRenderingContext());
// Generate XPFE paint event
nsPaintEvent event(PR_TRUE, NS_PAINT, this);
event.point.x = 0;
event.point.y = 0;
event.rect = &rect;
// XXX fix this!
event.region = nsnull;
// XXX fix this!
event.renderingContext = rc;
nsEventStatus status;
DispatchEvent(&event, status);
return ignoreEvent(status);
}
bool
nsCommonWidget::moveEvent(QMoveEvent *e)
{
// can we shortcut?
if (!mWidget || (mBounds.x == e->pos().x() &&
mBounds.y == e->pos().y()))
return FALSE;
#ifdef DEBUG_WIDGETS
bool shown = mWidget ? mWidget->isShown() : false;
bool popup = mWidget ? mWidget->isPopup() : false;
qDebug("moveEvent mWidget=%p %d %d (%s, %s)", (void*)mWidget, e->pos().x(), e->pos().y(),
shown? "shown": "hidden", popup ? "popup": "widget");
#endif
// Toplevel windows need to have their bounds set so that we can
// keep track of our location. It's not often that the x,y is set
// by the layout engine. Width and height are set elsewhere.
QPoint pos = e->pos();
if (mContainer) {
// Need to translate this into the right coordinates
nsRect oldrect, newrect;
WidgetToScreen(oldrect, newrect);
mBounds.x = newrect.x;
mBounds.y = newrect.y;
#ifdef DEBUG_WIDGETS
qDebug("BOUNDS are [%d, %d]", mBounds.x, mBounds.y);
#endif
}
nsGUIEvent event(PR_TRUE, NS_MOVE, this);
event.point.x = pos.x();
event.point.y = pos.y();
// XXX mozilla will invalidate the entire window after this move
// complete. wtf?
nsEventStatus status;
DispatchEvent(&event, status);
return ignoreEvent(status);
}
bool
nsCommonWidget::resizeEvent(QResizeEvent *e)
{
nsRect rect;
// Generate XPFE resize event
GetBounds(rect);
rect.width = e->size().width();
rect.height = e->size().height();
mBounds.width = rect.width;
mBounds.height = rect.height;
#ifdef DEBUG_WIDGETS
qDebug("resizeEvent: mWidget=%p, aWidth=%d, aHeight=%d, aX = %d, aY = %d", (void*)mWidget,
rect.width, rect.height, rect.x, rect.y);
#endif
nsEventStatus status;
DispatchResizeEvent(rect, status);
return ignoreEvent(status);
}
bool
nsCommonWidget::closeEvent(QCloseEvent *)
{
nsGUIEvent event(PR_TRUE, NS_XUL_CLOSE, this);
event.point.x = 0;
event.point.y = 0;
nsEventStatus status;
DispatchEvent(&event, status);
return ignoreEvent(status);
}
bool
nsCommonWidget::contextMenuEvent(QContextMenuEvent *)
{
//qDebug("context menu");
return false;
}
bool
nsCommonWidget::imStartEvent(QIMEvent *)
{
qWarning("XXX imStartEvent");
return false;
}
bool
nsCommonWidget::imComposeEvent(QIMEvent *)
{
qWarning("XXX imComposeEvent");
return false;
}
bool
nsCommonWidget::imEndEvent(QIMEvent * )
{
qWarning("XXX imComposeEvent");
return false;
}
bool
nsCommonWidget::dragEnterEvent(QDragEnterEvent *)
{
qDebug("XXX dragEnterEvent");
return false;
}
bool
nsCommonWidget::dragMoveEvent(QDragMoveEvent *)
{
qDebug("XXX dragMoveEvent");
return false;
}
bool
nsCommonWidget::dragLeaveEvent(QDragLeaveEvent *)
{
qDebug("XXX dragLeaveEvent");
return false;
}
bool
nsCommonWidget::dropEvent(QDropEvent *)
{
qDebug("XXX dropEvent");
return false;
}
bool
nsCommonWidget::showEvent(QShowEvent *)
{
#ifdef DEBUG_WIDGETS
qDebug("showEvent mWidget=%p", (void*)mWidget);
#endif
QRect r = mWidget->rect();
nsRect rect(r.x(), r.y(), r.width(), r.height());
nsCOMPtr<nsIRenderingContext> rc = getter_AddRefs(GetRenderingContext());
// Generate XPFE paint event
nsPaintEvent event(PR_TRUE, NS_PAINT, this);
event.point.x = 0;
event.point.y = 0;
event.rect = &rect;
// XXX fix this!
event.region = nsnull;
// XXX fix this!
event.renderingContext = rc;
nsEventStatus status;
DispatchEvent(&event, status);
return false;
}
bool
nsCommonWidget::hideEvent(QHideEvent *)
{
#ifdef DEBUG_WIDGETS
qDebug("hideEvent mWidget=%p", (void*)mWidget);
#endif
return false;
}
void
nsCommonWidget::InitKeyEvent(nsKeyEvent *nsEvent, QKeyEvent *qEvent)
{
nsEvent->isShift = qEvent->state() & Qt::ShiftButton;
nsEvent->isControl = qEvent->state() & Qt::ControlButton;
nsEvent->isAlt = qEvent->state() & Qt::AltButton;
nsEvent->isMeta = qEvent->state() & Qt::MetaButton;
nsEvent->time = 0;
if (qEvent->text().length() && qEvent->text()[0].isPrint()) {
nsEvent->charCode = (PRInt32)qEvent->text()[0].unicode();
}
else {
nsEvent->charCode = 0;
}
if (nsEvent->charCode) {
nsEvent->keyCode = 0;
}
else {
nsEvent->keyCode = NS_GetKey(qEvent->key());
}
}
void
nsCommonWidget::InitMouseEvent(nsMouseEvent *nsEvent, QMouseEvent *qEvent, int aClickCount)
{
nsEvent->point.x = nscoord(qEvent->x());
nsEvent->point.y = nscoord(qEvent->y());
nsEvent->isShift = qEvent->state() & Qt::ShiftButton;
nsEvent->isControl = qEvent->state() & Qt::ControlButton;
nsEvent->isAlt = qEvent->state() & Qt::AltButton;
nsEvent->isMeta = qEvent->state() & Qt::MetaButton;
nsEvent->clickCount = aClickCount;
}
void
nsCommonWidget::InitMouseWheelEvent(nsMouseScrollEvent *aEvent,
QWheelEvent *qEvent)
{
switch (qEvent->orientation()) {
case Qt::Vertical:
aEvent->scrollFlags = nsMouseScrollEvent::kIsVertical;
break;
case Qt::Horizontal:
aEvent->scrollFlags = nsMouseScrollEvent::kIsHorizontal;
break;
default:
Q_ASSERT(0);
break;
}
aEvent->delta = (int)((qEvent->delta() / WHEEL_DELTA) * -3);
aEvent->point.x = nscoord(qEvent->x());
aEvent->point.y = nscoord(qEvent->y());
aEvent->isShift = qEvent->state() & Qt::ShiftButton;
aEvent->isControl = qEvent->state() & Qt::ControlButton;
aEvent->isAlt = qEvent->state() & Qt::AltButton;
aEvent->isMeta = qEvent->state() & Qt::MetaButton;
aEvent->time = 0;
}
void
nsCommonWidget::CommonCreate(nsIWidget *aParent, PRBool aListenForResizes)
{
mParent = aParent;
mListenForResizes = aListenForResizes;
}
PRBool
nsCommonWidget::AreBoundsSane() const
{
if (mBounds.width > 0 && mBounds.height > 0)
return PR_TRUE;
return PR_FALSE;
}
NS_IMETHODIMP
nsCommonWidget::Create(nsIWidget *aParent, const nsRect &aRect, EVENT_CALLBACK aHandleEventFunction,
nsIDeviceContext *aContext, nsIAppShell *aAppShell, nsIToolkit *aToolkit,
nsWidgetInitData *aInitData)
{
return NativeCreate(aParent, nsnull, aRect, aHandleEventFunction, aContext, aAppShell,
aToolkit, aInitData);
}
NS_IMETHODIMP
nsCommonWidget::Create(nsNativeWidget aParent, const nsRect &aRect, EVENT_CALLBACK aHandleEventFunction,
nsIDeviceContext *aContext, nsIAppShell *aAppShell, nsIToolkit *aToolkit,
nsWidgetInitData *aInitData)
{
return NativeCreate(nsnull, (QWidget*)aParent, aRect, aHandleEventFunction, aContext, aAppShell,
aToolkit, aInitData);
}
nsresult
nsCommonWidget::NativeCreate(nsIWidget *aParent,
QWidget *aNativeParent,
const nsRect &aRect,
EVENT_CALLBACK aHandleEventFunction,
nsIDeviceContext *aContext,
nsIAppShell *aAppShell,
nsIToolkit *aToolkit,
nsWidgetInitData *aInitData)
{
// only set the base parent if we're going to be a dialog or a
// toplevel
nsIWidget *baseParent = aInitData &&
(aInitData->mWindowType == eWindowType_dialog ||
aInitData->mWindowType == eWindowType_toplevel ||
aInitData->mWindowType == eWindowType_invisible) ?
nsnull : aParent;
// initialize all the common bits of this class
BaseCreate(baseParent, aRect, aHandleEventFunction, aContext,
aAppShell, aToolkit, aInitData);
// Do we need to listen for resizes?
PRBool listenForResizes = PR_FALSE;;
if (aNativeParent || (aInitData && aInitData->mListenForResizes))
listenForResizes = PR_TRUE;
// and do our common creation
CommonCreate(aParent, listenForResizes);
// save our bounds
mBounds = aRect;
QWidget *parent = 0;
if (aParent != nsnull)
parent = (QWidget*)aParent->GetNativeData(NS_NATIVE_WIDGET);
else
parent = aNativeParent;
mWidget = createQWidget(parent, aInitData);
Initialize(mWidget);
Resize(mBounds.width, mBounds.height, PR_FALSE);
return NS_OK;
}
nsCursor nsCommonWidget::GetCursor()
{
return mCursor;
}
NS_METHOD nsCommonWidget::SetCursor(nsCursor aCursor)
{
mCursor = aCursor;
Qt::CursorShape cursor = Qt::ArrowCursor;
switch(mCursor) {
case eCursor_standard:
cursor = Qt::ArrowCursor;
break;
case eCursor_wait:
cursor = Qt::WaitCursor;
break;
case eCursor_select:
cursor = Qt::IbeamCursor;
break;
case eCursor_hyperlink:
cursor = Qt::PointingHandCursor;
break;
case eCursor_ew_resize:
cursor = Qt::SplitHCursor;
break;
case eCursor_ns_resize:
cursor = Qt::SplitVCursor;
break;
case eCursor_nw_resize:
case eCursor_se_resize:
cursor = Qt::SizeBDiagCursor;
break;
case eCursor_ne_resize:
case eCursor_sw_resize:
cursor = Qt::SizeFDiagCursor;
break;
case eCursor_crosshair:
case eCursor_move:
cursor = Qt::SizeAllCursor;
break;
case eCursor_help:
cursor = Qt::WhatsThisCursor;
break;
case eCursor_copy:
case eCursor_alias:
break;
case eCursor_context_menu:
case eCursor_cell:
case eCursor_grab:
case eCursor_grabbing:
case eCursor_spinning:
case eCursor_zoom_in:
case eCursor_zoom_out:
default:
break;
}
mWidget->setCursor(cursor);
return NS_OK;
}
bool nsCommonWidget::ignoreEvent(nsEventStatus aStatus) const
{
switch(aStatus) {
case nsEventStatus_eIgnore:
return(PR_FALSE);
case nsEventStatus_eConsumeNoDefault:
return(PR_TRUE);
case nsEventStatus_eConsumeDoDefault:
return(PR_FALSE);
default:
NS_ASSERTION(0,"Illegal nsEventStatus enumeration value");
break;
}
return(PR_FALSE);
}
NS_METHOD nsCommonWidget::SetModal(PRBool aModal)
{
#ifdef DEBUG_WIDGETS
qDebug("------------> SetModal mWidget=%p",(void*) mWidget);
#endif
MozQWidget *mozWidget = qt_cast<MozQWidget*>(mWidget);
if (mozWidget)
mozWidget->setModal(aModal);
return NS_OK;
}
NS_IMETHODIMP nsCommonWidget::GetScreenBounds(nsRect &aRect)
{
nsRect origin(0,0,mBounds.width,mBounds.height);
WidgetToScreen(origin, aRect);
return NS_OK;
}
void
nsCommonWidget::NativeShow(PRBool aState)
{
mNeedsShow = PR_FALSE;
if (!mWidget) {
//XXX: apperently can be null during the printing, check whether
// that's true
qDebug("nsCommon::Show : widget empty");
return;
}
mWidget->setShown(aState);
}
void
nsCommonWidget::NativeResize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
{
mNeedsResize = PR_FALSE;
mWidget->resize( aWidth, aHeight);
if (aRepaint) {
if (mWidget->isVisible())
mWidget->repaint(false);
}
}
void
nsCommonWidget::NativeResize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight,
PRBool aRepaint)
{
mNeedsResize = PR_FALSE;
QPoint pos(aX, aY);
if (mContainer)
{
if (mParent && mWidget->isPopup()) {
nsRect oldrect, newrect;
oldrect.x = aX;
oldrect.y = aY;
mParent->WidgetToScreen(oldrect, newrect);
pos = QPoint(newrect.x, newrect.y);
#ifdef DEBUG_WIDGETS
qDebug("pos is [%d,%d]", pos.x(), pos.y());
#endif
} else {
#ifdef DEBUG_WIDGETS
qDebug("Widget with original position? (%p)", mWidget);
#endif
}
}
mWidget->setGeometry(pos.x(), pos.y(), aWidth, aHeight);
if (aRepaint) {
if (mWidget->isVisible())
mWidget->repaint(false);
}
}