Bumping manifests a=b2g-bump
[gecko.git] / widget / qt / nsWindow.cpp
blob3e3f9a544b2af299877ebd7524e8f333ae325bfe
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim:expandtab:shiftwidth=4:tabstop=4:
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "mozilla/ArrayUtils.h"
9 #include "mozilla/MiscEvents.h"
10 #include "mozilla/MouseEvents.h"
11 #include "mozilla/TextEvents.h"
12 #include "mozilla/TouchEvents.h"
14 #include <QGuiApplication>
15 #include <QtGui/QCursor>
16 #include <QIcon>
17 #include <QMouseEvent>
18 #include <QWheelEvent>
19 #include <QResizeEvent>
20 #include <QPaintEngine>
21 #include <QMimeData>
22 #include <QScreen>
24 #include <QtCore/QDebug>
25 #include <QtCore/QEvent>
26 #include <QtCore/QVariant>
27 #include <algorithm>
29 #ifdef MOZ_X11
30 #include <X11/Xlib.h>
31 #include <X11/Xutil.h>
32 #include "gfxXlibSurface.h"
33 #endif //MOZ_X11
35 #include "nsXULAppAPI.h"
37 #include "prlink.h"
39 #include "nsWindow.h"
40 #include "mozqwidget.h"
42 #include "nsIdleService.h"
43 #include "nsRenderingContext.h"
44 #include "nsIRollupListener.h"
45 #include "nsWidgetsCID.h"
46 #include "nsQtKeyUtils.h"
47 #include "mozilla/Services.h"
48 #include "mozilla/Preferences.h"
49 #include "mozilla/Likely.h"
50 #include "mozilla/layers/LayersTypes.h"
51 #include "nsIWidgetListener.h"
52 #include "ClientLayerManager.h"
53 #include "BasicLayers.h"
55 #include "nsIStringBundle.h"
56 #include "nsGfxCIID.h"
58 #include "imgIContainer.h"
59 #include "nsGfxCIID.h"
60 #include "nsIInterfaceRequestorUtils.h"
61 #include "nsAutoPtr.h"
63 #include "gfxQtPlatform.h"
65 #include "nsIDOMWheelEvent.h"
67 #include "GLContext.h"
69 #ifdef MOZ_X11
70 #include "keysym2ucs.h"
71 #endif
73 #include "Layers.h"
74 #include "GLContextProvider.h"
76 using namespace mozilla;
77 using namespace mozilla::gl;
78 using namespace mozilla::widget;
79 using namespace mozilla::gfx;
80 using namespace mozilla::layers;
81 using mozilla::gl::GLContext;
83 #define kWindowPositionSlop 20
85 // Qt
86 static const int WHEEL_DELTA = 120;
87 static bool gGlobalsInitialized = false;
88 static bool sAltGrModifier = false;
90 static void find_first_visible_parent(QWindow* aItem, QWindow*& aVisibleItem);
91 static bool is_mouse_in_window (MozQWidget* aWindow, double aMouseX, double aMouseY);
93 nsWindow::nsWindow()
95 LOG(("%s [%p]\n", __PRETTY_FUNCTION__, (void *)this));
97 mIsTopLevel = false;
98 mIsDestroyed = false;
99 mIsShown = false;
100 mEnabled = true;
101 mWidget = nullptr;
102 mVisible = false;
103 mActivatePending = false;
104 mWindowType = eWindowType_child;
105 mSizeState = nsSizeMode_Normal;
106 mLastSizeMode = nsSizeMode_Normal;
107 mQCursor = Qt::ArrowCursor;
108 mNeedsResize = false;
109 mNeedsMove = false;
110 mListenForResizes = false;
111 mNeedsShow = false;
112 mTimerStarted = false;
113 mMoveEvent.needDispatch = false;
115 if (!gGlobalsInitialized) {
116 gfxPlatform::GetPlatform();
117 gGlobalsInitialized = true;
120 memset(mKeyDownFlags, 0, sizeof(mKeyDownFlags));
122 mIsTransparent = false;
124 mCursor = eCursor_standard;
127 nsWindow::~nsWindow()
129 LOG(("%s [%p]\n", __PRETTY_FUNCTION__, (void *)this));
131 Destroy();
134 nsresult
135 nsWindow::Create(nsIWidget *aParent,
136 nsNativeWidget aNativeParent,
137 const nsIntRect &aRect,
138 nsDeviceContext *aContext,
139 nsWidgetInitData *aInitData)
141 // only set the base parent if we're not going to be a dialog or a
142 // toplevel
143 nsIWidget *baseParent = aParent;
145 // initialize all the common bits of this class
146 BaseCreate(baseParent, aRect, aContext, aInitData);
148 mVisible = true;
150 // and do our common creation
151 mParent = (nsWindow *)aParent;
153 // save our bounds
154 mBounds = aRect;
156 // find native parent
157 MozQWidget *parent = nullptr;
159 if (aParent != nullptr) {
160 parent = static_cast<MozQWidget*>(aParent->GetNativeData(NS_NATIVE_WIDGET));
161 } else if (aNativeParent != nullptr) {
162 parent = static_cast<MozQWidget*>(aNativeParent);
163 if (parent && mParent == nullptr) {
164 mParent = parent->getReceiver();
168 LOG(("Create: nsWindow [%p] mWidget:[%p] parent:[%p], natPar:[%p] mParent:%p\n", (void *)this, (void*)mWidget, parent, aNativeParent, mParent));
170 // ok, create our QGraphicsWidget
171 mWidget = createQWidget(parent, aInitData);
173 if (!mWidget) {
174 return NS_ERROR_OUT_OF_MEMORY;
178 // resize so that everything is set to the right dimensions
179 Resize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, false);
181 // check if we should listen for resizes
182 mListenForResizes = (aNativeParent ||
183 (aInitData && aInitData->mListenForResizes));
185 return NS_OK;
188 MozQWidget*
189 nsWindow::createQWidget(MozQWidget* parent,
190 nsWidgetInitData* aInitData)
192 const char *windowName = nullptr;
193 Qt::WindowFlags flags = Qt::Widget;
195 // ok, create our windows
196 switch (mWindowType) {
197 case eWindowType_dialog:
198 windowName = "topLevelDialog";
199 flags = Qt::Dialog;
200 break;
201 case eWindowType_popup:
202 windowName = "topLevelPopup";
203 flags = Qt::Popup;
204 break;
205 case eWindowType_toplevel:
206 windowName = "topLevelWindow";
207 flags = Qt::Window;
208 break;
209 case eWindowType_invisible:
210 windowName = "topLevelInvisible";
211 break;
212 case eWindowType_child:
213 case eWindowType_plugin:
214 default: // sheet
215 windowName = "paintArea";
216 break;
219 MozQWidget* widget = new MozQWidget(this, parent);
220 if (!widget) {
221 return nullptr;
224 widget->setObjectName(QString(windowName));
225 if (mWindowType == eWindowType_invisible) {
226 #if (QT_VERSION >= QT_VERSION_CHECK(5, 1, 0))
227 widget->setVisibility(QWindow::Hidden);
228 #else
229 widget->hide();
230 #endif
232 if (mWindowType == eWindowType_dialog) {
233 widget->setModality(Qt::WindowModal);
236 widget->create();
238 // create a QGraphicsView if this is a new toplevel window
239 LOG(("nsWindow::%s [%p] Created Window: %s, widget:%p, par:%p\n", __FUNCTION__, (void *)this, windowName, widget, parent));
241 return widget;
244 NS_IMETHODIMP
245 nsWindow::Destroy(void)
247 if (mIsDestroyed || !mWidget) {
248 return NS_OK;
251 LOG(("nsWindow::Destroy [%p]\n", (void *)this));
252 mIsDestroyed = true;
254 /** Need to clean our LayerManager up while still alive */
255 if (mLayerManager) {
256 mLayerManager->Destroy();
258 mLayerManager = nullptr;
260 // It is safe to call DestroyeCompositor several times (here and
261 // in the parent class) since it will take effect only once.
262 // The reason we call it here is because on gtk platforms we need
263 // to destroy the compositor before we destroy the gdk window (which
264 // destroys the the gl context attached to it).
265 DestroyCompositor();
267 ClearCachedResources();
269 nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
270 if (rollupListener) {
271 nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
272 if (static_cast<nsIWidget *>(this) == rollupWidget) {
273 rollupListener->Rollup(0, nullptr, nullptr);
277 Show(false);
279 // walk the list of children and call destroy on them. Have to be
280 // careful, though -- calling destroy on a kid may actually remove
281 // it from our child list, losing its sibling links.
282 for (nsIWidget* kid = mFirstChild; kid; ) {
283 nsIWidget* next = kid->GetNextSibling();
284 kid->Destroy();
285 kid = next;
288 // Destroy thebes surface now. Badness can happen if we destroy
289 // the surface after its X Window.
290 if (mWidget) {
291 mWidget->dropReceiver();
293 // Call deleteLater instead of delete; Qt still needs the object
294 // to be valid even after sending it a Close event. We could
295 // also set WA_DeleteOnClose, but this gives us more control.
296 mWidget->deleteLater();
298 mWidget = nullptr;
300 OnDestroy();
302 return NS_OK;
305 NS_IMETHODIMP
306 nsWindow::Show(bool aState)
308 LOG(("nsWindow::Show [%p] state %d\n", (void *)this, aState));
309 if (aState == mIsShown) {
310 return NS_OK;
313 // Clear our cached resources when the window is hidden.
314 if (mIsShown && !aState) {
315 ClearCachedResources();
318 mIsShown = aState;
320 if ((aState && !AreBoundsSane()) || !mWidget) {
321 LOG(("\tbounds are insane or window hasn't been created yet\n"));
322 mNeedsShow = true;
323 return NS_OK;
326 if (aState) {
327 if (mNeedsMove) {
328 NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height,
329 false);
330 } else if (mNeedsResize) {
331 NativeResize(mBounds.width, mBounds.height, false);
334 else {
335 // If someone is hiding this widget, clear any needing show flag.
336 mNeedsShow = false;
339 NativeShow(aState);
341 return NS_OK;
344 bool
345 nsWindow::IsVisible() const
347 return mIsShown;
350 NS_IMETHODIMP
351 nsWindow::ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY)
353 if (!mWidget) {
354 return NS_ERROR_FAILURE;
357 int32_t screenWidth = qApp->primaryScreen()->size().width();
358 int32_t screenHeight = qApp->primaryScreen()->size().height();
360 if (aAllowSlop) {
361 if (*aX < (kWindowPositionSlop - mBounds.width))
362 *aX = kWindowPositionSlop - mBounds.width;
363 if (*aX > (screenWidth - kWindowPositionSlop))
364 *aX = screenWidth - kWindowPositionSlop;
365 if (*aY < (kWindowPositionSlop - mBounds.height))
366 *aY = kWindowPositionSlop - mBounds.height;
367 if (*aY > (screenHeight - kWindowPositionSlop))
368 *aY = screenHeight - kWindowPositionSlop;
369 } else {
370 if (*aX < 0)
371 *aX = 0;
372 if (*aX > (screenWidth - mBounds.width))
373 *aX = screenWidth - mBounds.width;
374 if (*aY < 0)
375 *aY = 0;
376 if (*aY > (screenHeight - mBounds.height))
377 *aY = screenHeight - mBounds.height;
380 return NS_OK;
383 NS_IMETHODIMP
384 nsWindow::Move(double aX, double aY)
386 LOG(("nsWindow::Move [%p] %f %f\n", (void *)this,
387 aX, aY));
389 int32_t x = NSToIntRound(aX);
390 int32_t y = NSToIntRound(aY);
392 if (mIsTopLevel) {
393 SetSizeMode(nsSizeMode_Normal);
396 if (x == mBounds.x && y == mBounds.y) {
397 return NS_OK;
400 mNeedsMove = false;
402 // update the bounds
403 QPoint pos(x, y);
404 if (mIsTopLevel) {
405 mWidget->setPosition(x, y);
407 else if (mWidget) {
408 // the position of the widget is set relative to the parent
409 // so we map the coordinates accordingly
410 pos = mWidget->mapToGlobal(pos);
411 mWidget->setPosition(pos);
414 mBounds.x = pos.x();
415 mBounds.y = pos.y();
417 NotifyRollupGeometryChange();
418 return NS_OK;
421 NS_IMETHODIMP
422 nsWindow::Resize(double aWidth, double aHeight, bool aRepaint)
424 mBounds.width = NSToIntRound(aWidth);
425 mBounds.height = NSToIntRound(aHeight);
427 if (!mWidget)
428 return NS_OK;
430 if (mIsShown) {
431 if (AreBoundsSane()) {
432 if (mIsTopLevel || mNeedsShow)
433 NativeResize(mBounds.x, mBounds.y,
434 mBounds.width, mBounds.height, aRepaint);
435 else
436 NativeResize(mBounds.width, mBounds.height, aRepaint);
438 // Does it need to be shown because it was previously insane?
439 if (mNeedsShow) {
440 NativeShow(true);
443 else {
444 // If someone has set this so that the needs show flag is false
445 // and it needs to be hidden, update the flag and hide the
446 // window. This flag will be cleared the next time someone
447 // hides the window or shows it. It also prevents us from
448 // calling NativeShow(false) excessively on the window which
449 // causes unneeded X traffic.
450 if (!mNeedsShow) {
451 mNeedsShow = true;
452 NativeShow(false);
456 else if (AreBoundsSane() && mListenForResizes) {
457 // For widgets that we listen for resizes for (widgets created
458 // with native parents) we apparently _always_ have to resize. I
459 // dunno why, but apparently we're lame like that.
460 NativeResize(mBounds.width, mBounds.height, aRepaint);
462 else {
463 mNeedsResize = true;
466 // synthesize a resize event if this isn't a toplevel
467 if (mIsTopLevel || mListenForResizes) {
468 nsEventStatus status;
469 DispatchResizeEvent(mBounds, status);
472 NotifyRollupGeometryChange();
473 return NS_OK;
476 NS_IMETHODIMP
477 nsWindow::Resize(double aX, double aY, double aWidth, double aHeight,
478 bool aRepaint)
480 mBounds.x = NSToIntRound(aX);
481 mBounds.y = NSToIntRound(aY);
482 mBounds.width = NSToIntRound(aWidth);
483 mBounds.height = NSToIntRound(aHeight);
485 mPlaced = true;
487 if (!mWidget) {
488 return NS_OK;
491 // Has this widget been set to visible?
492 if (mIsShown) {
493 // Are the bounds sane?
494 if (AreBoundsSane()) {
495 // Yep? Resize the window
496 NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height,
497 aRepaint);
498 // Does it need to be shown because it was previously insane?
499 if (mNeedsShow)
500 NativeShow(true);
502 else {
503 // If someone has set this so that the needs show flag is false
504 // and it needs to be hidden, update the flag and hide the
505 // window. This flag will be cleared the next time someone
506 // hides the window or shows it. It also prevents us from
507 // calling NativeShow(false) excessively on the window which
508 // causes unneeded X traffic.
509 if (!mNeedsShow) {
510 mNeedsShow = true;
511 NativeShow(false);
515 // If the widget hasn't been shown, mark the widget as needing to be
516 // resized before it is shown
517 else if (AreBoundsSane() && mListenForResizes) {
518 // For widgets that we listen for resizes for (widgets created
519 // with native parents) we apparently _always_ have to resize. I
520 // dunno why, but apparently we're lame like that.
521 NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height,
522 aRepaint);
524 else {
525 mNeedsResize = true;
526 mNeedsMove = true;
529 if (mIsTopLevel || mListenForResizes) {
530 // synthesize a resize event
531 nsEventStatus status;
532 DispatchResizeEvent(mBounds, status);
535 if (aRepaint) {
536 mWidget->renderLater();
539 NotifyRollupGeometryChange();
540 return NS_OK;
543 NS_IMETHODIMP
544 nsWindow::Enable(bool aState)
546 mEnabled = aState;
548 return NS_OK;
551 bool
552 nsWindow::IsEnabled() const
554 return mEnabled;
557 NS_IMETHODIMP
558 nsWindow::SetFocus(bool aRaise)
560 // Make sure that our owning widget has focus. If it doesn't try to
561 // grab it. Note that we don't set our focus flag in this case.
562 LOGFOCUS((" SetFocus [%p]\n", (void *)this));
564 if (!mWidget) {
565 return NS_ERROR_FAILURE;
568 if (mWidget->focusObject()) {
569 return NS_OK;
572 // Because QGraphicsItem cannot get the focus if they are
573 // invisible, we look up the chain, for the lowest visible
574 // parent and focus that one
575 QWindow* realFocusItem = nullptr;
576 find_first_visible_parent(mWidget, realFocusItem);
578 if (!realFocusItem || realFocusItem->focusObject()) {
579 return NS_OK;
582 if (aRaise && mWidget) {
583 // the raising has to happen on the view widget
584 mWidget->raise();
587 // XXXndeakin why is this here? It should dispatch only when the OS
588 // notifies us.
589 DispatchActivateEvent();
591 return NS_OK;
594 NS_IMETHODIMP
595 nsWindow::ConfigureChildren(const nsTArray<nsIWidget::Configuration>& aConfigurations)
597 for (uint32_t i = 0; i < aConfigurations.Length(); ++i) {
598 const Configuration& configuration = aConfigurations[i];
600 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
601 NS_ASSERTION(w->GetParent() == this,
602 "Configured widget is not a child");
604 if (w->mBounds.Size() != configuration.mBounds.Size()) {
605 w->Resize(configuration.mBounds.x, configuration.mBounds.y,
606 configuration.mBounds.width, configuration.mBounds.height,
607 true);
608 } else if (w->mBounds.TopLeft() != configuration.mBounds.TopLeft()) {
609 w->Move(configuration.mBounds.x, configuration.mBounds.y);
612 return NS_OK;
615 NS_IMETHODIMP
616 nsWindow::Invalidate(const nsIntRect &aRect)
618 LOGDRAW(("Invalidate (rect) [%p,%p]: %d %d %d %d\n", (void *)this,
619 (void*)mWidget,aRect.x, aRect.y, aRect.width, aRect.height));
621 if (!mWidget) {
622 return NS_OK;
625 mWidget->renderLater();
627 return NS_OK;
630 nsIntPoint
631 nsWindow::WidgetToScreenOffset()
633 NS_ENSURE_TRUE(mWidget, nsIntPoint(0,0));
635 QPoint origin(0, 0);
636 origin = mWidget->mapToGlobal(origin);
638 return nsIntPoint(origin.x(), origin.y());
641 void*
642 nsWindow::GetNativeData(uint32_t aDataType)
644 switch (aDataType) {
645 case NS_NATIVE_WINDOW:
646 case NS_NATIVE_WIDGET: {
647 return mWidget;
649 case NS_NATIVE_SHAREABLE_WINDOW: {
650 return mWidget ? (void*)mWidget->winId() : nullptr;
652 case NS_NATIVE_DISPLAY: {
653 #ifdef MOZ_X11
654 return gfxQtPlatform::GetXDisplay(mWidget);
655 #endif
656 break;
658 case NS_NATIVE_PLUGIN_PORT:
659 case NS_NATIVE_GRAPHIC:
660 case NS_NATIVE_SHELLWIDGET: {
661 break;
663 default:
664 NS_WARNING("nsWindow::GetNativeData called with bad value");
665 return nullptr;
667 LOG(("nsWindow::%s [%p] aDataType:%i\n", __FUNCTION__, (void *)this, aDataType));
668 return nullptr;
671 NS_IMETHODIMP
672 nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
674 #ifdef DEBUG
675 debug_DumpEvent(stdout, aEvent->widget, aEvent,
676 nsAutoCString("something"), 0);
677 #endif
679 aStatus = nsEventStatus_eIgnore;
681 // send it to the standard callback
682 if (mWidgetListener) {
683 aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
686 return NS_OK;
689 NS_IMETHODIMP_(void)
690 nsWindow::SetInputContext(const InputContext& aContext,
691 const InputContextAction& aAction)
693 NS_ENSURE_TRUE_VOID(mWidget);
695 // SetSoftwareKeyboardState uses mInputContext,
696 // so, before calling that, record aContext in mInputContext.
697 mInputContext = aContext;
699 switch (mInputContext.mIMEState.mEnabled) {
700 case IMEState::ENABLED:
701 case IMEState::PASSWORD:
702 case IMEState::PLUGIN:
703 SetSoftwareKeyboardState(true, aAction);
704 break;
705 default:
706 SetSoftwareKeyboardState(false, aAction);
707 break;
711 NS_IMETHODIMP_(InputContext)
712 nsWindow::GetInputContext()
714 mInputContext.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
715 // Our qt widget looks like using only one context per process.
716 // However, it's better to set the context's pointer.
717 mInputContext.mNativeIMEContext = qApp->inputMethod();
719 return mInputContext;
722 NS_IMETHODIMP
723 nsWindow::ReparentNativeWidget(nsIWidget *aNewParent)
725 NS_PRECONDITION(aNewParent, "");
727 MozQWidget* newParent = static_cast<MozQWidget*>(aNewParent->GetNativeData(NS_NATIVE_WINDOW));
728 NS_ASSERTION(newParent, "Parent widget has a null native window handle");
729 if (mWidget) {
730 mWidget->setParent(newParent);
732 return NS_OK;
735 NS_IMETHODIMP
736 nsWindow::MakeFullScreen(bool aFullScreen)
738 NS_ENSURE_TRUE(mWidget, NS_ERROR_FAILURE);
740 if (aFullScreen) {
741 if (mSizeMode != nsSizeMode_Fullscreen) {
742 mLastSizeMode = mSizeMode;
745 mSizeMode = nsSizeMode_Fullscreen;
746 mWidget->showFullScreen();
748 else {
749 mSizeMode = mLastSizeMode;
751 switch (mSizeMode) {
752 case nsSizeMode_Maximized:
753 mWidget->showMaximized();
754 break;
755 case nsSizeMode_Minimized:
756 mWidget->showMinimized();
757 break;
758 case nsSizeMode_Normal:
759 mWidget->showNormal();
760 break;
761 default:
762 mWidget->showNormal();
763 break;
767 NS_ASSERTION(mLastSizeMode != nsSizeMode_Fullscreen,
768 "mLastSizeMode should never be fullscreen");
769 return nsBaseWidget::MakeFullScreen(aFullScreen);
772 LayerManager*
773 nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager,
774 LayersBackend aBackendHint,
775 LayerManagerPersistence aPersistence,
776 bool* aAllowRetaining)
778 if (!mLayerManager && eTransparencyTransparent == GetTransparencyMode()) {
779 mLayerManager = CreateBasicLayerManager();
782 return nsBaseWidget::GetLayerManager(aShadowManager, aBackendHint,
783 aPersistence, aAllowRetaining);
786 void
787 nsWindow::UserActivity()
789 if (!mIdleService) {
790 mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
793 if (mIdleService) {
794 mIdleService->ResetIdleTimeOut(0);
798 uint32_t
799 nsWindow::GetGLFrameBufferFormat()
801 if (mLayerManager &&
802 mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_OPENGL) {
803 return LOCAL_GL_RGB;
805 return LOCAL_GL_NONE;
808 TemporaryRef<DrawTarget>
809 nsWindow::StartRemoteDrawing()
811 if (!mWidget) {
812 return nullptr;
815 #ifdef MOZ_X11
816 Display* dpy = gfxQtPlatform::GetXDisplay(mWidget);
817 Screen* screen = DefaultScreenOfDisplay(dpy);
818 Visual* defaultVisual = DefaultVisualOfScreen(screen);
819 gfxASurface* surf = new gfxXlibSurface(dpy, mWidget->winId(), defaultVisual,
820 gfxIntSize(mWidget->width(),
821 mWidget->height()));
823 IntSize size(surf->GetSize().width, surf->GetSize().height);
824 if (size.width <= 0 || size.height <= 0) {
825 return nullptr;
828 return gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf, size);
829 #else
830 return nullptr;
831 #endif
834 NS_IMETHODIMP
835 nsWindow::SetCursor(nsCursor aCursor)
837 if (mCursor == aCursor && !mUpdateCursor) {
838 return NS_OK;
840 mUpdateCursor = false;
841 mCursor = aCursor;
842 if (mWidget) {
843 mWidget->SetCursor(mCursor);
845 return NS_OK;
848 NS_IMETHODIMP
849 nsWindow::SetTitle(const nsAString& aTitle)
851 QString qStr(QString::fromUtf16((const ushort*)aTitle.BeginReading(), aTitle.Length()));
853 mWidget->setTitle(qStr);
855 return NS_OK;
858 // EVENTS
860 void
861 nsWindow::OnPaint()
863 LOGDRAW(("nsWindow::%s [%p]\n", __FUNCTION__, (void *)this));
864 nsIWidgetListener* listener =
865 mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
866 if (!listener) {
867 return;
870 listener->WillPaintWindow(this);
872 switch (GetLayerManager()->GetBackendType()) {
873 case mozilla::layers::LayersBackend::LAYERS_CLIENT: {
874 nsIntRegion region(nsIntRect(0, 0, mWidget->width(), mWidget->height()));
875 listener->PaintWindow(this, region);
876 break;
878 default:
879 NS_ERROR("Invalid layer manager");
882 listener->DidPaintWindow();
885 nsEventStatus
886 nsWindow::moveEvent(QMoveEvent* aEvent)
888 LOG(("configure event [%p] %d %d\n", (void *)this,
889 aEvent->pos().x(), aEvent->pos().y()));
891 // can we shortcut?
892 if (!mWidget || !mWidgetListener)
893 return nsEventStatus_eIgnore;
895 if ((mBounds.x == aEvent->pos().x() &&
896 mBounds.y == aEvent->pos().y()))
898 return nsEventStatus_eIgnore;
901 NotifyWindowMoved(aEvent->pos().x(), aEvent->pos().y());
902 return nsEventStatus_eConsumeNoDefault;
905 nsEventStatus
906 nsWindow::resizeEvent(QResizeEvent* aEvent)
908 nsIntRect rect;
910 // Generate XPFE resize event
911 GetBounds(rect);
913 rect.width = aEvent->size().width();
914 rect.height = aEvent->size().height();
916 mBounds.width = rect.width;
917 mBounds.height = rect.height;
919 nsEventStatus status;
920 DispatchResizeEvent(rect, status);
921 return status;
924 nsEventStatus
925 nsWindow::mouseMoveEvent(QMouseEvent* aEvent)
927 UserActivity();
929 mMoveEvent.pos = aEvent->pos();
930 mMoveEvent.modifiers = aEvent->modifiers();
931 mMoveEvent.needDispatch = true;
932 DispatchMotionToMainThread();
934 return nsEventStatus_eIgnore;
937 static void
938 InitMouseEvent(WidgetMouseEvent& aMouseEvent, QMouseEvent* aEvent,
939 int aClickCount)
941 aMouseEvent.refPoint.x = nscoord(aEvent->pos().x());
942 aMouseEvent.refPoint.y = nscoord(aEvent->pos().y());
944 aMouseEvent.InitBasicModifiers(aEvent->modifiers() & Qt::ControlModifier,
945 aEvent->modifiers() & Qt::AltModifier,
946 aEvent->modifiers() & Qt::ShiftModifier,
947 aEvent->modifiers() & Qt::MetaModifier);
948 aMouseEvent.clickCount = aClickCount;
950 switch (aEvent->button()) {
951 case Qt::LeftButton:
952 aMouseEvent.button = WidgetMouseEvent::eLeftButton;
953 break;
954 case Qt::RightButton:
955 aMouseEvent.button = WidgetMouseEvent::eRightButton;
956 break;
957 case Qt::MiddleButton:
958 aMouseEvent.button = WidgetMouseEvent::eMiddleButton;
959 break;
960 default:
961 break;
965 static bool
966 IsAcceptedButton(Qt::MouseButton button)
968 switch (button) {
969 case Qt::LeftButton:
970 case Qt::RightButton:
971 case Qt::MiddleButton:
972 return true;
973 default:
974 return false;
978 nsEventStatus
979 nsWindow::mousePressEvent(QMouseEvent* aEvent)
981 // The user has done something.
982 UserActivity();
984 QPoint pos = aEvent->pos();
986 // we check against the widgets geometry, so use parent coordinates
987 // for the check
988 if (mWidget)
989 pos = mWidget->mapToGlobal(pos);
991 if (CheckForRollup(pos.x(), pos.y(), false))
992 return nsEventStatus_eIgnore;
994 if (!IsAcceptedButton(aEvent->button())) {
995 if (aEvent->button() == Qt::BackButton)
996 return DispatchCommandEvent(nsGkAtoms::Back);
997 if (aEvent->button() == Qt::ForwardButton)
998 return DispatchCommandEvent(nsGkAtoms::Forward);
999 return nsEventStatus_eIgnore;
1002 WidgetMouseEvent event(true, NS_MOUSE_BUTTON_DOWN, this,
1003 WidgetMouseEvent::eReal);
1004 InitMouseEvent(event, aEvent, 1);
1005 nsEventStatus status = DispatchEvent(&event);
1007 // Right click on linux should also pop up a context menu.
1008 if (event.button == WidgetMouseEvent::eRightButton &&
1009 MOZ_LIKELY(!mIsDestroyed)) {
1010 WidgetMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this,
1011 WidgetMouseEvent::eReal);
1012 InitMouseEvent(contextMenuEvent, aEvent, 1);
1013 DispatchEvent(&contextMenuEvent, status);
1016 return status;
1019 nsEventStatus
1020 nsWindow::mouseReleaseEvent(QMouseEvent* aEvent)
1022 // The user has done something.
1023 UserActivity();
1025 if (!IsAcceptedButton(aEvent->button()))
1026 return nsEventStatus_eIgnore;
1028 WidgetMouseEvent event(true, NS_MOUSE_BUTTON_UP, this,
1029 WidgetMouseEvent::eReal);
1030 InitMouseEvent(event, aEvent, 1);
1031 return DispatchEvent(&event);
1034 nsEventStatus
1035 nsWindow::mouseDoubleClickEvent(QMouseEvent* aEvent)
1037 // The user has done something.
1038 UserActivity();
1040 if (!IsAcceptedButton(aEvent->button()))
1041 return nsEventStatus_eIgnore;
1043 WidgetMouseEvent event(true, NS_MOUSE_DOUBLECLICK, this,
1044 WidgetMouseEvent::eReal);
1045 InitMouseEvent(event, aEvent, 2);
1046 return DispatchEvent(&event);
1049 nsEventStatus
1050 nsWindow::focusInEvent(QFocusEvent* aEvent)
1052 LOGFOCUS(("OnFocusInEvent [%p]\n", (void *)this));
1054 if (!mWidget) {
1055 return nsEventStatus_eIgnore;
1058 DispatchActivateEventOnTopLevelWindow();
1060 LOGFOCUS(("Events sent from focus in event [%p]\n", (void *)this));
1061 return nsEventStatus_eIgnore;
1064 nsEventStatus
1065 nsWindow::focusOutEvent(QFocusEvent* aEvent)
1067 LOGFOCUS(("OnFocusOutEvent [%p]\n", (void *)this));
1069 if (!mWidget) {
1070 return nsEventStatus_eIgnore;
1073 DispatchDeactivateEventOnTopLevelWindow();
1075 LOGFOCUS(("Done with container focus out [%p]\n", (void *)this));
1076 return nsEventStatus_eIgnore;
1079 static bool
1080 IsContextMenuKeyEvent(const QKeyEvent* aQEvent)
1082 if (aQEvent->modifiers() & (Qt::ControlModifier |
1083 Qt::AltModifier |
1084 Qt::MetaModifier)) {
1085 return false;
1088 bool isShift = aQEvent->modifiers() & Qt::ShiftModifier;
1089 uint32_t keyCode = QtKeyCodeToDOMKeyCode(aQEvent->key());
1090 return (keyCode == NS_VK_F10 && isShift) ||
1091 (keyCode == NS_VK_CONTEXT_MENU && !isShift);
1094 static void
1095 InitKeyEvent(WidgetKeyboardEvent& aEvent, QKeyEvent* aQEvent)
1097 aEvent.InitBasicModifiers(aQEvent->modifiers() & Qt::ControlModifier,
1098 aQEvent->modifiers() & Qt::AltModifier,
1099 aQEvent->modifiers() & Qt::ShiftModifier,
1100 aQEvent->modifiers() & Qt::MetaModifier);
1102 aEvent.mIsRepeat =
1103 (aEvent.message == NS_KEY_DOWN || aEvent.message == NS_KEY_PRESS) &&
1104 aQEvent->isAutoRepeat();
1105 aEvent.time = 0;
1107 if (sAltGrModifier) {
1108 aEvent.modifiers |= (MODIFIER_CONTROL | MODIFIER_ALT);
1111 if (aQEvent->text().length() && aQEvent->text()[0].isPrint()) {
1112 aEvent.charCode = (int32_t) aQEvent->text()[0].unicode();
1113 aEvent.keyCode = 0;
1114 aEvent.mKeyNameIndex = KEY_NAME_INDEX_PrintableKey;
1115 } else {
1116 aEvent.charCode = 0;
1117 aEvent.keyCode = QtKeyCodeToDOMKeyCode(aQEvent->key());
1118 aEvent.mKeyNameIndex = QtKeyCodeToDOMKeyNameIndex(aQEvent->key());
1121 aEvent.mCodeNameIndex = ScanCodeToDOMCodeNameIndex(aQEvent->nativeScanCode());
1123 // The transformations above and in qt for the keyval are not invertible
1124 // so link to the QKeyEvent (which will vanish soon after return from the
1125 // event callback) to give plugins access to hardware_keycode and state.
1126 // (An XEvent would be nice but the QKeyEvent is good enough.)
1127 aEvent.mPluginEvent.Copy(*aQEvent);
1130 nsEventStatus
1131 nsWindow::keyPressEvent(QKeyEvent* aEvent)
1133 LOGFOCUS(("OnKeyPressEvent [%p]\n", (void *)this));
1135 // The user has done something.
1136 UserActivity();
1138 if (aEvent->key() == Qt::Key_AltGr) {
1139 sAltGrModifier = true;
1142 // Before we dispatch a key, check if it's the context menu key.
1143 // If so, send a context menu key event instead.
1144 if (IsContextMenuKeyEvent(aEvent)) {
1145 WidgetMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this,
1146 WidgetMouseEvent::eReal,
1147 WidgetMouseEvent::eContextMenuKey);
1148 return DispatchEvent(&contextMenuEvent);
1151 //:TODO: fix shortcuts hebrew for non X11,
1152 //see Bug 562195##51
1154 uint32_t domKeyCode = QtKeyCodeToDOMKeyCode(aEvent->key());
1156 if (!aEvent->isAutoRepeat() && !IsKeyDown(domKeyCode)) {
1157 SetKeyDownFlag(domKeyCode);
1159 WidgetKeyboardEvent downEvent(true, NS_KEY_DOWN, this);
1160 InitKeyEvent(downEvent, aEvent);
1162 nsEventStatus status = DispatchEvent(&downEvent);
1164 // DispatchEvent can Destroy us (bug 378273)
1165 if (MOZ_UNLIKELY(mIsDestroyed)) {
1166 qWarning() << "Returning[" << __LINE__ << "]: " << "Window destroyed";
1167 return status;
1170 // If prevent default on keydown, don't dispatch keypress event
1171 if (status == nsEventStatus_eConsumeNoDefault) {
1172 return nsEventStatus_eConsumeNoDefault;
1176 // Don't pass modifiers as NS_KEY_PRESS events.
1177 // Instead of selectively excluding some keys from NS_KEY_PRESS events,
1178 // we instead selectively include (as per MSDN spec
1179 // ( http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keypress%28VS.71%29.aspx );
1180 // no official spec covers KeyPress events).
1181 if (aEvent->key() == Qt::Key_Shift ||
1182 aEvent->key() == Qt::Key_Control ||
1183 aEvent->key() == Qt::Key_Meta ||
1184 aEvent->key() == Qt::Key_Alt ||
1185 aEvent->key() == Qt::Key_AltGr) {
1186 return nsEventStatus_eIgnore;
1189 // Look for specialized app-command keys
1190 switch (aEvent->key()) {
1191 case Qt::Key_Back:
1192 return DispatchCommandEvent(nsGkAtoms::Back);
1193 case Qt::Key_Forward:
1194 return DispatchCommandEvent(nsGkAtoms::Forward);
1195 case Qt::Key_Refresh:
1196 return DispatchCommandEvent(nsGkAtoms::Reload);
1197 case Qt::Key_Stop:
1198 return DispatchCommandEvent(nsGkAtoms::Stop);
1199 case Qt::Key_Search:
1200 return DispatchCommandEvent(nsGkAtoms::Search);
1201 case Qt::Key_Favorites:
1202 return DispatchCommandEvent(nsGkAtoms::Bookmarks);
1203 case Qt::Key_HomePage:
1204 return DispatchCommandEvent(nsGkAtoms::Home);
1205 case Qt::Key_Copy:
1206 case Qt::Key_F16: // F16, F20, F18, F14 are old keysyms for Copy Cut Paste Undo
1207 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_COPY);
1208 case Qt::Key_Cut:
1209 case Qt::Key_F20:
1210 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_CUT);
1211 case Qt::Key_Paste:
1212 case Qt::Key_F18:
1213 case Qt::Key_F9:
1214 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_PASTE);
1215 case Qt::Key_F14:
1216 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_UNDO);
1219 // Qt::Key_Redo and Qt::Key_Undo are not available yet.
1220 if (aEvent->nativeVirtualKey() == 0xff66) {
1221 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_REDO);
1223 if (aEvent->nativeVirtualKey() == 0xff65) {
1224 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_UNDO);
1227 WidgetKeyboardEvent event(true, NS_KEY_PRESS, this);
1228 InitKeyEvent(event, aEvent);
1229 // Seend the key press event
1230 return DispatchEvent(&event);
1233 nsEventStatus
1234 nsWindow::keyReleaseEvent(QKeyEvent* aEvent)
1236 LOGFOCUS(("OnKeyReleaseEvent [%p]\n", (void *)this));
1238 // The user has done something.
1239 UserActivity();
1241 if (IsContextMenuKeyEvent(aEvent)) {
1242 // er, what do we do here? DoDefault or NoDefault?
1243 return nsEventStatus_eConsumeDoDefault;
1246 // send the key event as a key up event
1247 WidgetKeyboardEvent event(true, NS_KEY_UP, this);
1248 InitKeyEvent(event, aEvent);
1250 if (aEvent->key() == Qt::Key_AltGr) {
1251 sAltGrModifier = false;
1254 // unset the key down flag
1255 ClearKeyDownFlag(event.keyCode);
1257 return DispatchEvent(&event);
1260 nsEventStatus
1261 nsWindow::wheelEvent(QWheelEvent* aEvent)
1263 // check to see if we should rollup
1264 WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, this);
1265 wheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE;
1267 // negative values for aEvent->delta indicate downward scrolling;
1268 // this is opposite Gecko usage.
1269 // TODO: Store the unused delta values due to fraction round and add it
1270 // to next event. The stored values should be reset by other
1271 // direction scroll event.
1272 int32_t delta = (int)(aEvent->delta() / WHEEL_DELTA) * -3;
1274 switch (aEvent->orientation()) {
1275 case Qt::Vertical:
1276 wheelEvent.deltaY = wheelEvent.lineOrPageDeltaY = delta;
1277 break;
1278 case Qt::Horizontal:
1279 wheelEvent.deltaX = wheelEvent.lineOrPageDeltaX = delta;
1280 break;
1281 default:
1282 Q_ASSERT(0);
1283 break;
1286 wheelEvent.refPoint.x = nscoord(aEvent->pos().x());
1287 wheelEvent.refPoint.y = nscoord(aEvent->pos().y());
1289 wheelEvent.InitBasicModifiers(aEvent->modifiers() & Qt::ControlModifier,
1290 aEvent->modifiers() & Qt::AltModifier,
1291 aEvent->modifiers() & Qt::ShiftModifier,
1292 aEvent->modifiers() & Qt::MetaModifier);
1293 wheelEvent.time = 0;
1295 return DispatchEvent(&wheelEvent);
1298 nsEventStatus
1299 nsWindow::showEvent(QShowEvent *)
1301 LOG(("%s [%p]\n", __PRETTY_FUNCTION__,(void *)this));
1302 mVisible = true;
1303 return nsEventStatus_eConsumeDoDefault;
1306 nsEventStatus
1307 nsWindow::hideEvent(QHideEvent *)
1309 LOG(("%s [%p]\n", __PRETTY_FUNCTION__,(void *)this));
1310 mVisible = false;
1311 return nsEventStatus_eConsumeDoDefault;
1314 nsEventStatus nsWindow::touchEvent(QTouchEvent* aEvent)
1316 return nsEventStatus_eIgnore;
1319 nsEventStatus
1320 nsWindow::tabletEvent(QTabletEvent* aEvent)
1322 LOGFOCUS(("nsWindow::%s [%p]\n", __FUNCTION__, (void *)this));
1323 return nsEventStatus_eIgnore;
1326 // Helpers
1328 nsEventStatus
1329 nsWindow::DispatchEvent(WidgetGUIEvent* aEvent)
1331 nsEventStatus status;
1332 DispatchEvent(aEvent, status);
1333 return status;
1336 void
1337 nsWindow::DispatchActivateEvent(void)
1339 if (mWidgetListener) {
1340 mWidgetListener->WindowActivated();
1344 void
1345 nsWindow::DispatchDeactivateEvent(void)
1347 if (mWidgetListener) {
1348 mWidgetListener->WindowDeactivated();
1352 void
1353 nsWindow::DispatchActivateEventOnTopLevelWindow(void)
1355 nsWindow* topLevelWindow = static_cast<nsWindow*>(GetTopLevelWidget());
1356 if (topLevelWindow != nullptr) {
1357 topLevelWindow->DispatchActivateEvent();
1361 void
1362 nsWindow::DispatchDeactivateEventOnTopLevelWindow(void)
1364 nsWindow* topLevelWindow = static_cast<nsWindow*>(GetTopLevelWidget());
1365 if (topLevelWindow != nullptr) {
1366 topLevelWindow->DispatchDeactivateEvent();
1370 void
1371 nsWindow::DispatchResizeEvent(nsIntRect &aRect, nsEventStatus &aStatus)
1373 aStatus = nsEventStatus_eIgnore;
1374 if (mWidgetListener &&
1375 mWidgetListener->WindowResized(this, aRect.width, aRect.height)) {
1376 aStatus = nsEventStatus_eConsumeNoDefault;
1380 ///////////////////////////////////// OLD GECKO ECENTS need to Sort ///////////////////
1382 NS_IMPL_ISUPPORTS_INHERITED(nsWindow, nsBaseWidget, nsISupportsWeakReference)
1386 void
1387 nsWindow::ClearCachedResources()
1389 if (mLayerManager &&
1390 mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_BASIC) {
1391 mLayerManager->ClearCachedResources();
1393 for (nsIWidget* kid = mFirstChild; kid; ) {
1394 nsIWidget* next = kid->GetNextSibling();
1395 static_cast<nsWindow*>(kid)->ClearCachedResources();
1396 kid = next;
1400 NS_IMETHODIMP
1401 nsWindow::SetParent(nsIWidget *aNewParent)
1403 NS_ENSURE_ARG_POINTER(aNewParent);
1405 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
1406 nsIWidget* parent = GetParent();
1407 if (parent) {
1408 parent->RemoveChild(this);
1410 ReparentNativeWidget(aNewParent);
1411 aNewParent->AddChild(this);
1412 return NS_OK;
1415 NS_IMETHODIMP
1416 nsWindow::SetModal(bool aModal)
1418 LOG(("nsWindow::SetModal [%p] %d, widget[%p]\n", (void *)this, aModal, mWidget));
1419 if (mWidget) {
1420 mWidget->setModality(aModal ? Qt::WindowModal : Qt::NonModal);
1423 return NS_OK;
1427 NS_IMETHODIMP
1428 nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
1429 nsIWidget *aWidget,
1430 bool aActivate)
1432 return NS_ERROR_NOT_IMPLEMENTED;
1435 NS_IMETHODIMP
1436 nsWindow::SetSizeMode(int32_t aMode)
1438 nsresult rv;
1440 LOG(("nsWindow::SetSizeMode [%p] %d\n", (void *)this, aMode));
1441 if (aMode != nsSizeMode_Minimized) {
1442 mWidget->requestActivate();
1445 // Save the requested state.
1446 rv = nsBaseWidget::SetSizeMode(aMode);
1448 // return if there's no shell or our current state is the same as
1449 // the mode we were just set to.
1450 if (!mWidget || mSizeState == mSizeMode) {
1451 return rv;
1454 switch (aMode) {
1455 case nsSizeMode_Maximized:
1456 mWidget->showMaximized();
1457 break;
1458 case nsSizeMode_Minimized:
1459 mWidget->showMinimized();
1460 break;
1461 case nsSizeMode_Fullscreen:
1462 mWidget->showFullScreen();
1463 break;
1465 default:
1466 // nsSizeMode_Normal, really.
1467 mWidget->show();
1468 break;
1471 mSizeState = mSizeMode;
1473 return rv;
1476 // Helper function to recursively find the first parent item that
1477 // is still visible (QGraphicsItem can be hidden even if they are
1478 // set to visible if one of their ancestors is invisible)
1479 /* static */
1480 void find_first_visible_parent(QWindow* aItem, QWindow*& aVisibleItem)
1482 NS_ENSURE_TRUE_VOID(aItem);
1484 aVisibleItem = nullptr;
1485 QWindow* parItem = nullptr;
1486 while (!aVisibleItem) {
1487 if (aItem->isVisible()) {
1488 aVisibleItem = aItem;
1490 else {
1491 parItem = aItem->parent();
1492 if (parItem) {
1493 aItem = parItem;
1495 else {
1496 aItem->setVisible(true);
1497 aVisibleItem = aItem;
1503 NS_IMETHODIMP
1504 nsWindow::GetScreenBounds(nsIntRect &aRect)
1506 aRect = nsIntRect(nsIntPoint(0, 0), mBounds.Size());
1507 if (mIsTopLevel) {
1508 QPoint pos = mWidget->position();
1509 aRect.MoveTo(pos.x(), pos.y());
1511 else {
1512 aRect.MoveTo(WidgetToScreenOffset());
1514 LOG(("GetScreenBounds %d %d | %d %d | %d %d\n",
1515 aRect.x, aRect.y,
1516 mBounds.width, mBounds.height,
1517 aRect.width, aRect.height));
1518 return NS_OK;
1521 NS_IMETHODIMP
1522 nsWindow::SetIcon(const nsAString& aIconSpec)
1524 if (!mWidget)
1525 return NS_OK;
1527 nsCOMPtr<nsIFile> iconFile;
1528 nsAutoCString path;
1529 nsTArray<nsCString> iconList;
1531 // Look for icons with the following suffixes appended to the base name.
1532 // The last two entries (for the old XPM format) will be ignored unless
1533 // no icons are found using the other suffixes. XPM icons are depricated.
1535 const char extensions[6][7] = { ".png", "16.png", "32.png", "48.png",
1536 ".xpm", "16.xpm" };
1538 for (uint32_t i = 0; i < ArrayLength(extensions); i++) {
1539 // Don't bother looking for XPM versions if we found a PNG.
1540 if (i == ArrayLength(extensions) - 2 && iconList.Length())
1541 break;
1543 nsAutoString extension;
1544 extension.AppendASCII(extensions[i]);
1546 ResolveIconName(aIconSpec, extension, getter_AddRefs(iconFile));
1547 if (iconFile) {
1548 iconFile->GetNativePath(path);
1549 iconList.AppendElement(path);
1553 // leave the default icon intact if no matching icons were found
1554 if (iconList.Length() == 0)
1555 return NS_OK;
1557 return SetWindowIconList(iconList);
1560 NS_IMETHODIMP
1561 nsWindow::CaptureMouse(bool aCapture)
1563 LOG(("CaptureMouse %p\n", (void *)this));
1565 if (!mWidget)
1566 return NS_OK;
1568 mWidget->setMouseGrabEnabled(aCapture);
1570 return NS_OK;
1573 bool
1574 nsWindow::CheckForRollup(double aMouseX, double aMouseY,
1575 bool aIsWheel)
1577 nsIRollupListener* rollupListener = GetActiveRollupListener();
1578 nsCOMPtr<nsIWidget> rollupWidget;
1579 if (rollupListener) {
1580 rollupWidget = rollupListener->GetRollupWidget();
1582 if (!rollupWidget) {
1583 nsBaseWidget::gRollupListener = nullptr;
1584 return false;
1587 bool retVal = false;
1588 MozQWidget *currentPopup =
1589 (MozQWidget *)rollupWidget->GetNativeData(NS_NATIVE_WINDOW);
1590 if (!is_mouse_in_window(currentPopup, aMouseX, aMouseY)) {
1591 bool rollup = true;
1592 if (aIsWheel) {
1593 rollup = rollupListener->ShouldRollupOnMouseWheelEvent();
1594 retVal = true;
1596 // if we're dealing with menus, we probably have submenus and
1597 // we don't want to rollup if the clickis in a parent menu of
1598 // the current submenu
1599 uint32_t popupsToRollup = UINT32_MAX;
1600 if (rollupListener) {
1601 nsAutoTArray<nsIWidget*, 5> widgetChain;
1602 uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain);
1603 for (uint32_t i=0; i<widgetChain.Length(); ++i) {
1604 nsIWidget* widget = widgetChain[i];
1605 MozQWidget* currWindow =
1606 (MozQWidget*) widget->GetNativeData(NS_NATIVE_WINDOW);
1607 if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) {
1608 if (i < sameTypeCount) {
1609 rollup = false;
1611 else {
1612 popupsToRollup = sameTypeCount;
1614 break;
1616 } // foreach parent menu widget
1617 } // if rollup listener knows about menus
1619 // if we've determined that we should still rollup, do it.
1620 if (rollup) {
1621 nsIntPoint pos(aMouseX, aMouseY);
1622 retVal = rollupListener->Rollup(popupsToRollup, &pos, nullptr);
1626 return retVal;
1629 /* static */
1630 bool
1631 is_mouse_in_window (MozQWidget* aWindow, double aMouseX, double aMouseY)
1633 return aWindow->geometry().contains(aMouseX, aMouseY);
1636 NS_IMETHODIMP
1637 nsWindow::GetAttention(int32_t aCycleCount)
1639 LOG(("nsWindow::GetAttention [%p]\n", (void *)this));
1640 return NS_ERROR_NOT_IMPLEMENTED;
1645 nsEventStatus
1646 nsWindow::OnCloseEvent(QCloseEvent *aEvent)
1648 if (!mWidgetListener)
1649 return nsEventStatus_eIgnore;
1650 mWidgetListener->RequestWindowClose(this);
1651 return nsEventStatus_eConsumeNoDefault;
1655 inline bool
1656 is_latin_shortcut_key(quint32 aKeyval)
1658 return ((Qt::Key_0 <= aKeyval && aKeyval <= Qt::Key_9) ||
1659 (Qt::Key_A <= aKeyval && aKeyval <= Qt::Key_Z));
1662 nsEventStatus
1663 nsWindow::DispatchCommandEvent(nsIAtom* aCommand)
1665 WidgetCommandEvent event(true, nsGkAtoms::onAppCommand, aCommand, this);
1667 nsEventStatus status;
1668 DispatchEvent(&event, status);
1670 return status;
1673 nsEventStatus
1674 nsWindow::DispatchContentCommandEvent(int32_t aMsg)
1676 WidgetContentCommandEvent event(true, aMsg, this);
1678 nsEventStatus status;
1679 DispatchEvent(&event, status);
1681 return status;
1685 static void
1686 GetBrandName(nsXPIDLString& brandName)
1688 nsCOMPtr<nsIStringBundleService> bundleService =
1689 mozilla::services::GetStringBundleService();
1691 nsCOMPtr<nsIStringBundle> bundle;
1692 if (bundleService) {
1693 bundleService->CreateBundle(
1694 "chrome://branding/locale/brand.properties",
1695 getter_AddRefs(bundle));
1698 if (bundle) {
1699 bundle->GetStringFromName(
1700 MOZ_UTF16("brandShortName"),
1701 getter_Copies(brandName));
1704 if (brandName.IsEmpty()) {
1705 brandName.AssignLiteral(MOZ_UTF16("Mozilla"));
1709 NS_IMETHODIMP
1710 nsWindow::SetWindowClass(const nsAString &xulWinType)
1712 if (!mWidget) {
1713 return NS_ERROR_FAILURE;
1716 nsXPIDLString brandName;
1717 GetBrandName(brandName);
1719 #ifdef MOZ_X11
1720 XClassHint *class_hint = XAllocClassHint();
1721 if (!class_hint) {
1722 return NS_ERROR_OUT_OF_MEMORY;
1724 const char *role = nullptr;
1725 class_hint->res_name = ToNewCString(xulWinType);
1726 if (!class_hint->res_name) {
1727 XFree(class_hint);
1728 return NS_ERROR_OUT_OF_MEMORY;
1730 class_hint->res_class = ToNewCString(brandName);
1731 if (!class_hint->res_class) {
1732 nsMemory::Free(class_hint->res_name);
1733 XFree(class_hint);
1734 return NS_ERROR_OUT_OF_MEMORY;
1737 // Parse res_name into a name and role. Characters other than
1738 // [A-Za-z0-9_-] are converted to '_'. Anything after the first
1739 // colon is assigned to role; if there's no colon, assign the
1740 // whole thing to both role and res_name.
1741 for (char *c = class_hint->res_name; *c; c++) {
1742 if (':' == *c) {
1743 *c = 0;
1744 role = c + 1;
1746 else if (!isascii(*c) || (!isalnum(*c) && ('_' != *c) && ('-' != *c)))
1747 *c = '_';
1749 class_hint->res_name[0] = toupper(class_hint->res_name[0]);
1750 if (!role) role = class_hint->res_name;
1752 QWindow *widget = mWidget;
1753 // If widget not show, handle might be null
1754 if (widget && widget->winId()) {
1755 XSetClassHint(gfxQtPlatform::GetXDisplay(widget),
1756 widget->winId(),
1757 class_hint);
1760 nsMemory::Free(class_hint->res_class);
1761 nsMemory::Free(class_hint->res_name);
1762 XFree(class_hint);
1763 #endif
1765 return NS_OK;
1768 void
1769 nsWindow::NativeResize(int32_t aWidth, int32_t aHeight, bool aRepaint)
1771 LOG(("nsWindow::NativeResize [%p] %d %d\n", (void *)this,
1772 aWidth, aHeight));
1774 mNeedsResize = false;
1776 mWidget->resize(aWidth, aHeight);
1778 if (aRepaint) {
1779 mWidget->renderLater();
1783 void
1784 nsWindow::NativeResize(int32_t aX, int32_t aY,
1785 int32_t aWidth, int32_t aHeight,
1786 bool aRepaint)
1788 LOG(("nsWindow::NativeResize [%p] %d %d %d %d\n", (void *)this,
1789 aX, aY, aWidth, aHeight));
1791 mNeedsResize = false;
1792 mNeedsMove = false;
1794 mWidget->setGeometry(aX, aY, aWidth, aHeight);
1796 if (aRepaint) {
1797 mWidget->renderLater();
1801 void
1802 nsWindow::NativeShow(bool aAction)
1804 if (aAction) {
1805 // On e10s, we never want the child process or plugin process
1806 // to go fullscreen because if we do the window because visible
1807 // do to disabled Qt-Xembed
1808 mWidget->show();
1809 // unset our flag now that our window has been shown
1810 mNeedsShow = false;
1812 else {
1813 mWidget->hide();
1817 NS_IMETHODIMP
1818 nsWindow::SetHasTransparentBackground(bool aTransparent)
1820 return NS_ERROR_NOT_IMPLEMENTED;
1823 NS_IMETHODIMP
1824 nsWindow::GetHasTransparentBackground(bool& aTransparent)
1826 aTransparent = mIsTransparent;
1827 return NS_OK;
1830 void *
1831 nsWindow::SetupPluginPort(void)
1833 NS_WARNING("Not implemented");
1834 return nullptr;
1837 nsresult
1838 nsWindow::SetWindowIconList(const nsTArray<nsCString> &aIconList)
1840 QIcon icon;
1842 for (uint32_t i = 0; i < aIconList.Length(); ++i) {
1843 const char *path = aIconList[i].get();
1844 LOG(("window [%p] Loading icon from %s\n", (void *)this, path));
1845 icon.addFile(path);
1848 mWidget->setIcon(icon);
1850 return NS_OK;
1853 void
1854 nsWindow::SetDefaultIcon(void)
1856 SetIcon(NS_LITERAL_STRING("default"));
1859 void nsWindow::QWidgetDestroyed()
1861 mWidget = nullptr;
1865 NS_IMETHODIMP
1866 nsWindow::HideWindowChrome(bool aShouldHide)
1868 if (!mWidget) {
1869 // Nothing to hide
1870 return NS_ERROR_FAILURE;
1873 // Sawfish, metacity, and presumably other window managers get
1874 // confused if we change the window decorations while the window
1875 // is visible.
1876 bool wasVisible = false;
1877 if (mWidget->isVisible()) {
1878 NativeShow(false);
1879 wasVisible = true;
1882 if (wasVisible) {
1883 NativeShow(true);
1886 return NS_OK;
1889 //////////////////////////////////////////////////////////////////////
1891 NS_IMETHODIMP_(bool)
1892 nsWindow::HasGLContext()
1894 return false;
1898 nsIWidget*
1899 nsWindow::GetParent(void)
1901 return mParent;
1904 float
1905 nsWindow::GetDPI()
1907 return qApp->primaryScreen()->logicalDotsPerInch();
1910 void
1911 nsWindow::OnDestroy(void)
1913 if (mOnDestroyCalled) {
1914 return;
1917 mOnDestroyCalled = true;
1919 // release references to children and device context
1920 nsBaseWidget::OnDestroy();
1922 // let go of our parent
1923 mParent = nullptr;
1925 nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
1926 NotifyWindowDestroyed();
1929 bool
1930 nsWindow::AreBoundsSane(void)
1932 if (mBounds.width > 0 && mBounds.height > 0) {
1933 return true;
1936 return false;
1939 void
1940 nsWindow::SetSoftwareKeyboardState(bool aOpen,
1941 const InputContextAction& aAction)
1943 if (aOpen) {
1944 NS_ENSURE_TRUE_VOID(mInputContext.mIMEState.mEnabled !=
1945 IMEState::DISABLED);
1947 // Ensure that opening the virtual keyboard is allowed for this specific
1948 // InputContext depending on the content.ime.strict.policy pref
1949 if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN &&
1950 Preferences::GetBool("content.ime.strict_policy", false) &&
1951 !aAction.ContentGotFocusByTrustedCause() &&
1952 !aAction.UserMightRequestOpenVKB()) {
1953 return;
1957 if (aOpen) {
1958 qApp->inputMethod()->show();
1959 } else {
1960 qApp->inputMethod()->hide();
1963 return;
1967 void
1968 nsWindow::ProcessMotionEvent()
1970 if (mMoveEvent.needDispatch) {
1971 WidgetMouseEvent event(true, NS_MOUSE_MOVE, this,
1972 WidgetMouseEvent::eReal);
1974 event.refPoint.x = nscoord(mMoveEvent.pos.x());
1975 event.refPoint.y = nscoord(mMoveEvent.pos.y());
1977 event.InitBasicModifiers(mMoveEvent.modifiers & Qt::ControlModifier,
1978 mMoveEvent.modifiers & Qt::AltModifier,
1979 mMoveEvent.modifiers & Qt::ShiftModifier,
1980 mMoveEvent.modifiers & Qt::MetaModifier);
1981 event.clickCount = 0;
1983 DispatchEvent(&event);
1984 mMoveEvent.needDispatch = false;
1987 mTimerStarted = false;