michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* vim:expandtab:shiftwidth=4:tabstop=4: michael@0: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/ArrayUtils.h" michael@0: #include "mozilla/MiscEvents.h" michael@0: #include "mozilla/MouseEvents.h" michael@0: #include "mozilla/TextEvents.h" michael@0: #include "mozilla/TouchEvents.h" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #ifdef MOZ_X11 michael@0: #include michael@0: #include michael@0: #endif //MOZ_X11 michael@0: michael@0: #include "nsXULAppAPI.h" michael@0: michael@0: #include "prlink.h" michael@0: michael@0: #include "nsWindow.h" michael@0: #include "mozqwidget.h" michael@0: michael@0: #include "nsIdleService.h" michael@0: #include "nsRenderingContext.h" michael@0: #include "nsIRollupListener.h" michael@0: #include "nsWidgetsCID.h" michael@0: #include "nsQtKeyUtils.h" michael@0: #include "mozilla/Services.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/Likely.h" michael@0: #include "mozilla/layers/LayersTypes.h" michael@0: #include "nsIWidgetListener.h" michael@0: #include "ClientLayerManager.h" michael@0: #include "BasicLayers.h" michael@0: michael@0: #include "nsIStringBundle.h" michael@0: #include "nsGfxCIID.h" michael@0: michael@0: #include "imgIContainer.h" michael@0: #include "nsGfxCIID.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "nsAutoPtr.h" michael@0: michael@0: #include "gfxQtPlatform.h" michael@0: michael@0: #include "nsIDOMWheelEvent.h" michael@0: michael@0: #include "GLContext.h" michael@0: michael@0: #ifdef MOZ_X11 michael@0: #include "keysym2ucs.h" michael@0: #endif michael@0: michael@0: #include "Layers.h" michael@0: #include "GLContextProvider.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::gl; michael@0: using namespace mozilla::widget; michael@0: using namespace mozilla::gfx; michael@0: using namespace mozilla::layers; michael@0: using mozilla::gl::GLContext; michael@0: michael@0: #define kWindowPositionSlop 20 michael@0: michael@0: // Qt michael@0: static const int WHEEL_DELTA = 120; michael@0: static bool gGlobalsInitialized = false; michael@0: static bool sAltGrModifier = false; michael@0: michael@0: static void find_first_visible_parent(QWindow* aItem, QWindow*& aVisibleItem); michael@0: static bool is_mouse_in_window (MozQWidget* aWindow, double aMouseX, double aMouseY); michael@0: static bool isContextMenuKeyEvent(const QKeyEvent *qe); michael@0: static void InitKeyEvent(WidgetKeyboardEvent &aEvent, QKeyEvent *aQEvent); michael@0: michael@0: nsWindow::nsWindow() michael@0: { michael@0: LOG(("%s [%p]\n", __PRETTY_FUNCTION__, (void *)this)); michael@0: michael@0: mIsTopLevel = false; michael@0: mIsDestroyed = false; michael@0: mIsShown = false; michael@0: mEnabled = true; michael@0: mWidget = nullptr; michael@0: mVisible = false; michael@0: mActivatePending = false; michael@0: mWindowType = eWindowType_child; michael@0: mSizeState = nsSizeMode_Normal; michael@0: mLastSizeMode = nsSizeMode_Normal; michael@0: mQCursor = Qt::ArrowCursor; michael@0: mNeedsResize = false; michael@0: mNeedsMove = false; michael@0: mListenForResizes = false; michael@0: mNeedsShow = false; michael@0: mTimerStarted = false; michael@0: mMoveEvent.needDispatch = false; michael@0: michael@0: if (!gGlobalsInitialized) { michael@0: gfxPlatform::GetPlatform(); michael@0: gGlobalsInitialized = true; michael@0: } michael@0: michael@0: memset(mKeyDownFlags, 0, sizeof(mKeyDownFlags)); michael@0: michael@0: mIsTransparent = false; michael@0: michael@0: mCursor = eCursor_standard; michael@0: } michael@0: michael@0: nsWindow::~nsWindow() michael@0: { michael@0: LOG(("%s [%p]\n", __PRETTY_FUNCTION__, (void *)this)); michael@0: michael@0: Destroy(); michael@0: } michael@0: michael@0: nsresult michael@0: nsWindow::Create(nsIWidget *aParent, michael@0: nsNativeWidget aNativeParent, michael@0: const nsIntRect &aRect, michael@0: nsDeviceContext *aContext, michael@0: nsWidgetInitData *aInitData) michael@0: { michael@0: // only set the base parent if we're not going to be a dialog or a michael@0: // toplevel michael@0: nsIWidget *baseParent = aParent; michael@0: michael@0: // initialize all the common bits of this class michael@0: BaseCreate(baseParent, aRect, aContext, aInitData); michael@0: michael@0: mVisible = true; michael@0: michael@0: // and do our common creation michael@0: mParent = (nsWindow *)aParent; michael@0: michael@0: // save our bounds michael@0: mBounds = aRect; michael@0: michael@0: // find native parent michael@0: MozQWidget *parent = nullptr; michael@0: michael@0: if (aParent != nullptr) { michael@0: parent = static_cast(aParent->GetNativeData(NS_NATIVE_WIDGET)); michael@0: } else if (aNativeParent != nullptr) { michael@0: parent = static_cast(aNativeParent); michael@0: if (parent && mParent == nullptr) { michael@0: mParent = parent->getReceiver(); michael@0: } michael@0: } michael@0: michael@0: LOG(("Create: nsWindow [%p] mWidget:[%p] parent:[%p], natPar:[%p] mParent:%p\n", (void *)this, (void*)mWidget, parent, aNativeParent, mParent)); michael@0: michael@0: // ok, create our QGraphicsWidget michael@0: mWidget = createQWidget(parent, aInitData); michael@0: michael@0: if (!mWidget) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: michael@0: // resize so that everything is set to the right dimensions michael@0: Resize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, false); michael@0: michael@0: // check if we should listen for resizes michael@0: mListenForResizes = (aNativeParent || michael@0: (aInitData && aInitData->mListenForResizes)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: MozQWidget* michael@0: nsWindow::createQWidget(MozQWidget* parent, michael@0: nsWidgetInitData* aInitData) michael@0: { michael@0: const char *windowName = nullptr; michael@0: Qt::WindowFlags flags = Qt::Widget; michael@0: michael@0: // ok, create our windows michael@0: switch (mWindowType) { michael@0: case eWindowType_dialog: michael@0: windowName = "topLevelDialog"; michael@0: flags = Qt::Dialog; michael@0: break; michael@0: case eWindowType_popup: michael@0: windowName = "topLevelPopup"; michael@0: flags = Qt::Popup; michael@0: break; michael@0: case eWindowType_toplevel: michael@0: windowName = "topLevelWindow"; michael@0: flags = Qt::Window; michael@0: break; michael@0: case eWindowType_invisible: michael@0: windowName = "topLevelInvisible"; michael@0: break; michael@0: case eWindowType_child: michael@0: case eWindowType_plugin: michael@0: default: // sheet michael@0: windowName = "paintArea"; michael@0: break; michael@0: } michael@0: michael@0: MozQWidget* widget = new MozQWidget(this, parent); michael@0: if (!widget) { michael@0: return nullptr; michael@0: } michael@0: michael@0: widget->setObjectName(QString(windowName)); michael@0: if (mWindowType == eWindowType_invisible) { michael@0: widget->setVisibility(QWindow::Hidden); michael@0: } michael@0: if (mWindowType == eWindowType_dialog) { michael@0: widget->setModality(Qt::WindowModal); michael@0: } michael@0: michael@0: widget->create(); michael@0: michael@0: // create a QGraphicsView if this is a new toplevel window michael@0: LOG(("nsWindow::%s [%p] Created Window: %s, widget:%p, par:%p\n", __FUNCTION__, (void *)this, windowName, widget, parent)); michael@0: michael@0: return widget; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::Destroy(void) michael@0: { michael@0: if (mIsDestroyed || !mWidget) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: LOG(("nsWindow::Destroy [%p]\n", (void *)this)); michael@0: mIsDestroyed = true; michael@0: michael@0: /** Need to clean our LayerManager up while still alive */ michael@0: if (mLayerManager) { michael@0: mLayerManager->Destroy(); michael@0: } michael@0: mLayerManager = nullptr; michael@0: michael@0: // It is safe to call DestroyeCompositor several times (here and michael@0: // in the parent class) since it will take effect only once. michael@0: // The reason we call it here is because on gtk platforms we need michael@0: // to destroy the compositor before we destroy the gdk window (which michael@0: // destroys the the gl context attached to it). michael@0: DestroyCompositor(); michael@0: michael@0: ClearCachedResources(); michael@0: michael@0: nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener(); michael@0: if (rollupListener) { michael@0: nsCOMPtr rollupWidget = rollupListener->GetRollupWidget(); michael@0: if (static_cast(this) == rollupWidget) { michael@0: rollupListener->Rollup(0, nullptr, nullptr); michael@0: } michael@0: } michael@0: michael@0: Show(false); michael@0: michael@0: // walk the list of children and call destroy on them. Have to be michael@0: // careful, though -- calling destroy on a kid may actually remove michael@0: // it from our child list, losing its sibling links. michael@0: for (nsIWidget* kid = mFirstChild; kid; ) { michael@0: nsIWidget* next = kid->GetNextSibling(); michael@0: kid->Destroy(); michael@0: kid = next; michael@0: } michael@0: michael@0: // Destroy thebes surface now. Badness can happen if we destroy michael@0: // the surface after its X Window. michael@0: if (mWidget) { michael@0: mWidget->dropReceiver(); michael@0: michael@0: // Call deleteLater instead of delete; Qt still needs the object michael@0: // to be valid even after sending it a Close event. We could michael@0: // also set WA_DeleteOnClose, but this gives us more control. michael@0: mWidget->deleteLater(); michael@0: } michael@0: mWidget = nullptr; michael@0: michael@0: OnDestroy(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::Show(bool aState) michael@0: { michael@0: LOG(("nsWindow::Show [%p] state %d\n", (void *)this, aState)); michael@0: if (aState == mIsShown) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Clear our cached resources when the window is hidden. michael@0: if (mIsShown && !aState) { michael@0: ClearCachedResources(); michael@0: } michael@0: michael@0: mIsShown = aState; michael@0: michael@0: if ((aState && !AreBoundsSane()) || !mWidget) { michael@0: LOG(("\tbounds are insane or window hasn't been created yet\n")); michael@0: mNeedsShow = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (aState) { michael@0: if (mNeedsMove) { michael@0: NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, michael@0: false); michael@0: } else if (mNeedsResize) { michael@0: NativeResize(mBounds.width, mBounds.height, false); michael@0: } michael@0: } michael@0: else { michael@0: // If someone is hiding this widget, clear any needing show flag. michael@0: mNeedsShow = false; michael@0: } michael@0: michael@0: NativeShow(aState); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: nsWindow::IsVisible() const michael@0: { michael@0: return mIsShown; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY) michael@0: { michael@0: if (!mWidget) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: int32_t screenWidth = qApp->primaryScreen()->size().width(); michael@0: int32_t screenHeight = qApp->primaryScreen()->size().height(); michael@0: michael@0: if (aAllowSlop) { michael@0: if (*aX < (kWindowPositionSlop - mBounds.width)) michael@0: *aX = kWindowPositionSlop - mBounds.width; michael@0: if (*aX > (screenWidth - kWindowPositionSlop)) michael@0: *aX = screenWidth - kWindowPositionSlop; michael@0: if (*aY < (kWindowPositionSlop - mBounds.height)) michael@0: *aY = kWindowPositionSlop - mBounds.height; michael@0: if (*aY > (screenHeight - kWindowPositionSlop)) michael@0: *aY = screenHeight - kWindowPositionSlop; michael@0: } else { michael@0: if (*aX < 0) michael@0: *aX = 0; michael@0: if (*aX > (screenWidth - mBounds.width)) michael@0: *aX = screenWidth - mBounds.width; michael@0: if (*aY < 0) michael@0: *aY = 0; michael@0: if (*aY > (screenHeight - mBounds.height)) michael@0: *aY = screenHeight - mBounds.height; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::Move(double aX, double aY) michael@0: { michael@0: LOG(("nsWindow::Move [%p] %f %f\n", (void *)this, michael@0: aX, aY)); michael@0: michael@0: int32_t x = NSToIntRound(aX); michael@0: int32_t y = NSToIntRound(aY); michael@0: michael@0: if (mIsTopLevel) { michael@0: SetSizeMode(nsSizeMode_Normal); michael@0: } michael@0: michael@0: if (x == mBounds.x && y == mBounds.y) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: mNeedsMove = false; michael@0: michael@0: // update the bounds michael@0: QPoint pos(x, y); michael@0: if (mIsTopLevel) { michael@0: mWidget->setPosition(x, y); michael@0: } michael@0: else if (mWidget) { michael@0: // the position of the widget is set relative to the parent michael@0: // so we map the coordinates accordingly michael@0: pos = mWidget->mapToGlobal(pos); michael@0: mWidget->setPosition(pos); michael@0: } michael@0: michael@0: mBounds.x = pos.x(); michael@0: mBounds.y = pos.y(); michael@0: michael@0: NotifyRollupGeometryChange(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::Resize(double aWidth, double aHeight, bool aRepaint) michael@0: { michael@0: mBounds.width = NSToIntRound(aWidth); michael@0: mBounds.height = NSToIntRound(aHeight); michael@0: michael@0: if (!mWidget) michael@0: return NS_OK; michael@0: michael@0: if (mIsShown) { michael@0: if (AreBoundsSane()) { michael@0: if (mIsTopLevel || mNeedsShow) michael@0: NativeResize(mBounds.x, mBounds.y, michael@0: mBounds.width, mBounds.height, aRepaint); michael@0: else michael@0: NativeResize(mBounds.width, mBounds.height, aRepaint); michael@0: michael@0: // Does it need to be shown because it was previously insane? michael@0: if (mNeedsShow) { michael@0: NativeShow(true); michael@0: } michael@0: } michael@0: else { michael@0: // If someone has set this so that the needs show flag is false michael@0: // and it needs to be hidden, update the flag and hide the michael@0: // window. This flag will be cleared the next time someone michael@0: // hides the window or shows it. It also prevents us from michael@0: // calling NativeShow(false) excessively on the window which michael@0: // causes unneeded X traffic. michael@0: if (!mNeedsShow) { michael@0: mNeedsShow = true; michael@0: NativeShow(false); michael@0: } michael@0: } michael@0: } michael@0: else if (AreBoundsSane() && mListenForResizes) { michael@0: // For widgets that we listen for resizes for (widgets created michael@0: // with native parents) we apparently _always_ have to resize. I michael@0: // dunno why, but apparently we're lame like that. michael@0: NativeResize(mBounds.width, mBounds.height, aRepaint); michael@0: } michael@0: else { michael@0: mNeedsResize = true; michael@0: } michael@0: michael@0: // synthesize a resize event if this isn't a toplevel michael@0: if (mIsTopLevel || mListenForResizes) { michael@0: nsEventStatus status; michael@0: DispatchResizeEvent(mBounds, status); michael@0: } michael@0: michael@0: NotifyRollupGeometryChange(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::Resize(double aX, double aY, double aWidth, double aHeight, michael@0: bool aRepaint) michael@0: { michael@0: mBounds.x = NSToIntRound(aX); michael@0: mBounds.y = NSToIntRound(aY); michael@0: mBounds.width = NSToIntRound(aWidth); michael@0: mBounds.height = NSToIntRound(aHeight); michael@0: michael@0: mPlaced = true; michael@0: michael@0: if (!mWidget) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Has this widget been set to visible? michael@0: if (mIsShown) { michael@0: // Are the bounds sane? michael@0: if (AreBoundsSane()) { michael@0: // Yep? Resize the window michael@0: NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, michael@0: aRepaint); michael@0: // Does it need to be shown because it was previously insane? michael@0: if (mNeedsShow) michael@0: NativeShow(true); michael@0: } michael@0: else { michael@0: // If someone has set this so that the needs show flag is false michael@0: // and it needs to be hidden, update the flag and hide the michael@0: // window. This flag will be cleared the next time someone michael@0: // hides the window or shows it. It also prevents us from michael@0: // calling NativeShow(false) excessively on the window which michael@0: // causes unneeded X traffic. michael@0: if (!mNeedsShow) { michael@0: mNeedsShow = true; michael@0: NativeShow(false); michael@0: } michael@0: } michael@0: } michael@0: // If the widget hasn't been shown, mark the widget as needing to be michael@0: // resized before it is shown michael@0: else if (AreBoundsSane() && mListenForResizes) { michael@0: // For widgets that we listen for resizes for (widgets created michael@0: // with native parents) we apparently _always_ have to resize. I michael@0: // dunno why, but apparently we're lame like that. michael@0: NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, michael@0: aRepaint); michael@0: } michael@0: else { michael@0: mNeedsResize = true; michael@0: mNeedsMove = true; michael@0: } michael@0: michael@0: if (mIsTopLevel || mListenForResizes) { michael@0: // synthesize a resize event michael@0: nsEventStatus status; michael@0: DispatchResizeEvent(mBounds, status); michael@0: } michael@0: michael@0: if (aRepaint) { michael@0: mWidget->renderLater(); michael@0: } michael@0: michael@0: NotifyRollupGeometryChange(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::Enable(bool aState) michael@0: { michael@0: mEnabled = aState; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: nsWindow::IsEnabled() const michael@0: { michael@0: return mEnabled; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::SetFocus(bool aRaise) michael@0: { michael@0: // Make sure that our owning widget has focus. If it doesn't try to michael@0: // grab it. Note that we don't set our focus flag in this case. michael@0: LOGFOCUS((" SetFocus [%p]\n", (void *)this)); michael@0: michael@0: if (!mWidget) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (mWidget->focusObject()) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Because QGraphicsItem cannot get the focus if they are michael@0: // invisible, we look up the chain, for the lowest visible michael@0: // parent and focus that one michael@0: QWindow* realFocusItem = nullptr; michael@0: find_first_visible_parent(mWidget, realFocusItem); michael@0: michael@0: if (!realFocusItem || realFocusItem->focusObject()) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (aRaise && mWidget) { michael@0: // the raising has to happen on the view widget michael@0: mWidget->raise(); michael@0: } michael@0: michael@0: // XXXndeakin why is this here? It should dispatch only when the OS michael@0: // notifies us. michael@0: DispatchActivateEvent(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::ConfigureChildren(const nsTArray& aConfigurations) michael@0: { michael@0: for (uint32_t i = 0; i < aConfigurations.Length(); ++i) { michael@0: const Configuration& configuration = aConfigurations[i]; michael@0: michael@0: nsWindow* w = static_cast(configuration.mChild); michael@0: NS_ASSERTION(w->GetParent() == this, michael@0: "Configured widget is not a child"); michael@0: michael@0: if (w->mBounds.Size() != configuration.mBounds.Size()) { michael@0: w->Resize(configuration.mBounds.x, configuration.mBounds.y, michael@0: configuration.mBounds.width, configuration.mBounds.height, michael@0: true); michael@0: } else if (w->mBounds.TopLeft() != configuration.mBounds.TopLeft()) { michael@0: w->Move(configuration.mBounds.x, configuration.mBounds.y); michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::Invalidate(const nsIntRect &aRect) michael@0: { michael@0: LOGDRAW(("Invalidate (rect) [%p,%p]: %d %d %d %d\n", (void *)this, michael@0: (void*)mWidget,aRect.x, aRect.y, aRect.width, aRect.height)); michael@0: michael@0: if (!mWidget) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: mWidget->renderLater(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsIntPoint michael@0: nsWindow::WidgetToScreenOffset() michael@0: { michael@0: NS_ENSURE_TRUE(mWidget, nsIntPoint(0,0)); michael@0: michael@0: QPoint origin(0, 0); michael@0: origin = mWidget->mapToGlobal(origin); michael@0: michael@0: return nsIntPoint(origin.x(), origin.y()); michael@0: } michael@0: michael@0: void* michael@0: nsWindow::GetNativeData(uint32_t aDataType) michael@0: { michael@0: switch (aDataType) { michael@0: case NS_NATIVE_WINDOW: michael@0: case NS_NATIVE_WIDGET: { michael@0: return mWidget; michael@0: } michael@0: case NS_NATIVE_SHAREABLE_WINDOW: { michael@0: return mWidget ? (void*)mWidget->winId() : nullptr; michael@0: } michael@0: case NS_NATIVE_DISPLAY: { michael@0: #ifdef MOZ_X11 michael@0: return gfxQtPlatform::GetXDisplay(mWidget); michael@0: #endif michael@0: break; michael@0: } michael@0: case NS_NATIVE_PLUGIN_PORT: michael@0: case NS_NATIVE_GRAPHIC: michael@0: case NS_NATIVE_SHELLWIDGET: { michael@0: break; michael@0: } michael@0: default: michael@0: NS_WARNING("nsWindow::GetNativeData called with bad value"); michael@0: return nullptr; michael@0: } michael@0: LOG(("nsWindow::%s [%p] aDataType:%i\n", __FUNCTION__, (void *)this, aDataType)); michael@0: return nullptr; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus) michael@0: { michael@0: #ifdef DEBUG michael@0: debug_DumpEvent(stdout, aEvent->widget, aEvent, michael@0: nsAutoCString("something"), 0); michael@0: #endif michael@0: michael@0: aStatus = nsEventStatus_eIgnore; michael@0: michael@0: // send it to the standard callback michael@0: if (mWidgetListener) { michael@0: aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP_(void) michael@0: nsWindow::SetInputContext(const InputContext& aContext, michael@0: const InputContextAction& aAction) michael@0: { michael@0: NS_ENSURE_TRUE_VOID(mWidget); michael@0: michael@0: // SetSoftwareKeyboardState uses mInputContext, michael@0: // so, before calling that, record aContext in mInputContext. michael@0: mInputContext = aContext; michael@0: michael@0: switch (mInputContext.mIMEState.mEnabled) { michael@0: case IMEState::ENABLED: michael@0: case IMEState::PASSWORD: michael@0: case IMEState::PLUGIN: michael@0: SetSoftwareKeyboardState(true, aAction); michael@0: break; michael@0: default: michael@0: SetSoftwareKeyboardState(false, aAction); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP_(InputContext) michael@0: nsWindow::GetInputContext() michael@0: { michael@0: mInputContext.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED; michael@0: // Our qt widget looks like using only one context per process. michael@0: // However, it's better to set the context's pointer. michael@0: mInputContext.mNativeIMEContext = qApp->inputMethod(); michael@0: michael@0: return mInputContext; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::ReparentNativeWidget(nsIWidget *aNewParent) michael@0: { michael@0: NS_PRECONDITION(aNewParent, ""); michael@0: michael@0: MozQWidget* newParent = static_cast(aNewParent->GetNativeData(NS_NATIVE_WINDOW)); michael@0: NS_ASSERTION(newParent, "Parent widget has a null native window handle"); michael@0: if (mWidget) { michael@0: mWidget->setParent(newParent); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::MakeFullScreen(bool aFullScreen) michael@0: { michael@0: NS_ENSURE_TRUE(mWidget, NS_ERROR_FAILURE); michael@0: michael@0: if (aFullScreen) { michael@0: if (mSizeMode != nsSizeMode_Fullscreen) { michael@0: mLastSizeMode = mSizeMode; michael@0: } michael@0: michael@0: mSizeMode = nsSizeMode_Fullscreen; michael@0: mWidget->showFullScreen(); michael@0: } michael@0: else { michael@0: mSizeMode = mLastSizeMode; michael@0: michael@0: switch (mSizeMode) { michael@0: case nsSizeMode_Maximized: michael@0: mWidget->showMaximized(); michael@0: break; michael@0: case nsSizeMode_Minimized: michael@0: mWidget->showMinimized(); michael@0: break; michael@0: case nsSizeMode_Normal: michael@0: mWidget->showNormal(); michael@0: break; michael@0: default: michael@0: mWidget->showNormal(); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: NS_ASSERTION(mLastSizeMode != nsSizeMode_Fullscreen, michael@0: "mLastSizeMode should never be fullscreen"); michael@0: return nsBaseWidget::MakeFullScreen(aFullScreen); michael@0: } michael@0: michael@0: LayerManager* michael@0: nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager, michael@0: LayersBackend aBackendHint, michael@0: LayerManagerPersistence aPersistence, michael@0: bool* aAllowRetaining) michael@0: { michael@0: if (!mLayerManager && eTransparencyTransparent == GetTransparencyMode()) { michael@0: mLayerManager = CreateBasicLayerManager(); michael@0: } michael@0: michael@0: return nsBaseWidget::GetLayerManager(aShadowManager, aBackendHint, michael@0: aPersistence, aAllowRetaining); michael@0: } michael@0: michael@0: void michael@0: nsWindow::UserActivity() michael@0: { michael@0: if (!mIdleService) { michael@0: mIdleService = do_GetService("@mozilla.org/widget/idleservice;1"); michael@0: } michael@0: michael@0: if (mIdleService) { michael@0: mIdleService->ResetIdleTimeOut(0); michael@0: } michael@0: } michael@0: michael@0: uint32_t michael@0: nsWindow::GetGLFrameBufferFormat() michael@0: { michael@0: if (mLayerManager && michael@0: mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_OPENGL) { michael@0: return LOCAL_GL_RGB; michael@0: } michael@0: return LOCAL_GL_NONE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::SetCursor(nsCursor aCursor) michael@0: { michael@0: if (mCursor == aCursor) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: mCursor = aCursor; michael@0: if (mWidget) { michael@0: mWidget->SetCursor(mCursor); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::SetTitle(const nsAString& aTitle) michael@0: { michael@0: QString qStr(QString::fromUtf16((const ushort*)aTitle.BeginReading(), aTitle.Length())); michael@0: michael@0: mWidget->setTitle(qStr); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // EVENTS michael@0: michael@0: void michael@0: nsWindow::OnPaint() michael@0: { michael@0: LOGDRAW(("nsWindow::%s [%p]\n", __FUNCTION__, (void *)this)); michael@0: nsIWidgetListener* listener = michael@0: mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener; michael@0: if (!listener) { michael@0: return; michael@0: } michael@0: michael@0: listener->WillPaintWindow(this); michael@0: michael@0: switch (GetLayerManager()->GetBackendType()) { michael@0: case mozilla::layers::LayersBackend::LAYERS_CLIENT: { michael@0: nsIntRegion region(nsIntRect(0, 0, mWidget->width(), mWidget->height())); michael@0: listener->PaintWindow(this, region); michael@0: break; michael@0: } michael@0: default: michael@0: NS_ERROR("Invalid layer manager"); michael@0: } michael@0: michael@0: listener->DidPaintWindow(); michael@0: } michael@0: michael@0: nsEventStatus michael@0: nsWindow::moveEvent(QMoveEvent* aEvent) michael@0: { michael@0: LOG(("configure event [%p] %d %d\n", (void *)this, michael@0: aEvent->pos().x(), aEvent->pos().y())); michael@0: michael@0: // can we shortcut? michael@0: if (!mWidget || !mWidgetListener) michael@0: return nsEventStatus_eIgnore; michael@0: michael@0: if ((mBounds.x == aEvent->pos().x() && michael@0: mBounds.y == aEvent->pos().y())) michael@0: { michael@0: return nsEventStatus_eIgnore; michael@0: } michael@0: michael@0: NotifyWindowMoved(aEvent->pos().x(), aEvent->pos().y()); michael@0: return nsEventStatus_eConsumeNoDefault; michael@0: } michael@0: michael@0: nsEventStatus michael@0: nsWindow::resizeEvent(QResizeEvent* aEvent) michael@0: { michael@0: nsIntRect rect; michael@0: michael@0: // Generate XPFE resize event michael@0: GetBounds(rect); michael@0: michael@0: rect.width = aEvent->size().width(); michael@0: rect.height = aEvent->size().height(); michael@0: michael@0: mBounds.width = rect.width; michael@0: mBounds.height = rect.height; michael@0: michael@0: nsEventStatus status; michael@0: DispatchResizeEvent(rect, status); michael@0: return status; michael@0: } michael@0: michael@0: nsEventStatus michael@0: nsWindow::mouseMoveEvent(QMouseEvent* aEvent) michael@0: { michael@0: UserActivity(); michael@0: michael@0: mMoveEvent.pos = aEvent->pos(); michael@0: mMoveEvent.modifiers = aEvent->modifiers(); michael@0: mMoveEvent.needDispatch = true; michael@0: DispatchMotionToMainThread(); michael@0: michael@0: return nsEventStatus_eIgnore; michael@0: } michael@0: michael@0: nsEventStatus michael@0: nsWindow::mousePressEvent(QMouseEvent* aEvent) michael@0: { michael@0: // The user has done something. michael@0: UserActivity(); michael@0: michael@0: QPoint pos = aEvent->pos(); michael@0: michael@0: // we check against the widgets geometry, so use parent coordinates michael@0: // for the check michael@0: if (mWidget) michael@0: pos = mWidget->mapToGlobal(pos); michael@0: michael@0: if (CheckForRollup( pos.x(), pos.y(), false)) michael@0: return nsEventStatus_eIgnore; michael@0: michael@0: uint16_t domButton; michael@0: switch (aEvent->button()) { michael@0: case Qt::MidButton: michael@0: domButton = WidgetMouseEvent::eMiddleButton; michael@0: break; michael@0: case Qt::RightButton: michael@0: domButton = WidgetMouseEvent::eRightButton; michael@0: break; michael@0: default: michael@0: domButton = WidgetMouseEvent::eLeftButton; michael@0: break; michael@0: } michael@0: michael@0: WidgetMouseEvent event(true, NS_MOUSE_BUTTON_DOWN, this, michael@0: WidgetMouseEvent::eReal); michael@0: event.button = domButton; michael@0: InitButtonEvent(event, aEvent, 1); michael@0: michael@0: LOG(("%s [%p] button: %d\n", __PRETTY_FUNCTION__, (void*)this, domButton)); michael@0: michael@0: nsEventStatus status = DispatchEvent(&event); michael@0: michael@0: // right menu click on linux should also pop up a context menu michael@0: if (domButton == WidgetMouseEvent::eRightButton && michael@0: MOZ_LIKELY(!mIsDestroyed)) { michael@0: WidgetMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this, michael@0: WidgetMouseEvent::eReal); michael@0: InitButtonEvent(contextMenuEvent, aEvent, 1); michael@0: DispatchEvent(&contextMenuEvent, status); michael@0: } michael@0: michael@0: return status; michael@0: } michael@0: michael@0: nsEventStatus michael@0: nsWindow::mouseReleaseEvent(QMouseEvent* aEvent) michael@0: { michael@0: // The user has done something. michael@0: UserActivity(); michael@0: michael@0: uint16_t domButton; michael@0: michael@0: switch (aEvent->button()) { michael@0: case Qt::MidButton: michael@0: domButton = WidgetMouseEvent::eMiddleButton; michael@0: break; michael@0: case Qt::RightButton: michael@0: domButton = WidgetMouseEvent::eRightButton; michael@0: break; michael@0: default: michael@0: domButton = WidgetMouseEvent::eLeftButton; michael@0: break; michael@0: } michael@0: michael@0: LOG(("%s [%p] button: %d\n", __PRETTY_FUNCTION__, (void*)this, domButton)); michael@0: michael@0: WidgetMouseEvent event(true, NS_MOUSE_BUTTON_UP, this, michael@0: WidgetMouseEvent::eReal); michael@0: event.button = domButton; michael@0: InitButtonEvent(event, aEvent, 1); michael@0: michael@0: nsEventStatus status = DispatchEvent(&event); michael@0: michael@0: return status; michael@0: } michael@0: michael@0: nsEventStatus michael@0: nsWindow::mouseDoubleClickEvent(QMouseEvent* aEvent) michael@0: { michael@0: uint32_t eventType; michael@0: michael@0: switch (aEvent->button()) { michael@0: case Qt::MidButton: michael@0: eventType = WidgetMouseEvent::eMiddleButton; michael@0: break; michael@0: case Qt::RightButton: michael@0: eventType = WidgetMouseEvent::eRightButton; michael@0: break; michael@0: default: michael@0: eventType = WidgetMouseEvent::eLeftButton; michael@0: break; michael@0: } michael@0: michael@0: WidgetMouseEvent event(true, NS_MOUSE_DOUBLECLICK, this, michael@0: WidgetMouseEvent::eReal); michael@0: event.button = eventType; michael@0: michael@0: InitButtonEvent(event, aEvent, 2); michael@0: //pressed michael@0: return DispatchEvent(&event); michael@0: } michael@0: michael@0: nsEventStatus michael@0: nsWindow::focusInEvent(QFocusEvent* aEvent) michael@0: { michael@0: LOGFOCUS(("OnFocusInEvent [%p]\n", (void *)this)); michael@0: michael@0: if (!mWidget) { michael@0: return nsEventStatus_eIgnore; michael@0: } michael@0: michael@0: DispatchActivateEventOnTopLevelWindow(); michael@0: michael@0: LOGFOCUS(("Events sent from focus in event [%p]\n", (void *)this)); michael@0: return nsEventStatus_eIgnore; michael@0: } michael@0: michael@0: nsEventStatus michael@0: nsWindow::focusOutEvent(QFocusEvent* aEvent) michael@0: { michael@0: LOGFOCUS(("OnFocusOutEvent [%p]\n", (void *)this)); michael@0: michael@0: if (!mWidget) { michael@0: return nsEventStatus_eIgnore; michael@0: } michael@0: michael@0: DispatchDeactivateEventOnTopLevelWindow(); michael@0: michael@0: LOGFOCUS(("Done with container focus out [%p]\n", (void *)this)); michael@0: return nsEventStatus_eIgnore; michael@0: } michael@0: michael@0: nsEventStatus michael@0: nsWindow::keyPressEvent(QKeyEvent* aEvent) michael@0: { michael@0: LOGFOCUS(("OnKeyPressEvent [%p]\n", (void *)this)); michael@0: michael@0: // The user has done something. michael@0: UserActivity(); michael@0: michael@0: if (aEvent->key() == Qt::Key_AltGr) { michael@0: sAltGrModifier = true; michael@0: } michael@0: michael@0: #ifdef MOZ_X11 michael@0: // before we dispatch a key, check if it's the context menu key. michael@0: // If so, send a context menu key event instead. michael@0: if (isContextMenuKeyEvent(aEvent)) { michael@0: WidgetMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this, michael@0: WidgetMouseEvent::eReal, michael@0: WidgetMouseEvent::eContextMenuKey); michael@0: //keyEventToContextMenuEvent(&event, &contextMenuEvent); michael@0: return DispatchEvent(&contextMenuEvent); michael@0: } michael@0: michael@0: uint32_t domCharCode = 0; michael@0: uint32_t domKeyCode = QtKeyCodeToDOMKeyCode(aEvent->key()); michael@0: michael@0: // get keymap and modifier map from the Xserver michael@0: Display *display = gfxQtPlatform::GetXDisplay(mWidget); michael@0: int x_min_keycode = 0, x_max_keycode = 0, xkeysyms_per_keycode; michael@0: XDisplayKeycodes(display, &x_min_keycode, &x_max_keycode); michael@0: XModifierKeymap *xmodmap = XGetModifierMapping(display); michael@0: if (!xmodmap) michael@0: return nsEventStatus_eIgnore; michael@0: michael@0: KeySym *xkeymap = XGetKeyboardMapping(display, x_min_keycode, x_max_keycode - x_min_keycode, michael@0: &xkeysyms_per_keycode); michael@0: if (!xkeymap) { michael@0: XFreeModifiermap(xmodmap); michael@0: return nsEventStatus_eIgnore; michael@0: } michael@0: michael@0: // create modifier masks michael@0: qint32 shift_mask = 0, shift_lock_mask = 0, caps_lock_mask = 0, num_lock_mask = 0; michael@0: michael@0: for (int i = 0; i < 8 * xmodmap->max_keypermod; ++i) { michael@0: qint32 maskbit = 1 << (i / xmodmap->max_keypermod); michael@0: KeyCode modkeycode = xmodmap->modifiermap[i]; michael@0: if (modkeycode == NoSymbol) { michael@0: continue; michael@0: } michael@0: michael@0: quint32 mapindex = (modkeycode - x_min_keycode) * xkeysyms_per_keycode; michael@0: for (int j = 0; j < xkeysyms_per_keycode; ++j) { michael@0: KeySym modkeysym = xkeymap[mapindex + j]; michael@0: switch (modkeysym) { michael@0: case XK_Num_Lock: michael@0: num_lock_mask |= maskbit; michael@0: break; michael@0: case XK_Caps_Lock: michael@0: caps_lock_mask |= maskbit; michael@0: break; michael@0: case XK_Shift_Lock: michael@0: shift_lock_mask |= maskbit; michael@0: break; michael@0: case XK_Shift_L: michael@0: case XK_Shift_R: michael@0: shift_mask |= maskbit; michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: // indicate whether is down or not michael@0: bool shift_state = ((shift_mask & aEvent->nativeModifiers()) != 0) ^ michael@0: (bool)(shift_lock_mask & aEvent->nativeModifiers()); michael@0: bool capslock_state = (bool)(caps_lock_mask & aEvent->nativeModifiers()); michael@0: michael@0: // try to find a keysym that we can translate to a DOMKeyCode michael@0: // this is needed because some of Qt's keycodes cannot be translated michael@0: // TODO: use US keyboard keymap instead of localised keymap michael@0: if (!domKeyCode && michael@0: aEvent->nativeScanCode() >= (quint32)x_min_keycode && michael@0: aEvent->nativeScanCode() <= (quint32)x_max_keycode) { michael@0: int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode; michael@0: for(int i = 0; (i < xkeysyms_per_keycode) && (domKeyCode == (quint32)NoSymbol); ++i) { michael@0: domKeyCode = QtKeyCodeToDOMKeyCode(xkeymap[index + i]); michael@0: } michael@0: } michael@0: michael@0: // store character in domCharCode michael@0: if (aEvent->text().length() && aEvent->text()[0].isPrint()) michael@0: domCharCode = (int32_t) aEvent->text()[0].unicode(); michael@0: michael@0: KeyNameIndex keyNameIndex = michael@0: domCharCode ? KEY_NAME_INDEX_PrintableKey : michael@0: QtKeyCodeToDOMKeyNameIndex(aEvent->key()); michael@0: michael@0: // If the key isn't autorepeat, we need to send the initial down event michael@0: if (!aEvent->isAutoRepeat() && !IsKeyDown(domKeyCode)) { michael@0: // send the key down event michael@0: michael@0: SetKeyDownFlag(domKeyCode); michael@0: michael@0: WidgetKeyboardEvent downEvent(true, NS_KEY_DOWN, this); michael@0: InitKeyEvent(downEvent, aEvent); michael@0: michael@0: downEvent.keyCode = domKeyCode; michael@0: downEvent.mKeyNameIndex = keyNameIndex; michael@0: michael@0: nsEventStatus status = DispatchEvent(&downEvent); michael@0: michael@0: // DispatchEvent can Destroy us (bug 378273) michael@0: if (MOZ_UNLIKELY(mIsDestroyed)) { michael@0: qWarning() << "Returning[" << __LINE__ << "]: " << "Window destroyed"; michael@0: return status; michael@0: } michael@0: michael@0: // If prevent default on keydown, don't dispatch keypress event michael@0: if (status == nsEventStatus_eConsumeNoDefault) { michael@0: return nsEventStatus_eConsumeNoDefault; michael@0: } michael@0: } michael@0: michael@0: // Don't pass modifiers as NS_KEY_PRESS events. michael@0: // Instead of selectively excluding some keys from NS_KEY_PRESS events, michael@0: // we instead selectively include (as per MSDN spec michael@0: // ( http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keypress%28VS.71%29.aspx ); michael@0: // no official spec covers KeyPress events). michael@0: if (aEvent->key() == Qt::Key_Shift || michael@0: aEvent->key() == Qt::Key_Control || michael@0: aEvent->key() == Qt::Key_Meta || michael@0: aEvent->key() == Qt::Key_Alt || michael@0: aEvent->key() == Qt::Key_AltGr) { michael@0: michael@0: return nsEventStatus_eIgnore; michael@0: } michael@0: michael@0: // Look for specialized app-command keys michael@0: switch (aEvent->key()) { michael@0: case Qt::Key_Back: michael@0: return DispatchCommandEvent(nsGkAtoms::Back); michael@0: case Qt::Key_Forward: michael@0: return DispatchCommandEvent(nsGkAtoms::Forward); michael@0: case Qt::Key_Refresh: michael@0: return DispatchCommandEvent(nsGkAtoms::Reload); michael@0: case Qt::Key_Stop: michael@0: return DispatchCommandEvent(nsGkAtoms::Stop); michael@0: case Qt::Key_Search: michael@0: return DispatchCommandEvent(nsGkAtoms::Search); michael@0: case Qt::Key_Favorites: michael@0: return DispatchCommandEvent(nsGkAtoms::Bookmarks); michael@0: case Qt::Key_HomePage: michael@0: return DispatchCommandEvent(nsGkAtoms::Home); michael@0: case Qt::Key_Copy: michael@0: case Qt::Key_F16: // F16, F20, F18, F14 are old keysyms for Copy Cut Paste Undo michael@0: return DispatchContentCommandEvent(NS_CONTENT_COMMAND_COPY); michael@0: case Qt::Key_Cut: michael@0: case Qt::Key_F20: michael@0: return DispatchContentCommandEvent(NS_CONTENT_COMMAND_CUT); michael@0: case Qt::Key_Paste: michael@0: case Qt::Key_F18: michael@0: case Qt::Key_F9: michael@0: return DispatchContentCommandEvent(NS_CONTENT_COMMAND_PASTE); michael@0: case Qt::Key_F14: michael@0: return DispatchContentCommandEvent(NS_CONTENT_COMMAND_UNDO); michael@0: } michael@0: michael@0: // Qt::Key_Redo and Qt::Key_Undo are not available yet. michael@0: if (aEvent->nativeVirtualKey() == 0xff66) { michael@0: return DispatchContentCommandEvent(NS_CONTENT_COMMAND_REDO); michael@0: } michael@0: if (aEvent->nativeVirtualKey() == 0xff65) { michael@0: return DispatchContentCommandEvent(NS_CONTENT_COMMAND_UNDO); michael@0: } michael@0: michael@0: WidgetKeyboardEvent event(true, NS_KEY_PRESS, this); michael@0: InitKeyEvent(event, aEvent); michael@0: michael@0: // If there is no charcode attainable from the text, try to michael@0: // generate it from the keycode. Check shift state for case michael@0: // Also replace the charcode if ControlModifier is the only michael@0: // pressed Modifier michael@0: if ((!domCharCode) && michael@0: (QGuiApplication::keyboardModifiers() & michael@0: (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) { michael@0: michael@0: // get a character from X11 key map michael@0: KeySym keysym = aEvent->nativeVirtualKey(); michael@0: if (keysym) { michael@0: domCharCode = (uint32_t) keysym2ucs(keysym); michael@0: if (domCharCode == -1 || !QChar((quint32)domCharCode).isPrint()) { michael@0: domCharCode = 0; michael@0: } michael@0: } michael@0: michael@0: // if Ctrl is pressed and domCharCode is not a ASCII character michael@0: if (domCharCode > 0xFF && (QGuiApplication::keyboardModifiers() & Qt::ControlModifier)) { michael@0: // replace Unicode character michael@0: int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode; michael@0: for (int i = 0; i < xkeysyms_per_keycode; ++i) { michael@0: if (xkeymap[index + i] <= 0xFF && !shift_state) { michael@0: domCharCode = (uint32_t) QChar::toLower((uint) xkeymap[index + i]); michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: } else { // The key event should cause a character input. michael@0: // At that time, we need to reset the modifiers michael@0: // because nsEditor will not accept a key event michael@0: // for text input if one or more modifiers are set. michael@0: event.modifiers &= ~(MODIFIER_CONTROL | michael@0: MODIFIER_ALT | michael@0: MODIFIER_META); michael@0: } michael@0: michael@0: KeySym keysym = NoSymbol; michael@0: int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode; michael@0: for (int i = 0; i < xkeysyms_per_keycode; ++i) { michael@0: if (xkeymap[index + i] == aEvent->nativeVirtualKey()) { michael@0: if ((i % 2) == 0) { // shifted char michael@0: keysym = xkeymap[index + i + 1]; michael@0: break; michael@0: } else { // unshifted char michael@0: keysym = xkeymap[index + i - 1]; michael@0: break; michael@0: } michael@0: } michael@0: if (xkeysyms_per_keycode - 1 == i) { michael@0: qWarning() << "Symbol '" << aEvent->nativeVirtualKey() << "' not found"; michael@0: } michael@0: } michael@0: QChar unshiftedChar(domCharCode); michael@0: long ucs = keysym2ucs(keysym); michael@0: ucs = ucs == -1 ? 0 : ucs; michael@0: QChar shiftedChar((uint)ucs); michael@0: michael@0: // append alternativeCharCodes if modifier is pressed michael@0: // append an additional alternativeCharCodes if domCharCode is not a Latin character michael@0: // and if one of these modifiers is pressed (i.e. Ctrl, Alt, Meta) michael@0: if (domCharCode && michael@0: (QGuiApplication::keyboardModifiers() & michael@0: (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) { michael@0: michael@0: event.charCode = domCharCode; michael@0: event.keyCode = 0; michael@0: AlternativeCharCode altCharCode(0, 0); michael@0: // if character has a lower and upper representation michael@0: if ((unshiftedChar.isUpper() || unshiftedChar.isLower()) && michael@0: unshiftedChar.toLower() == shiftedChar.toLower()) { michael@0: if (shift_state ^ capslock_state) { michael@0: altCharCode.mUnshiftedCharCode = (uint32_t) QChar::toUpper((uint)domCharCode); michael@0: altCharCode.mShiftedCharCode = (uint32_t) QChar::toLower((uint)domCharCode); michael@0: } else { michael@0: altCharCode.mUnshiftedCharCode = (uint32_t) QChar::toLower((uint)domCharCode); michael@0: altCharCode.mShiftedCharCode = (uint32_t) QChar::toUpper((uint)domCharCode); michael@0: } michael@0: } else { michael@0: altCharCode.mUnshiftedCharCode = (uint32_t) unshiftedChar.unicode(); michael@0: altCharCode.mShiftedCharCode = (uint32_t) shiftedChar.unicode(); michael@0: } michael@0: michael@0: // append alternative char code to event michael@0: if ((altCharCode.mUnshiftedCharCode && altCharCode.mUnshiftedCharCode != domCharCode) || michael@0: (altCharCode.mShiftedCharCode && altCharCode.mShiftedCharCode != domCharCode)) { michael@0: event.alternativeCharCodes.AppendElement(altCharCode); michael@0: } michael@0: michael@0: // check if the alternative char codes are latin-1 michael@0: if (altCharCode.mUnshiftedCharCode > 0xFF || altCharCode.mShiftedCharCode > 0xFF) { michael@0: altCharCode.mUnshiftedCharCode = altCharCode.mShiftedCharCode = 0; michael@0: michael@0: // find latin char for keycode michael@0: KeySym keysym = NoSymbol; michael@0: int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode; michael@0: // find first shifted and unshifted Latin-Char in XKeyMap michael@0: for (int i = 0; i < xkeysyms_per_keycode; ++i) { michael@0: keysym = xkeymap[index + i]; michael@0: if (keysym && keysym <= 0xFF) { michael@0: if ((shift_state && (i % 2 == 1)) || michael@0: (!shift_state && (i % 2 == 0))) { michael@0: altCharCode.mUnshiftedCharCode = altCharCode.mUnshiftedCharCode ? michael@0: altCharCode.mUnshiftedCharCode : michael@0: keysym; michael@0: } else { michael@0: altCharCode.mShiftedCharCode = altCharCode.mShiftedCharCode ? michael@0: altCharCode.mShiftedCharCode : michael@0: keysym; michael@0: } michael@0: if (altCharCode.mUnshiftedCharCode && altCharCode.mShiftedCharCode) { michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (altCharCode.mUnshiftedCharCode || altCharCode.mShiftedCharCode) { michael@0: event.alternativeCharCodes.AppendElement(altCharCode); michael@0: } michael@0: } michael@0: } else { michael@0: event.charCode = domCharCode; michael@0: } michael@0: michael@0: if (xmodmap) { michael@0: XFreeModifiermap(xmodmap); michael@0: } michael@0: if (xkeymap) { michael@0: XFree(xkeymap); michael@0: } michael@0: michael@0: event.keyCode = domCharCode ? 0 : domKeyCode; michael@0: event.mKeyNameIndex = keyNameIndex; michael@0: // send the key press event michael@0: return DispatchEvent(&event); michael@0: #else michael@0: michael@0: //:TODO: fix shortcuts hebrew for non X11, michael@0: //see Bug 562195##51 michael@0: michael@0: // before we dispatch a key, check if it's the context menu key. michael@0: // If so, send a context menu key event instead. michael@0: if (isContextMenuKeyEvent(aEvent)) { michael@0: WidgetMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this, michael@0: WidgetMouseEvent::eReal, michael@0: WidgetMouseEvent::eContextMenuKey); michael@0: //keyEventToContextMenuEvent(&event, &contextMenuEvent); michael@0: return DispatchEvent(&contextMenuEvent); michael@0: } michael@0: michael@0: uint32_t domCharCode = 0; michael@0: uint32_t domKeyCode = QtKeyCodeToDOMKeyCode(aEvent->key()); michael@0: michael@0: if (aEvent->text().length() && aEvent->text()[0].isPrint()) { michael@0: domCharCode = (int32_t) aEvent->text()[0].unicode(); michael@0: } michael@0: michael@0: KeyNameIndex keyNameIndex = michael@0: domCharCode ? KEY_NAME_INDEX_PrintableKey : michael@0: QtKeyCodeToDOMKeyNameIndex(aEvent->key()); michael@0: michael@0: // If the key isn't autorepeat, we need to send the initial down event michael@0: if (!aEvent->isAutoRepeat() && !IsKeyDown(domKeyCode)) { michael@0: // send the key down event michael@0: michael@0: SetKeyDownFlag(domKeyCode); michael@0: michael@0: WidgetKeyboardEvent downEvent(true, NS_KEY_DOWN, this); michael@0: InitKeyEvent(downEvent, aEvent); michael@0: michael@0: downEvent.keyCode = domKeyCode; michael@0: downEvent.mKeyNameIndex = keyNameIndex; michael@0: michael@0: nsEventStatus status = DispatchEvent(&downEvent); michael@0: michael@0: // If prevent default on keydown, don't dispatch keypress event michael@0: if (status == nsEventStatus_eConsumeNoDefault) { michael@0: return nsEventStatus_eConsumeNoDefault; michael@0: } michael@0: } michael@0: michael@0: WidgetKeyboardEvent event(true, NS_KEY_PRESS, this); michael@0: InitKeyEvent(event, aEvent); michael@0: michael@0: event.charCode = domCharCode; michael@0: michael@0: event.keyCode = domCharCode ? 0 : domKeyCode; michael@0: event.mKeyNameIndex = keyNameIndex; michael@0: michael@0: // send the key press event michael@0: return DispatchEvent(&event); michael@0: #endif michael@0: } michael@0: michael@0: nsEventStatus michael@0: nsWindow::keyReleaseEvent(QKeyEvent* aEvent) michael@0: { michael@0: LOGFOCUS(("OnKeyReleaseEvent [%p]\n", (void *)this)); michael@0: michael@0: // The user has done something. michael@0: UserActivity(); michael@0: michael@0: if (isContextMenuKeyEvent(aEvent)) { michael@0: // er, what do we do here? DoDefault or NoDefault? michael@0: return nsEventStatus_eConsumeDoDefault; michael@0: } michael@0: michael@0: uint32_t domKeyCode = QtKeyCodeToDOMKeyCode(aEvent->key()); michael@0: michael@0: #ifdef MOZ_X11 michael@0: if (!domKeyCode) { michael@0: // get keymap from the Xserver michael@0: Display *display = gfxQtPlatform::GetXDisplay(mWidget); michael@0: int x_min_keycode = 0, x_max_keycode = 0, xkeysyms_per_keycode; michael@0: XDisplayKeycodes(display, &x_min_keycode, &x_max_keycode); michael@0: KeySym *xkeymap = XGetKeyboardMapping(display, x_min_keycode, x_max_keycode - x_min_keycode, michael@0: &xkeysyms_per_keycode); michael@0: michael@0: if (aEvent->nativeScanCode() >= (quint32)x_min_keycode && michael@0: aEvent->nativeScanCode() <= (quint32)x_max_keycode) { michael@0: int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode; michael@0: for(int i = 0; (i < xkeysyms_per_keycode) && (domKeyCode == (quint32)NoSymbol); ++i) { michael@0: domKeyCode = QtKeyCodeToDOMKeyCode(xkeymap[index + i]); michael@0: } michael@0: } michael@0: michael@0: if (xkeymap) { michael@0: XFree(xkeymap); michael@0: } michael@0: } michael@0: #endif // MOZ_X11 michael@0: michael@0: // send the key event as a key up event michael@0: WidgetKeyboardEvent event(true, NS_KEY_UP, this); michael@0: InitKeyEvent(event, aEvent); michael@0: michael@0: if (aEvent->key() == Qt::Key_AltGr) { michael@0: sAltGrModifier = false; michael@0: } michael@0: michael@0: event.keyCode = domKeyCode; michael@0: event.mKeyNameIndex = michael@0: (aEvent->text().length() && aEvent->text()[0].isPrint()) ? michael@0: KEY_NAME_INDEX_PrintableKey : michael@0: QtKeyCodeToDOMKeyNameIndex(aEvent->key()); michael@0: michael@0: // unset the key down flag michael@0: ClearKeyDownFlag(event.keyCode); michael@0: michael@0: return DispatchEvent(&event); michael@0: } michael@0: michael@0: nsEventStatus michael@0: nsWindow::wheelEvent(QWheelEvent* aEvent) michael@0: { michael@0: // check to see if we should rollup michael@0: WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, this); michael@0: wheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE; michael@0: michael@0: // negative values for aEvent->delta indicate downward scrolling; michael@0: // this is opposite Gecko usage. michael@0: // TODO: Store the unused delta values due to fraction round and add it michael@0: // to next event. The stored values should be reset by other michael@0: // direction scroll event. michael@0: int32_t delta = (int)(aEvent->delta() / WHEEL_DELTA) * -3; michael@0: michael@0: switch (aEvent->orientation()) { michael@0: case Qt::Vertical: michael@0: wheelEvent.deltaY = wheelEvent.lineOrPageDeltaY = delta; michael@0: break; michael@0: case Qt::Horizontal: michael@0: wheelEvent.deltaX = wheelEvent.lineOrPageDeltaX = delta; michael@0: break; michael@0: default: michael@0: Q_ASSERT(0); michael@0: break; michael@0: } michael@0: michael@0: wheelEvent.refPoint.x = nscoord(aEvent->pos().x()); michael@0: wheelEvent.refPoint.y = nscoord(aEvent->pos().y()); michael@0: michael@0: wheelEvent.InitBasicModifiers(aEvent->modifiers() & Qt::ControlModifier, michael@0: aEvent->modifiers() & Qt::AltModifier, michael@0: aEvent->modifiers() & Qt::ShiftModifier, michael@0: aEvent->modifiers() & Qt::MetaModifier); michael@0: wheelEvent.time = 0; michael@0: michael@0: return DispatchEvent(&wheelEvent); michael@0: } michael@0: michael@0: nsEventStatus michael@0: nsWindow::showEvent(QShowEvent *) michael@0: { michael@0: LOG(("%s [%p]\n", __PRETTY_FUNCTION__,(void *)this)); michael@0: mVisible = true; michael@0: return nsEventStatus_eConsumeDoDefault; michael@0: } michael@0: michael@0: nsEventStatus michael@0: nsWindow::hideEvent(QHideEvent *) michael@0: { michael@0: LOG(("%s [%p]\n", __PRETTY_FUNCTION__,(void *)this)); michael@0: mVisible = false; michael@0: return nsEventStatus_eConsumeDoDefault; michael@0: } michael@0: michael@0: nsEventStatus nsWindow::touchEvent(QTouchEvent* aEvent) michael@0: { michael@0: return nsEventStatus_eIgnore; michael@0: } michael@0: michael@0: nsEventStatus michael@0: nsWindow::tabletEvent(QTabletEvent* aEvent) michael@0: { michael@0: LOGFOCUS(("nsWindow::%s [%p]\n", __FUNCTION__, (void *)this)); michael@0: return nsEventStatus_eIgnore; michael@0: } michael@0: michael@0: // Helpers michael@0: michael@0: void michael@0: nsWindow::InitButtonEvent(WidgetMouseEvent& aMoveEvent, michael@0: QMouseEvent* aEvent, michael@0: int aClickCount) michael@0: { michael@0: aMoveEvent.refPoint.x = nscoord(aEvent->pos().x()); michael@0: aMoveEvent.refPoint.y = nscoord(aEvent->pos().y()); michael@0: michael@0: aMoveEvent.InitBasicModifiers(aEvent->modifiers() & Qt::ControlModifier, michael@0: aEvent->modifiers() & Qt::AltModifier, michael@0: aEvent->modifiers() & Qt::ShiftModifier, michael@0: aEvent->modifiers() & Qt::MetaModifier); michael@0: aMoveEvent.clickCount = aClickCount; michael@0: } michael@0: michael@0: nsEventStatus michael@0: nsWindow::DispatchEvent(WidgetGUIEvent* aEvent) michael@0: { michael@0: nsEventStatus status; michael@0: DispatchEvent(aEvent, status); michael@0: return status; michael@0: } michael@0: michael@0: void michael@0: nsWindow::DispatchActivateEvent(void) michael@0: { michael@0: if (mWidgetListener) { michael@0: mWidgetListener->WindowActivated(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsWindow::DispatchDeactivateEvent(void) michael@0: { michael@0: if (mWidgetListener) { michael@0: mWidgetListener->WindowDeactivated(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsWindow::DispatchActivateEventOnTopLevelWindow(void) michael@0: { michael@0: nsWindow* topLevelWindow = static_cast(GetTopLevelWidget()); michael@0: if (topLevelWindow != nullptr) { michael@0: topLevelWindow->DispatchActivateEvent(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsWindow::DispatchDeactivateEventOnTopLevelWindow(void) michael@0: { michael@0: nsWindow* topLevelWindow = static_cast(GetTopLevelWidget()); michael@0: if (topLevelWindow != nullptr) { michael@0: topLevelWindow->DispatchDeactivateEvent(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsWindow::DispatchResizeEvent(nsIntRect &aRect, nsEventStatus &aStatus) michael@0: { michael@0: aStatus = nsEventStatus_eIgnore; michael@0: if (mWidgetListener && michael@0: mWidgetListener->WindowResized(this, aRect.width, aRect.height)) { michael@0: aStatus = nsEventStatus_eConsumeNoDefault; michael@0: } michael@0: } michael@0: michael@0: ///////////////////////////////////// OLD GECKO ECENTS need to Sort /////////////////// michael@0: michael@0: /* static */ bool michael@0: isContextMenuKeyEvent(const QKeyEvent *qe) michael@0: { michael@0: uint32_t kc = QtKeyCodeToDOMKeyCode(qe->key()); michael@0: if (qe->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)) { michael@0: return false; michael@0: } michael@0: michael@0: bool isShift = qe->modifiers() & Qt::ShiftModifier; michael@0: return (kc == NS_VK_F10 && isShift) || michael@0: (kc == NS_VK_CONTEXT_MENU && !isShift); michael@0: } michael@0: michael@0: /* static */void michael@0: InitKeyEvent(WidgetKeyboardEvent &aEvent, QKeyEvent *aQEvent) michael@0: { michael@0: aEvent.InitBasicModifiers(aQEvent->modifiers() & Qt::ControlModifier, michael@0: aQEvent->modifiers() & Qt::AltModifier, michael@0: aQEvent->modifiers() & Qt::ShiftModifier, michael@0: aQEvent->modifiers() & Qt::MetaModifier); michael@0: aEvent.mIsRepeat = michael@0: (aEvent.message == NS_KEY_DOWN || aEvent.message == NS_KEY_PRESS) && michael@0: aQEvent->isAutoRepeat(); michael@0: aEvent.time = 0; michael@0: michael@0: if (sAltGrModifier) { michael@0: aEvent.modifiers |= (MODIFIER_CONTROL | MODIFIER_ALT); michael@0: } michael@0: michael@0: // The transformations above and in qt for the keyval are not invertible michael@0: // so link to the QKeyEvent (which will vanish soon after return from the michael@0: // event callback) to give plugins access to hardware_keycode and state. michael@0: // (An XEvent would be nice but the QKeyEvent is good enough.) michael@0: aEvent.pluginEvent = (void *)aQEvent; michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS_INHERITED(nsWindow, nsBaseWidget, nsISupportsWeakReference) michael@0: michael@0: michael@0: michael@0: void michael@0: nsWindow::ClearCachedResources() michael@0: { michael@0: if (mLayerManager && michael@0: mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_BASIC) { michael@0: mLayerManager->ClearCachedResources(); michael@0: } michael@0: for (nsIWidget* kid = mFirstChild; kid; ) { michael@0: nsIWidget* next = kid->GetNextSibling(); michael@0: static_cast(kid)->ClearCachedResources(); michael@0: kid = next; michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::SetParent(nsIWidget *aNewParent) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aNewParent); michael@0: michael@0: nsCOMPtr kungFuDeathGrip(this); michael@0: nsIWidget* parent = GetParent(); michael@0: if (parent) { michael@0: parent->RemoveChild(this); michael@0: } michael@0: ReparentNativeWidget(aNewParent); michael@0: aNewParent->AddChild(this); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::SetModal(bool aModal) michael@0: { michael@0: LOG(("nsWindow::SetModal [%p] %d, widget[%p]\n", (void *)this, aModal, mWidget)); michael@0: if (mWidget) { michael@0: mWidget->setModality(aModal ? Qt::WindowModal : Qt::NonModal); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement, michael@0: nsIWidget *aWidget, michael@0: bool aActivate) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::SetSizeMode(int32_t aMode) michael@0: { michael@0: nsresult rv; michael@0: michael@0: LOG(("nsWindow::SetSizeMode [%p] %d\n", (void *)this, aMode)); michael@0: if (aMode != nsSizeMode_Minimized) { michael@0: mWidget->requestActivate(); michael@0: } michael@0: michael@0: // Save the requested state. michael@0: rv = nsBaseWidget::SetSizeMode(aMode); michael@0: michael@0: // return if there's no shell or our current state is the same as michael@0: // the mode we were just set to. michael@0: if (!mWidget || mSizeState == mSizeMode) { michael@0: return rv; michael@0: } michael@0: michael@0: switch (aMode) { michael@0: case nsSizeMode_Maximized: michael@0: mWidget->showMaximized(); michael@0: break; michael@0: case nsSizeMode_Minimized: michael@0: mWidget->showMinimized(); michael@0: break; michael@0: case nsSizeMode_Fullscreen: michael@0: mWidget->showFullScreen(); michael@0: break; michael@0: michael@0: default: michael@0: // nsSizeMode_Normal, really. michael@0: mWidget->show(); michael@0: break; michael@0: } michael@0: michael@0: mSizeState = mSizeMode; michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: // Helper function to recursively find the first parent item that michael@0: // is still visible (QGraphicsItem can be hidden even if they are michael@0: // set to visible if one of their ancestors is invisible) michael@0: /* static */ michael@0: void find_first_visible_parent(QWindow* aItem, QWindow*& aVisibleItem) michael@0: { michael@0: NS_ENSURE_TRUE_VOID(aItem); michael@0: michael@0: aVisibleItem = nullptr; michael@0: QWindow* parItem = nullptr; michael@0: while (!aVisibleItem) { michael@0: if (aItem->isVisible()) { michael@0: aVisibleItem = aItem; michael@0: } michael@0: else { michael@0: parItem = aItem->parent(); michael@0: if (parItem) { michael@0: aItem = parItem; michael@0: } michael@0: else { michael@0: aItem->setVisible(true); michael@0: aVisibleItem = aItem; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::GetScreenBounds(nsIntRect &aRect) michael@0: { michael@0: aRect = nsIntRect(nsIntPoint(0, 0), mBounds.Size()); michael@0: if (mIsTopLevel) { michael@0: QPoint pos = mWidget->position(); michael@0: aRect.MoveTo(pos.x(), pos.y()); michael@0: } michael@0: else { michael@0: aRect.MoveTo(WidgetToScreenOffset()); michael@0: } michael@0: LOG(("GetScreenBounds %d %d | %d %d | %d %d\n", michael@0: aRect.x, aRect.y, michael@0: mBounds.width, mBounds.height, michael@0: aRect.width, aRect.height)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::SetIcon(const nsAString& aIconSpec) michael@0: { michael@0: if (!mWidget) michael@0: return NS_OK; michael@0: michael@0: nsCOMPtr iconFile; michael@0: nsAutoCString path; michael@0: nsTArray iconList; michael@0: michael@0: // Look for icons with the following suffixes appended to the base name. michael@0: // The last two entries (for the old XPM format) will be ignored unless michael@0: // no icons are found using the other suffixes. XPM icons are depricated. michael@0: michael@0: const char extensions[6][7] = { ".png", "16.png", "32.png", "48.png", michael@0: ".xpm", "16.xpm" }; michael@0: michael@0: for (uint32_t i = 0; i < ArrayLength(extensions); i++) { michael@0: // Don't bother looking for XPM versions if we found a PNG. michael@0: if (i == ArrayLength(extensions) - 2 && iconList.Length()) michael@0: break; michael@0: michael@0: nsAutoString extension; michael@0: extension.AppendASCII(extensions[i]); michael@0: michael@0: ResolveIconName(aIconSpec, extension, getter_AddRefs(iconFile)); michael@0: if (iconFile) { michael@0: iconFile->GetNativePath(path); michael@0: iconList.AppendElement(path); michael@0: } michael@0: } michael@0: michael@0: // leave the default icon intact if no matching icons were found michael@0: if (iconList.Length() == 0) michael@0: return NS_OK; michael@0: michael@0: return SetWindowIconList(iconList); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::CaptureMouse(bool aCapture) michael@0: { michael@0: LOG(("CaptureMouse %p\n", (void *)this)); michael@0: michael@0: if (!mWidget) michael@0: return NS_OK; michael@0: michael@0: mWidget->setMouseGrabEnabled(aCapture); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: nsWindow::CheckForRollup(double aMouseX, double aMouseY, michael@0: bool aIsWheel) michael@0: { michael@0: nsIRollupListener* rollupListener = GetActiveRollupListener(); michael@0: nsCOMPtr rollupWidget; michael@0: if (rollupListener) { michael@0: rollupWidget = rollupListener->GetRollupWidget(); michael@0: } michael@0: if (!rollupWidget) { michael@0: nsBaseWidget::gRollupListener = nullptr; michael@0: return false; michael@0: } michael@0: michael@0: bool retVal = false; michael@0: MozQWidget *currentPopup = michael@0: (MozQWidget *)rollupWidget->GetNativeData(NS_NATIVE_WINDOW); michael@0: if (!is_mouse_in_window(currentPopup, aMouseX, aMouseY)) { michael@0: bool rollup = true; michael@0: if (aIsWheel) { michael@0: rollup = rollupListener->ShouldRollupOnMouseWheelEvent(); michael@0: retVal = true; michael@0: } michael@0: // if we're dealing with menus, we probably have submenus and michael@0: // we don't want to rollup if the clickis in a parent menu of michael@0: // the current submenu michael@0: uint32_t popupsToRollup = UINT32_MAX; michael@0: if (rollupListener) { michael@0: nsAutoTArray widgetChain; michael@0: uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain); michael@0: for (uint32_t i=0; iGetNativeData(NS_NATIVE_WINDOW); michael@0: if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) { michael@0: if (i < sameTypeCount) { michael@0: rollup = false; michael@0: } michael@0: else { michael@0: popupsToRollup = sameTypeCount; michael@0: } michael@0: break; michael@0: } michael@0: } // foreach parent menu widget michael@0: } // if rollup listener knows about menus michael@0: michael@0: // if we've determined that we should still rollup, do it. michael@0: if (rollup) { michael@0: nsIntPoint pos(aMouseX, aMouseY); michael@0: retVal = rollupListener->Rollup(popupsToRollup, &pos, nullptr); michael@0: } michael@0: } michael@0: michael@0: return retVal; michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: is_mouse_in_window (MozQWidget* aWindow, double aMouseX, double aMouseY) michael@0: { michael@0: return aWindow->geometry().contains(aMouseX, aMouseY); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::GetAttention(int32_t aCycleCount) michael@0: { michael@0: LOG(("nsWindow::GetAttention [%p]\n", (void *)this)); michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: michael@0: michael@0: nsEventStatus michael@0: nsWindow::OnCloseEvent(QCloseEvent *aEvent) michael@0: { michael@0: if (!mWidgetListener) michael@0: return nsEventStatus_eIgnore; michael@0: mWidgetListener->RequestWindowClose(this); michael@0: return nsEventStatus_eConsumeNoDefault; michael@0: } michael@0: michael@0: michael@0: inline bool michael@0: is_latin_shortcut_key(quint32 aKeyval) michael@0: { michael@0: return ((Qt::Key_0 <= aKeyval && aKeyval <= Qt::Key_9) || michael@0: (Qt::Key_A <= aKeyval && aKeyval <= Qt::Key_Z)); michael@0: } michael@0: michael@0: nsEventStatus michael@0: nsWindow::DispatchCommandEvent(nsIAtom* aCommand) michael@0: { michael@0: WidgetCommandEvent event(true, nsGkAtoms::onAppCommand, aCommand, this); michael@0: michael@0: nsEventStatus status; michael@0: DispatchEvent(&event, status); michael@0: michael@0: return status; michael@0: } michael@0: michael@0: nsEventStatus michael@0: nsWindow::DispatchContentCommandEvent(int32_t aMsg) michael@0: { michael@0: WidgetContentCommandEvent event(true, aMsg, this); michael@0: michael@0: nsEventStatus status; michael@0: DispatchEvent(&event, status); michael@0: michael@0: return status; michael@0: } michael@0: michael@0: michael@0: static void michael@0: GetBrandName(nsXPIDLString& brandName) michael@0: { michael@0: nsCOMPtr bundleService = michael@0: mozilla::services::GetStringBundleService(); michael@0: michael@0: nsCOMPtr bundle; michael@0: if (bundleService) { michael@0: bundleService->CreateBundle( michael@0: "chrome://branding/locale/brand.properties", michael@0: getter_AddRefs(bundle)); michael@0: } michael@0: michael@0: if (bundle) { michael@0: bundle->GetStringFromName( michael@0: MOZ_UTF16("brandShortName"), michael@0: getter_Copies(brandName)); michael@0: } michael@0: michael@0: if (brandName.IsEmpty()) { michael@0: brandName.Assign(NS_LITERAL_STRING("Mozilla")); michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::SetWindowClass(const nsAString &xulWinType) michael@0: { michael@0: if (!mWidget) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsXPIDLString brandName; michael@0: GetBrandName(brandName); michael@0: michael@0: #ifdef MOZ_X11 michael@0: XClassHint *class_hint = XAllocClassHint(); michael@0: if (!class_hint) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: const char *role = nullptr; michael@0: class_hint->res_name = ToNewCString(xulWinType); michael@0: if (!class_hint->res_name) { michael@0: XFree(class_hint); michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: class_hint->res_class = ToNewCString(brandName); michael@0: if (!class_hint->res_class) { michael@0: nsMemory::Free(class_hint->res_name); michael@0: XFree(class_hint); michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: // Parse res_name into a name and role. Characters other than michael@0: // [A-Za-z0-9_-] are converted to '_'. Anything after the first michael@0: // colon is assigned to role; if there's no colon, assign the michael@0: // whole thing to both role and res_name. michael@0: for (char *c = class_hint->res_name; *c; c++) { michael@0: if (':' == *c) { michael@0: *c = 0; michael@0: role = c + 1; michael@0: } michael@0: else if (!isascii(*c) || (!isalnum(*c) && ('_' != *c) && ('-' != *c))) michael@0: *c = '_'; michael@0: } michael@0: class_hint->res_name[0] = toupper(class_hint->res_name[0]); michael@0: if (!role) role = class_hint->res_name; michael@0: michael@0: QWindow *widget = mWidget; michael@0: // If widget not show, handle might be null michael@0: if (widget && widget->winId()) { michael@0: XSetClassHint(gfxQtPlatform::GetXDisplay(widget), michael@0: widget->winId(), michael@0: class_hint); michael@0: } michael@0: michael@0: nsMemory::Free(class_hint->res_class); michael@0: nsMemory::Free(class_hint->res_name); michael@0: XFree(class_hint); michael@0: #endif michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsWindow::NativeResize(int32_t aWidth, int32_t aHeight, bool aRepaint) michael@0: { michael@0: LOG(("nsWindow::NativeResize [%p] %d %d\n", (void *)this, michael@0: aWidth, aHeight)); michael@0: michael@0: mNeedsResize = false; michael@0: michael@0: mWidget->resize(aWidth, aHeight); michael@0: michael@0: if (aRepaint) { michael@0: mWidget->renderLater(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsWindow::NativeResize(int32_t aX, int32_t aY, michael@0: int32_t aWidth, int32_t aHeight, michael@0: bool aRepaint) michael@0: { michael@0: LOG(("nsWindow::NativeResize [%p] %d %d %d %d\n", (void *)this, michael@0: aX, aY, aWidth, aHeight)); michael@0: michael@0: mNeedsResize = false; michael@0: mNeedsMove = false; michael@0: michael@0: mWidget->setGeometry(aX, aY, aWidth, aHeight); michael@0: michael@0: if (aRepaint) { michael@0: mWidget->renderLater(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsWindow::NativeShow(bool aAction) michael@0: { michael@0: if (aAction) { michael@0: // On e10s, we never want the child process or plugin process michael@0: // to go fullscreen because if we do the window because visible michael@0: // do to disabled Qt-Xembed michael@0: mWidget->show(); michael@0: // unset our flag now that our window has been shown michael@0: mNeedsShow = false; michael@0: } michael@0: else { michael@0: mWidget->hide(); michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::SetHasTransparentBackground(bool aTransparent) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::GetHasTransparentBackground(bool& aTransparent) michael@0: { michael@0: aTransparent = mIsTransparent; michael@0: return NS_OK; michael@0: } michael@0: michael@0: void * michael@0: nsWindow::SetupPluginPort(void) michael@0: { michael@0: NS_WARNING("Not implemented"); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsresult michael@0: nsWindow::SetWindowIconList(const nsTArray &aIconList) michael@0: { michael@0: QIcon icon; michael@0: michael@0: for (uint32_t i = 0; i < aIconList.Length(); ++i) { michael@0: const char *path = aIconList[i].get(); michael@0: LOG(("window [%p] Loading icon from %s\n", (void *)this, path)); michael@0: icon.addFile(path); michael@0: } michael@0: michael@0: mWidget->setIcon(icon); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsWindow::SetDefaultIcon(void) michael@0: { michael@0: SetIcon(NS_LITERAL_STRING("default")); michael@0: } michael@0: michael@0: void nsWindow::QWidgetDestroyed() michael@0: { michael@0: mWidget = nullptr; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::HideWindowChrome(bool aShouldHide) michael@0: { michael@0: if (!mWidget) { michael@0: // Nothing to hide michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // Sawfish, metacity, and presumably other window managers get michael@0: // confused if we change the window decorations while the window michael@0: // is visible. michael@0: bool wasVisible = false; michael@0: if (mWidget->isVisible()) { michael@0: NativeShow(false); michael@0: wasVisible = true; michael@0: } michael@0: michael@0: if (wasVisible) { michael@0: NativeShow(true); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: ////////////////////////////////////////////////////////////////////// michael@0: michael@0: NS_IMETHODIMP_(bool) michael@0: nsWindow::HasGLContext() michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: michael@0: nsIWidget* michael@0: nsWindow::GetParent(void) michael@0: { michael@0: return mParent; michael@0: } michael@0: michael@0: float michael@0: nsWindow::GetDPI() michael@0: { michael@0: return qApp->primaryScreen()->logicalDotsPerInch(); michael@0: } michael@0: michael@0: void michael@0: nsWindow::OnDestroy(void) michael@0: { michael@0: if (mOnDestroyCalled) { michael@0: return; michael@0: } michael@0: michael@0: mOnDestroyCalled = true; michael@0: michael@0: // release references to children and device context michael@0: nsBaseWidget::OnDestroy(); michael@0: michael@0: // let go of our parent michael@0: mParent = nullptr; michael@0: michael@0: nsCOMPtr kungFuDeathGrip = this; michael@0: NotifyWindowDestroyed(); michael@0: } michael@0: michael@0: bool michael@0: nsWindow::AreBoundsSane(void) michael@0: { michael@0: if (mBounds.width > 0 && mBounds.height > 0) { michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: nsWindow::SetSoftwareKeyboardState(bool aOpen, michael@0: const InputContextAction& aAction) michael@0: { michael@0: if (aOpen) { michael@0: NS_ENSURE_TRUE_VOID(mInputContext.mIMEState.mEnabled != michael@0: IMEState::DISABLED); michael@0: michael@0: // Ensure that opening the virtual keyboard is allowed for this specific michael@0: // InputContext depending on the content.ime.strict.policy pref michael@0: if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN && michael@0: Preferences::GetBool("content.ime.strict_policy", false) && michael@0: !aAction.ContentGotFocusByTrustedCause() && michael@0: !aAction.UserMightRequestOpenVKB()) { michael@0: return; michael@0: } michael@0: } michael@0: michael@0: if (aOpen) { michael@0: qApp->inputMethod()->show(); michael@0: } else { michael@0: qApp->inputMethod()->hide(); michael@0: } michael@0: michael@0: return; michael@0: } michael@0: michael@0: michael@0: void michael@0: nsWindow::ProcessMotionEvent() michael@0: { michael@0: if (mMoveEvent.needDispatch) { michael@0: WidgetMouseEvent event(true, NS_MOUSE_MOVE, this, michael@0: WidgetMouseEvent::eReal); michael@0: michael@0: event.refPoint.x = nscoord(mMoveEvent.pos.x()); michael@0: event.refPoint.y = nscoord(mMoveEvent.pos.y()); michael@0: michael@0: event.InitBasicModifiers(mMoveEvent.modifiers & Qt::ControlModifier, michael@0: mMoveEvent.modifiers & Qt::AltModifier, michael@0: mMoveEvent.modifiers & Qt::ShiftModifier, michael@0: mMoveEvent.modifiers & Qt::MetaModifier); michael@0: event.clickCount = 0; michael@0: michael@0: DispatchEvent(&event); michael@0: mMoveEvent.needDispatch = false; michael@0: } michael@0: michael@0: mTimerStarted = false; michael@0: } michael@0: