Bumping manifests a=b2g-bump
[gecko.git] / widget / qt / nsWindow.cpp
blob193d39e22befcf2bfd53767f361b3e9f32e6b273
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 "nsIRollupListener.h"
44 #include "nsWidgetsCID.h"
45 #include "nsQtKeyUtils.h"
46 #include "mozilla/Services.h"
47 #include "mozilla/Preferences.h"
48 #include "mozilla/Likely.h"
49 #include "mozilla/layers/LayersTypes.h"
50 #include "nsIWidgetListener.h"
51 #include "ClientLayerManager.h"
52 #include "BasicLayers.h"
54 #include "nsIStringBundle.h"
55 #include "nsGfxCIID.h"
57 #include "imgIContainer.h"
58 #include "nsGfxCIID.h"
59 #include "nsIInterfaceRequestorUtils.h"
60 #include "nsAutoPtr.h"
62 #include "gfxQtPlatform.h"
64 #include "nsIDOMWheelEvent.h"
66 #include "GLContext.h"
68 #ifdef MOZ_X11
69 #include "keysym2ucs.h"
70 #endif
72 #include "Layers.h"
73 #include "GLContextProvider.h"
75 using namespace mozilla;
76 using namespace mozilla::gl;
77 using namespace mozilla::widget;
78 using namespace mozilla::gfx;
79 using namespace mozilla::layers;
80 using mozilla::gl::GLContext;
82 #define kWindowPositionSlop 20
84 // Qt
85 static const int WHEEL_DELTA = 120;
86 static bool gGlobalsInitialized = false;
87 static bool sAltGrModifier = false;
89 static void find_first_visible_parent(QWindow* aItem, QWindow*& aVisibleItem);
90 static bool is_mouse_in_window (MozQWidget* aWindow, double aMouseX, double aMouseY);
92 nsWindow::nsWindow()
94 LOG(("%s [%p]\n", __PRETTY_FUNCTION__, (void *)this));
96 mIsTopLevel = false;
97 mIsDestroyed = false;
98 mIsShown = false;
99 mEnabled = true;
100 mWidget = nullptr;
101 mVisible = false;
102 mActivatePending = false;
103 mWindowType = eWindowType_child;
104 mSizeState = nsSizeMode_Normal;
105 mLastSizeMode = nsSizeMode_Normal;
106 mQCursor = Qt::ArrowCursor;
107 mNeedsResize = false;
108 mNeedsMove = false;
109 mListenForResizes = false;
110 mNeedsShow = false;
111 mTimerStarted = false;
112 mMoveEvent.needDispatch = false;
114 if (!gGlobalsInitialized) {
115 gfxPlatform::GetPlatform();
116 gGlobalsInitialized = true;
119 memset(mKeyDownFlags, 0, sizeof(mKeyDownFlags));
121 mIsTransparent = false;
123 mCursor = eCursor_standard;
126 nsWindow::~nsWindow()
128 LOG(("%s [%p]\n", __PRETTY_FUNCTION__, (void *)this));
130 Destroy();
133 nsresult
134 nsWindow::Create(nsIWidget *aParent,
135 nsNativeWidget aNativeParent,
136 const nsIntRect &aRect,
137 nsDeviceContext *aContext,
138 nsWidgetInitData *aInitData)
140 // only set the base parent if we're not going to be a dialog or a
141 // toplevel
142 nsIWidget *baseParent = aParent;
144 // initialize all the common bits of this class
145 BaseCreate(baseParent, aRect, aContext, aInitData);
147 mVisible = true;
149 // and do our common creation
150 mParent = (nsWindow *)aParent;
152 // save our bounds
153 mBounds = aRect;
155 // find native parent
156 MozQWidget *parent = nullptr;
158 if (aParent != nullptr) {
159 parent = static_cast<MozQWidget*>(aParent->GetNativeData(NS_NATIVE_WIDGET));
160 } else if (aNativeParent != nullptr) {
161 parent = static_cast<MozQWidget*>(aNativeParent);
162 if (parent && mParent == nullptr) {
163 mParent = parent->getReceiver();
167 LOG(("Create: nsWindow [%p] mWidget:[%p] parent:[%p], natPar:[%p] mParent:%p\n", (void *)this, (void*)mWidget, parent, aNativeParent, mParent));
169 // ok, create our QGraphicsWidget
170 mWidget = createQWidget(parent, aInitData);
172 if (!mWidget) {
173 return NS_ERROR_OUT_OF_MEMORY;
177 // resize so that everything is set to the right dimensions
178 Resize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, false);
180 // check if we should listen for resizes
181 mListenForResizes = (aNativeParent ||
182 (aInitData && aInitData->mListenForResizes));
184 return NS_OK;
187 MozQWidget*
188 nsWindow::createQWidget(MozQWidget* parent,
189 nsWidgetInitData* aInitData)
191 const char *windowName = nullptr;
192 Qt::WindowFlags flags = Qt::Widget;
194 // ok, create our windows
195 switch (mWindowType) {
196 case eWindowType_dialog:
197 windowName = "topLevelDialog";
198 flags = Qt::Dialog;
199 break;
200 case eWindowType_popup:
201 windowName = "topLevelPopup";
202 flags = Qt::Popup;
203 break;
204 case eWindowType_toplevel:
205 windowName = "topLevelWindow";
206 flags = Qt::Window;
207 break;
208 case eWindowType_invisible:
209 windowName = "topLevelInvisible";
210 break;
211 case eWindowType_child:
212 case eWindowType_plugin:
213 default: // sheet
214 windowName = "paintArea";
215 break;
218 MozQWidget* widget = new MozQWidget(this, parent);
219 if (!widget) {
220 return nullptr;
223 widget->setObjectName(QString(windowName));
224 if (mWindowType == eWindowType_invisible) {
225 #if (QT_VERSION >= QT_VERSION_CHECK(5, 1, 0))
226 widget->setVisibility(QWindow::Hidden);
227 #else
228 widget->hide();
229 #endif
231 if (mWindowType == eWindowType_dialog) {
232 widget->setModality(Qt::WindowModal);
235 widget->create();
237 // create a QGraphicsView if this is a new toplevel window
238 LOG(("nsWindow::%s [%p] Created Window: %s, widget:%p, par:%p\n", __FUNCTION__, (void *)this, windowName, widget, parent));
240 return widget;
243 NS_IMETHODIMP
244 nsWindow::Destroy(void)
246 if (mIsDestroyed || !mWidget) {
247 return NS_OK;
250 LOG(("nsWindow::Destroy [%p]\n", (void *)this));
251 mIsDestroyed = true;
253 /** Need to clean our LayerManager up while still alive */
254 if (mLayerManager) {
255 mLayerManager->Destroy();
257 mLayerManager = nullptr;
259 // It is safe to call DestroyeCompositor several times (here and
260 // in the parent class) since it will take effect only once.
261 // The reason we call it here is because on gtk platforms we need
262 // to destroy the compositor before we destroy the gdk window (which
263 // destroys the the gl context attached to it).
264 DestroyCompositor();
266 ClearCachedResources();
268 nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
269 if (rollupListener) {
270 nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
271 if (static_cast<nsIWidget *>(this) == rollupWidget) {
272 rollupListener->Rollup(0, false, nullptr, nullptr);
276 Show(false);
278 // walk the list of children and call destroy on them. Have to be
279 // careful, though -- calling destroy on a kid may actually remove
280 // it from our child list, losing its sibling links.
281 for (nsIWidget* kid = mFirstChild; kid; ) {
282 nsIWidget* next = kid->GetNextSibling();
283 kid->Destroy();
284 kid = next;
287 // Destroy thebes surface now. Badness can happen if we destroy
288 // the surface after its X Window.
289 if (mWidget) {
290 mWidget->dropReceiver();
292 // Call deleteLater instead of delete; Qt still needs the object
293 // to be valid even after sending it a Close event. We could
294 // also set WA_DeleteOnClose, but this gives us more control.
295 mWidget->deleteLater();
297 mWidget = nullptr;
299 OnDestroy();
301 return NS_OK;
304 NS_IMETHODIMP
305 nsWindow::Show(bool aState)
307 LOG(("nsWindow::Show [%p] state %d\n", (void *)this, aState));
308 if (aState == mIsShown) {
309 return NS_OK;
312 // Clear our cached resources when the window is hidden.
313 if (mIsShown && !aState) {
314 ClearCachedResources();
317 mIsShown = aState;
319 if ((aState && !AreBoundsSane()) || !mWidget) {
320 LOG(("\tbounds are insane or window hasn't been created yet\n"));
321 mNeedsShow = true;
322 return NS_OK;
325 if (aState) {
326 if (mNeedsMove) {
327 NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height,
328 false);
329 } else if (mNeedsResize) {
330 NativeResize(mBounds.width, mBounds.height, false);
333 else {
334 // If someone is hiding this widget, clear any needing show flag.
335 mNeedsShow = false;
338 NativeShow(aState);
340 return NS_OK;
343 bool
344 nsWindow::IsVisible() const
346 return mIsShown;
349 NS_IMETHODIMP
350 nsWindow::ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY)
352 if (!mWidget) {
353 return NS_ERROR_FAILURE;
356 int32_t screenWidth = qApp->primaryScreen()->size().width();
357 int32_t screenHeight = qApp->primaryScreen()->size().height();
359 if (aAllowSlop) {
360 if (*aX < (kWindowPositionSlop - mBounds.width))
361 *aX = kWindowPositionSlop - mBounds.width;
362 if (*aX > (screenWidth - kWindowPositionSlop))
363 *aX = screenWidth - kWindowPositionSlop;
364 if (*aY < (kWindowPositionSlop - mBounds.height))
365 *aY = kWindowPositionSlop - mBounds.height;
366 if (*aY > (screenHeight - kWindowPositionSlop))
367 *aY = screenHeight - kWindowPositionSlop;
368 } else {
369 if (*aX < 0)
370 *aX = 0;
371 if (*aX > (screenWidth - mBounds.width))
372 *aX = screenWidth - mBounds.width;
373 if (*aY < 0)
374 *aY = 0;
375 if (*aY > (screenHeight - mBounds.height))
376 *aY = screenHeight - mBounds.height;
379 return NS_OK;
382 NS_IMETHODIMP
383 nsWindow::Move(double aX, double aY)
385 LOG(("nsWindow::Move [%p] %f %f\n", (void *)this,
386 aX, aY));
388 int32_t x = NSToIntRound(aX);
389 int32_t y = NSToIntRound(aY);
391 if (mIsTopLevel) {
392 SetSizeMode(nsSizeMode_Normal);
395 if (x == mBounds.x && y == mBounds.y) {
396 return NS_OK;
399 mNeedsMove = false;
401 // update the bounds
402 QPoint pos(x, y);
403 if (mIsTopLevel) {
404 mWidget->setPosition(x, y);
406 else if (mWidget) {
407 // the position of the widget is set relative to the parent
408 // so we map the coordinates accordingly
409 pos = mWidget->mapToGlobal(pos);
410 mWidget->setPosition(pos);
413 mBounds.x = pos.x();
414 mBounds.y = pos.y();
416 NotifyRollupGeometryChange();
417 return NS_OK;
420 NS_IMETHODIMP
421 nsWindow::Resize(double aWidth, double aHeight, bool aRepaint)
423 mBounds.width = NSToIntRound(aWidth);
424 mBounds.height = NSToIntRound(aHeight);
426 if (!mWidget)
427 return NS_OK;
429 if (mIsShown) {
430 if (AreBoundsSane()) {
431 if (mIsTopLevel || mNeedsShow)
432 NativeResize(mBounds.x, mBounds.y,
433 mBounds.width, mBounds.height, aRepaint);
434 else
435 NativeResize(mBounds.width, mBounds.height, aRepaint);
437 // Does it need to be shown because it was previously insane?
438 if (mNeedsShow) {
439 NativeShow(true);
442 else {
443 // If someone has set this so that the needs show flag is false
444 // and it needs to be hidden, update the flag and hide the
445 // window. This flag will be cleared the next time someone
446 // hides the window or shows it. It also prevents us from
447 // calling NativeShow(false) excessively on the window which
448 // causes unneeded X traffic.
449 if (!mNeedsShow) {
450 mNeedsShow = true;
451 NativeShow(false);
455 else if (AreBoundsSane() && mListenForResizes) {
456 // For widgets that we listen for resizes for (widgets created
457 // with native parents) we apparently _always_ have to resize. I
458 // dunno why, but apparently we're lame like that.
459 NativeResize(mBounds.width, mBounds.height, aRepaint);
461 else {
462 mNeedsResize = true;
465 // synthesize a resize event if this isn't a toplevel
466 if (mIsTopLevel || mListenForResizes) {
467 nsEventStatus status;
468 DispatchResizeEvent(mBounds, status);
471 NotifyRollupGeometryChange();
472 return NS_OK;
475 NS_IMETHODIMP
476 nsWindow::Resize(double aX, double aY, double aWidth, double aHeight,
477 bool aRepaint)
479 mBounds.x = NSToIntRound(aX);
480 mBounds.y = NSToIntRound(aY);
481 mBounds.width = NSToIntRound(aWidth);
482 mBounds.height = NSToIntRound(aHeight);
484 mPlaced = true;
486 if (!mWidget) {
487 return NS_OK;
490 // Has this widget been set to visible?
491 if (mIsShown) {
492 // Are the bounds sane?
493 if (AreBoundsSane()) {
494 // Yep? Resize the window
495 NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height,
496 aRepaint);
497 // Does it need to be shown because it was previously insane?
498 if (mNeedsShow)
499 NativeShow(true);
501 else {
502 // If someone has set this so that the needs show flag is false
503 // and it needs to be hidden, update the flag and hide the
504 // window. This flag will be cleared the next time someone
505 // hides the window or shows it. It also prevents us from
506 // calling NativeShow(false) excessively on the window which
507 // causes unneeded X traffic.
508 if (!mNeedsShow) {
509 mNeedsShow = true;
510 NativeShow(false);
514 // If the widget hasn't been shown, mark the widget as needing to be
515 // resized before it is shown
516 else if (AreBoundsSane() && mListenForResizes) {
517 // For widgets that we listen for resizes for (widgets created
518 // with native parents) we apparently _always_ have to resize. I
519 // dunno why, but apparently we're lame like that.
520 NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height,
521 aRepaint);
523 else {
524 mNeedsResize = true;
525 mNeedsMove = true;
528 if (mIsTopLevel || mListenForResizes) {
529 // synthesize a resize event
530 nsEventStatus status;
531 DispatchResizeEvent(mBounds, status);
534 if (aRepaint) {
535 mWidget->renderLater();
538 NotifyRollupGeometryChange();
539 return NS_OK;
542 NS_IMETHODIMP
543 nsWindow::Enable(bool aState)
545 mEnabled = aState;
547 return NS_OK;
550 bool
551 nsWindow::IsEnabled() const
553 return mEnabled;
556 NS_IMETHODIMP
557 nsWindow::SetFocus(bool aRaise)
559 // Make sure that our owning widget has focus. If it doesn't try to
560 // grab it. Note that we don't set our focus flag in this case.
561 LOGFOCUS((" SetFocus [%p]\n", (void *)this));
563 if (!mWidget) {
564 return NS_ERROR_FAILURE;
567 if (mWidget->focusObject()) {
568 return NS_OK;
571 // Because QGraphicsItem cannot get the focus if they are
572 // invisible, we look up the chain, for the lowest visible
573 // parent and focus that one
574 QWindow* realFocusItem = nullptr;
575 find_first_visible_parent(mWidget, realFocusItem);
577 if (!realFocusItem || realFocusItem->focusObject()) {
578 return NS_OK;
581 if (aRaise && mWidget) {
582 // the raising has to happen on the view widget
583 mWidget->raise();
586 // XXXndeakin why is this here? It should dispatch only when the OS
587 // notifies us.
588 DispatchActivateEvent();
590 return NS_OK;
593 NS_IMETHODIMP
594 nsWindow::ConfigureChildren(const nsTArray<nsIWidget::Configuration>& aConfigurations)
596 for (uint32_t i = 0; i < aConfigurations.Length(); ++i) {
597 const Configuration& configuration = aConfigurations[i];
599 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
600 NS_ASSERTION(w->GetParent() == this,
601 "Configured widget is not a child");
603 if (w->mBounds.Size() != configuration.mBounds.Size()) {
604 w->Resize(configuration.mBounds.x, configuration.mBounds.y,
605 configuration.mBounds.width, configuration.mBounds.height,
606 true);
607 } else if (w->mBounds.TopLeft() != configuration.mBounds.TopLeft()) {
608 w->Move(configuration.mBounds.x, configuration.mBounds.y);
611 return NS_OK;
614 NS_IMETHODIMP
615 nsWindow::Invalidate(const nsIntRect &aRect)
617 LOGDRAW(("Invalidate (rect) [%p,%p]: %d %d %d %d\n", (void *)this,
618 (void*)mWidget,aRect.x, aRect.y, aRect.width, aRect.height));
620 if (!mWidget) {
621 return NS_OK;
624 mWidget->renderLater();
626 return NS_OK;
629 nsIntPoint
630 nsWindow::WidgetToScreenOffset()
632 NS_ENSURE_TRUE(mWidget, nsIntPoint(0,0));
634 QPoint origin(0, 0);
635 origin = mWidget->mapToGlobal(origin);
637 return nsIntPoint(origin.x(), origin.y());
640 void*
641 nsWindow::GetNativeData(uint32_t aDataType)
643 switch (aDataType) {
644 case NS_NATIVE_WINDOW:
645 case NS_NATIVE_WIDGET: {
646 return mWidget;
648 case NS_NATIVE_SHAREABLE_WINDOW: {
649 return mWidget ? (void*)mWidget->winId() : nullptr;
651 case NS_NATIVE_DISPLAY: {
652 #ifdef MOZ_X11
653 return gfxQtPlatform::GetXDisplay(mWidget);
654 #endif
655 break;
657 case NS_NATIVE_PLUGIN_PORT:
658 case NS_NATIVE_GRAPHIC:
659 case NS_NATIVE_SHELLWIDGET: {
660 break;
662 default:
663 NS_WARNING("nsWindow::GetNativeData called with bad value");
664 return nullptr;
666 LOG(("nsWindow::%s [%p] aDataType:%i\n", __FUNCTION__, (void *)this, aDataType));
667 return nullptr;
670 NS_IMETHODIMP
671 nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
673 #ifdef DEBUG
674 debug_DumpEvent(stdout, aEvent->widget, aEvent,
675 nsAutoCString("something"), 0);
676 #endif
678 aStatus = nsEventStatus_eIgnore;
680 // send it to the standard callback
681 if (mWidgetListener) {
682 aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
685 return NS_OK;
688 NS_IMETHODIMP_(void)
689 nsWindow::SetInputContext(const InputContext& aContext,
690 const InputContextAction& aAction)
692 NS_ENSURE_TRUE_VOID(mWidget);
694 // SetSoftwareKeyboardState uses mInputContext,
695 // so, before calling that, record aContext in mInputContext.
696 mInputContext = aContext;
698 switch (mInputContext.mIMEState.mEnabled) {
699 case IMEState::ENABLED:
700 case IMEState::PASSWORD:
701 case IMEState::PLUGIN:
702 SetSoftwareKeyboardState(true, aAction);
703 break;
704 default:
705 SetSoftwareKeyboardState(false, aAction);
706 break;
710 NS_IMETHODIMP_(InputContext)
711 nsWindow::GetInputContext()
713 mInputContext.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
714 // Our qt widget looks like using only one context per process.
715 // However, it's better to set the context's pointer.
716 mInputContext.mNativeIMEContext = qApp->inputMethod();
718 return mInputContext;
721 NS_IMETHODIMP
722 nsWindow::ReparentNativeWidget(nsIWidget *aNewParent)
724 NS_PRECONDITION(aNewParent, "");
726 MozQWidget* newParent = static_cast<MozQWidget*>(aNewParent->GetNativeData(NS_NATIVE_WINDOW));
727 NS_ASSERTION(newParent, "Parent widget has a null native window handle");
728 if (mWidget) {
729 mWidget->setParent(newParent);
731 return NS_OK;
734 NS_IMETHODIMP
735 nsWindow::MakeFullScreen(bool aFullScreen, nsIScreen*)
737 NS_ENSURE_TRUE(mWidget, NS_ERROR_FAILURE);
739 if (aFullScreen) {
740 if (mSizeMode != nsSizeMode_Fullscreen) {
741 mLastSizeMode = mSizeMode;
744 mSizeMode = nsSizeMode_Fullscreen;
745 mWidget->showFullScreen();
747 else {
748 mSizeMode = mLastSizeMode;
750 switch (mSizeMode) {
751 case nsSizeMode_Maximized:
752 mWidget->showMaximized();
753 break;
754 case nsSizeMode_Minimized:
755 mWidget->showMinimized();
756 break;
757 case nsSizeMode_Normal:
758 mWidget->showNormal();
759 break;
760 default:
761 mWidget->showNormal();
762 break;
766 NS_ASSERTION(mLastSizeMode != nsSizeMode_Fullscreen,
767 "mLastSizeMode should never be fullscreen");
768 return nsBaseWidget::MakeFullScreen(aFullScreen);
771 LayerManager*
772 nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager,
773 LayersBackend aBackendHint,
774 LayerManagerPersistence aPersistence,
775 bool* aAllowRetaining)
777 if (!mLayerManager && eTransparencyTransparent == GetTransparencyMode()) {
778 mLayerManager = CreateBasicLayerManager();
781 return nsBaseWidget::GetLayerManager(aShadowManager, aBackendHint,
782 aPersistence, aAllowRetaining);
785 void
786 nsWindow::UserActivity()
788 if (!mIdleService) {
789 mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
792 if (mIdleService) {
793 mIdleService->ResetIdleTimeOut(0);
797 uint32_t
798 nsWindow::GetGLFrameBufferFormat()
800 if (mLayerManager &&
801 mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_OPENGL) {
802 return LOCAL_GL_RGB;
804 return LOCAL_GL_NONE;
807 TemporaryRef<DrawTarget>
808 nsWindow::StartRemoteDrawing()
810 if (!mWidget) {
811 return nullptr;
814 #ifdef MOZ_X11
815 Display* dpy = gfxQtPlatform::GetXDisplay(mWidget);
816 Screen* screen = DefaultScreenOfDisplay(dpy);
817 Visual* defaultVisual = DefaultVisualOfScreen(screen);
818 gfxASurface* surf = new gfxXlibSurface(dpy, mWidget->winId(), defaultVisual,
819 gfxIntSize(mWidget->width(),
820 mWidget->height()));
822 IntSize size(surf->GetSize().width, surf->GetSize().height);
823 if (size.width <= 0 || size.height <= 0) {
824 return nullptr;
827 return gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf, size);
828 #else
829 return nullptr;
830 #endif
833 NS_IMETHODIMP
834 nsWindow::SetCursor(nsCursor aCursor)
836 if (mCursor == aCursor && !mUpdateCursor) {
837 return NS_OK;
839 mUpdateCursor = false;
840 mCursor = aCursor;
841 if (mWidget) {
842 mWidget->SetCursor(mCursor);
844 return NS_OK;
847 NS_IMETHODIMP
848 nsWindow::SetTitle(const nsAString& aTitle)
850 QString qStr(QString::fromUtf16((const ushort*)aTitle.BeginReading(), aTitle.Length()));
852 mWidget->setTitle(qStr);
854 return NS_OK;
857 // EVENTS
859 void
860 nsWindow::OnPaint()
862 LOGDRAW(("nsWindow::%s [%p]\n", __FUNCTION__, (void *)this));
863 nsIWidgetListener* listener =
864 mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
865 if (!listener) {
866 return;
869 listener->WillPaintWindow(this);
871 switch (GetLayerManager()->GetBackendType()) {
872 case mozilla::layers::LayersBackend::LAYERS_CLIENT: {
873 nsIntRegion region(nsIntRect(0, 0, mWidget->width(), mWidget->height()));
874 listener->PaintWindow(this, region);
875 break;
877 default:
878 NS_ERROR("Invalid layer manager");
881 listener->DidPaintWindow();
884 nsEventStatus
885 nsWindow::moveEvent(QMoveEvent* aEvent)
887 LOG(("configure event [%p] %d %d\n", (void *)this,
888 aEvent->pos().x(), aEvent->pos().y()));
890 // can we shortcut?
891 if (!mWidget || !mWidgetListener)
892 return nsEventStatus_eIgnore;
894 if ((mBounds.x == aEvent->pos().x() &&
895 mBounds.y == aEvent->pos().y()))
897 return nsEventStatus_eIgnore;
900 NotifyWindowMoved(aEvent->pos().x(), aEvent->pos().y());
901 return nsEventStatus_eConsumeNoDefault;
904 nsEventStatus
905 nsWindow::resizeEvent(QResizeEvent* aEvent)
907 nsIntRect rect;
909 // Generate XPFE resize event
910 GetBounds(rect);
912 rect.width = aEvent->size().width();
913 rect.height = aEvent->size().height();
915 mBounds.width = rect.width;
916 mBounds.height = rect.height;
918 nsEventStatus status;
919 DispatchResizeEvent(rect, status);
920 return status;
923 nsEventStatus
924 nsWindow::mouseMoveEvent(QMouseEvent* aEvent)
926 UserActivity();
928 mMoveEvent.pos = aEvent->pos();
929 mMoveEvent.modifiers = aEvent->modifiers();
930 mMoveEvent.needDispatch = true;
931 DispatchMotionToMainThread();
933 return nsEventStatus_eIgnore;
936 static void
937 InitMouseEvent(WidgetMouseEvent& aMouseEvent, QMouseEvent* aEvent,
938 int aClickCount)
940 aMouseEvent.refPoint.x = nscoord(aEvent->pos().x());
941 aMouseEvent.refPoint.y = nscoord(aEvent->pos().y());
943 aMouseEvent.InitBasicModifiers(aEvent->modifiers() & Qt::ControlModifier,
944 aEvent->modifiers() & Qt::AltModifier,
945 aEvent->modifiers() & Qt::ShiftModifier,
946 aEvent->modifiers() & Qt::MetaModifier);
947 aMouseEvent.clickCount = aClickCount;
949 switch (aEvent->button()) {
950 case Qt::LeftButton:
951 aMouseEvent.button = WidgetMouseEvent::eLeftButton;
952 break;
953 case Qt::RightButton:
954 aMouseEvent.button = WidgetMouseEvent::eRightButton;
955 break;
956 case Qt::MiddleButton:
957 aMouseEvent.button = WidgetMouseEvent::eMiddleButton;
958 break;
959 default:
960 break;
964 static bool
965 IsAcceptedButton(Qt::MouseButton button)
967 switch (button) {
968 case Qt::LeftButton:
969 case Qt::RightButton:
970 case Qt::MiddleButton:
971 return true;
972 default:
973 return false;
977 nsEventStatus
978 nsWindow::mousePressEvent(QMouseEvent* aEvent)
980 // The user has done something.
981 UserActivity();
983 QPoint pos = aEvent->pos();
985 // we check against the widgets geometry, so use parent coordinates
986 // for the check
987 if (mWidget)
988 pos = mWidget->mapToGlobal(pos);
990 if (CheckForRollup(pos.x(), pos.y(), false))
991 return nsEventStatus_eIgnore;
993 if (!IsAcceptedButton(aEvent->button())) {
994 if (aEvent->button() == Qt::BackButton)
995 return DispatchCommandEvent(nsGkAtoms::Back);
996 if (aEvent->button() == Qt::ForwardButton)
997 return DispatchCommandEvent(nsGkAtoms::Forward);
998 return nsEventStatus_eIgnore;
1001 WidgetMouseEvent event(true, NS_MOUSE_BUTTON_DOWN, this,
1002 WidgetMouseEvent::eReal);
1003 InitMouseEvent(event, aEvent, 1);
1004 nsEventStatus status = DispatchEvent(&event);
1006 // Right click on linux should also pop up a context menu.
1007 if (event.button == WidgetMouseEvent::eRightButton &&
1008 MOZ_LIKELY(!mIsDestroyed)) {
1009 WidgetMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this,
1010 WidgetMouseEvent::eReal);
1011 InitMouseEvent(contextMenuEvent, aEvent, 1);
1012 DispatchEvent(&contextMenuEvent, status);
1015 return status;
1018 nsEventStatus
1019 nsWindow::mouseReleaseEvent(QMouseEvent* aEvent)
1021 // The user has done something.
1022 UserActivity();
1024 if (!IsAcceptedButton(aEvent->button()))
1025 return nsEventStatus_eIgnore;
1027 WidgetMouseEvent event(true, NS_MOUSE_BUTTON_UP, this,
1028 WidgetMouseEvent::eReal);
1029 InitMouseEvent(event, aEvent, 1);
1030 return DispatchEvent(&event);
1033 nsEventStatus
1034 nsWindow::mouseDoubleClickEvent(QMouseEvent* aEvent)
1036 // The user has done something.
1037 UserActivity();
1039 if (!IsAcceptedButton(aEvent->button()))
1040 return nsEventStatus_eIgnore;
1042 WidgetMouseEvent event(true, NS_MOUSE_DOUBLECLICK, this,
1043 WidgetMouseEvent::eReal);
1044 InitMouseEvent(event, aEvent, 2);
1045 return DispatchEvent(&event);
1048 nsEventStatus
1049 nsWindow::focusInEvent(QFocusEvent* aEvent)
1051 LOGFOCUS(("OnFocusInEvent [%p]\n", (void *)this));
1053 if (!mWidget) {
1054 return nsEventStatus_eIgnore;
1057 DispatchActivateEventOnTopLevelWindow();
1059 LOGFOCUS(("Events sent from focus in event [%p]\n", (void *)this));
1060 return nsEventStatus_eIgnore;
1063 nsEventStatus
1064 nsWindow::focusOutEvent(QFocusEvent* aEvent)
1066 LOGFOCUS(("OnFocusOutEvent [%p]\n", (void *)this));
1068 if (!mWidget) {
1069 return nsEventStatus_eIgnore;
1072 DispatchDeactivateEventOnTopLevelWindow();
1074 LOGFOCUS(("Done with container focus out [%p]\n", (void *)this));
1075 return nsEventStatus_eIgnore;
1078 static bool
1079 IsContextMenuKeyEvent(const QKeyEvent* aQEvent)
1081 if (aQEvent->modifiers() & (Qt::ControlModifier |
1082 Qt::AltModifier |
1083 Qt::MetaModifier)) {
1084 return false;
1087 bool isShift = aQEvent->modifiers() & Qt::ShiftModifier;
1088 uint32_t keyCode = QtKeyCodeToDOMKeyCode(aQEvent->key());
1089 return (keyCode == NS_VK_F10 && isShift) ||
1090 (keyCode == NS_VK_CONTEXT_MENU && !isShift);
1093 static void
1094 InitKeyEvent(WidgetKeyboardEvent& aEvent, QKeyEvent* aQEvent)
1096 aEvent.InitBasicModifiers(aQEvent->modifiers() & Qt::ControlModifier,
1097 aQEvent->modifiers() & Qt::AltModifier,
1098 aQEvent->modifiers() & Qt::ShiftModifier,
1099 aQEvent->modifiers() & Qt::MetaModifier);
1101 aEvent.mIsRepeat =
1102 (aEvent.message == NS_KEY_DOWN || aEvent.message == NS_KEY_PRESS) &&
1103 aQEvent->isAutoRepeat();
1104 aEvent.time = 0;
1106 if (sAltGrModifier) {
1107 aEvent.modifiers |= (MODIFIER_CONTROL | MODIFIER_ALT);
1110 if (aQEvent->text().length() && aQEvent->text()[0].isPrint()) {
1111 aEvent.charCode = (int32_t) aQEvent->text()[0].unicode();
1112 aEvent.keyCode = 0;
1113 aEvent.mKeyNameIndex = KEY_NAME_INDEX_PrintableKey;
1114 } else {
1115 aEvent.charCode = 0;
1116 aEvent.keyCode = QtKeyCodeToDOMKeyCode(aQEvent->key());
1117 aEvent.mKeyNameIndex = QtKeyCodeToDOMKeyNameIndex(aQEvent->key());
1120 aEvent.mCodeNameIndex = ScanCodeToDOMCodeNameIndex(aQEvent->nativeScanCode());
1122 // The transformations above and in qt for the keyval are not invertible
1123 // so link to the QKeyEvent (which will vanish soon after return from the
1124 // event callback) to give plugins access to hardware_keycode and state.
1125 // (An XEvent would be nice but the QKeyEvent is good enough.)
1126 aEvent.mPluginEvent.Copy(*aQEvent);
1129 nsEventStatus
1130 nsWindow::keyPressEvent(QKeyEvent* aEvent)
1132 LOGFOCUS(("OnKeyPressEvent [%p]\n", (void *)this));
1134 // The user has done something.
1135 UserActivity();
1137 if (aEvent->key() == Qt::Key_AltGr) {
1138 sAltGrModifier = true;
1141 // Before we dispatch a key, check if it's the context menu key.
1142 // If so, send a context menu key event instead.
1143 if (IsContextMenuKeyEvent(aEvent)) {
1144 WidgetMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this,
1145 WidgetMouseEvent::eReal,
1146 WidgetMouseEvent::eContextMenuKey);
1147 return DispatchEvent(&contextMenuEvent);
1150 //:TODO: fix shortcuts hebrew for non X11,
1151 //see Bug 562195##51
1153 uint32_t domKeyCode = QtKeyCodeToDOMKeyCode(aEvent->key());
1155 if (!aEvent->isAutoRepeat() && !IsKeyDown(domKeyCode)) {
1156 SetKeyDownFlag(domKeyCode);
1158 WidgetKeyboardEvent downEvent(true, NS_KEY_DOWN, this);
1159 InitKeyEvent(downEvent, aEvent);
1161 nsEventStatus status = DispatchEvent(&downEvent);
1163 // DispatchEvent can Destroy us (bug 378273)
1164 if (MOZ_UNLIKELY(mIsDestroyed)) {
1165 qWarning() << "Returning[" << __LINE__ << "]: " << "Window destroyed";
1166 return status;
1169 // If prevent default on keydown, don't dispatch keypress event
1170 if (status == nsEventStatus_eConsumeNoDefault) {
1171 return nsEventStatus_eConsumeNoDefault;
1175 // Don't pass modifiers as NS_KEY_PRESS events.
1176 // Instead of selectively excluding some keys from NS_KEY_PRESS events,
1177 // we instead selectively include (as per MSDN spec
1178 // ( http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keypress%28VS.71%29.aspx );
1179 // no official spec covers KeyPress events).
1180 if (aEvent->key() == Qt::Key_Shift ||
1181 aEvent->key() == Qt::Key_Control ||
1182 aEvent->key() == Qt::Key_Meta ||
1183 aEvent->key() == Qt::Key_Alt ||
1184 aEvent->key() == Qt::Key_AltGr) {
1185 return nsEventStatus_eIgnore;
1188 // Look for specialized app-command keys
1189 switch (aEvent->key()) {
1190 case Qt::Key_Back:
1191 return DispatchCommandEvent(nsGkAtoms::Back);
1192 case Qt::Key_Forward:
1193 return DispatchCommandEvent(nsGkAtoms::Forward);
1194 case Qt::Key_Refresh:
1195 return DispatchCommandEvent(nsGkAtoms::Reload);
1196 case Qt::Key_Stop:
1197 return DispatchCommandEvent(nsGkAtoms::Stop);
1198 case Qt::Key_Search:
1199 return DispatchCommandEvent(nsGkAtoms::Search);
1200 case Qt::Key_Favorites:
1201 return DispatchCommandEvent(nsGkAtoms::Bookmarks);
1202 case Qt::Key_HomePage:
1203 return DispatchCommandEvent(nsGkAtoms::Home);
1204 case Qt::Key_Copy:
1205 case Qt::Key_F16: // F16, F20, F18, F14 are old keysyms for Copy Cut Paste Undo
1206 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_COPY);
1207 case Qt::Key_Cut:
1208 case Qt::Key_F20:
1209 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_CUT);
1210 case Qt::Key_Paste:
1211 case Qt::Key_F18:
1212 case Qt::Key_F9:
1213 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_PASTE);
1214 case Qt::Key_F14:
1215 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_UNDO);
1218 // Qt::Key_Redo and Qt::Key_Undo are not available yet.
1219 if (aEvent->nativeVirtualKey() == 0xff66) {
1220 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_REDO);
1222 if (aEvent->nativeVirtualKey() == 0xff65) {
1223 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_UNDO);
1226 WidgetKeyboardEvent event(true, NS_KEY_PRESS, this);
1227 InitKeyEvent(event, aEvent);
1228 // Seend the key press event
1229 return DispatchEvent(&event);
1232 nsEventStatus
1233 nsWindow::keyReleaseEvent(QKeyEvent* aEvent)
1235 LOGFOCUS(("OnKeyReleaseEvent [%p]\n", (void *)this));
1237 // The user has done something.
1238 UserActivity();
1240 if (IsContextMenuKeyEvent(aEvent)) {
1241 // er, what do we do here? DoDefault or NoDefault?
1242 return nsEventStatus_eConsumeDoDefault;
1245 // send the key event as a key up event
1246 WidgetKeyboardEvent event(true, NS_KEY_UP, this);
1247 InitKeyEvent(event, aEvent);
1249 if (aEvent->key() == Qt::Key_AltGr) {
1250 sAltGrModifier = false;
1253 // unset the key down flag
1254 ClearKeyDownFlag(event.keyCode);
1256 return DispatchEvent(&event);
1259 nsEventStatus
1260 nsWindow::wheelEvent(QWheelEvent* aEvent)
1262 // check to see if we should rollup
1263 WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, this);
1264 wheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE;
1266 // negative values for aEvent->delta indicate downward scrolling;
1267 // this is opposite Gecko usage.
1268 // TODO: Store the unused delta values due to fraction round and add it
1269 // to next event. The stored values should be reset by other
1270 // direction scroll event.
1271 int32_t delta = (int)(aEvent->delta() / WHEEL_DELTA) * -3;
1273 switch (aEvent->orientation()) {
1274 case Qt::Vertical:
1275 wheelEvent.deltaY = wheelEvent.lineOrPageDeltaY = delta;
1276 break;
1277 case Qt::Horizontal:
1278 wheelEvent.deltaX = wheelEvent.lineOrPageDeltaX = delta;
1279 break;
1280 default:
1281 Q_ASSERT(0);
1282 break;
1285 wheelEvent.refPoint.x = nscoord(aEvent->pos().x());
1286 wheelEvent.refPoint.y = nscoord(aEvent->pos().y());
1288 wheelEvent.InitBasicModifiers(aEvent->modifiers() & Qt::ControlModifier,
1289 aEvent->modifiers() & Qt::AltModifier,
1290 aEvent->modifiers() & Qt::ShiftModifier,
1291 aEvent->modifiers() & Qt::MetaModifier);
1292 wheelEvent.time = 0;
1294 return DispatchEvent(&wheelEvent);
1297 nsEventStatus
1298 nsWindow::showEvent(QShowEvent *)
1300 LOG(("%s [%p]\n", __PRETTY_FUNCTION__,(void *)this));
1301 mVisible = true;
1302 return nsEventStatus_eConsumeDoDefault;
1305 nsEventStatus
1306 nsWindow::hideEvent(QHideEvent *)
1308 LOG(("%s [%p]\n", __PRETTY_FUNCTION__,(void *)this));
1309 mVisible = false;
1310 return nsEventStatus_eConsumeDoDefault;
1313 nsEventStatus nsWindow::touchEvent(QTouchEvent* aEvent)
1315 return nsEventStatus_eIgnore;
1318 nsEventStatus
1319 nsWindow::tabletEvent(QTabletEvent* aEvent)
1321 LOGFOCUS(("nsWindow::%s [%p]\n", __FUNCTION__, (void *)this));
1322 return nsEventStatus_eIgnore;
1325 // Helpers
1327 nsEventStatus
1328 nsWindow::DispatchEvent(WidgetGUIEvent* aEvent)
1330 nsEventStatus status;
1331 DispatchEvent(aEvent, status);
1332 return status;
1335 void
1336 nsWindow::DispatchActivateEvent(void)
1338 if (mWidgetListener) {
1339 mWidgetListener->WindowActivated();
1343 void
1344 nsWindow::DispatchDeactivateEvent(void)
1346 if (mWidgetListener) {
1347 mWidgetListener->WindowDeactivated();
1351 void
1352 nsWindow::DispatchActivateEventOnTopLevelWindow(void)
1354 nsWindow* topLevelWindow = static_cast<nsWindow*>(GetTopLevelWidget());
1355 if (topLevelWindow != nullptr) {
1356 topLevelWindow->DispatchActivateEvent();
1360 void
1361 nsWindow::DispatchDeactivateEventOnTopLevelWindow(void)
1363 nsWindow* topLevelWindow = static_cast<nsWindow*>(GetTopLevelWidget());
1364 if (topLevelWindow != nullptr) {
1365 topLevelWindow->DispatchDeactivateEvent();
1369 void
1370 nsWindow::DispatchResizeEvent(nsIntRect &aRect, nsEventStatus &aStatus)
1372 aStatus = nsEventStatus_eIgnore;
1373 if (mWidgetListener &&
1374 mWidgetListener->WindowResized(this, aRect.width, aRect.height)) {
1375 aStatus = nsEventStatus_eConsumeNoDefault;
1379 ///////////////////////////////////// OLD GECKO ECENTS need to Sort ///////////////////
1381 NS_IMPL_ISUPPORTS_INHERITED(nsWindow, nsBaseWidget, nsISupportsWeakReference)
1385 void
1386 nsWindow::ClearCachedResources()
1388 if (mLayerManager &&
1389 mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_BASIC) {
1390 mLayerManager->ClearCachedResources();
1392 for (nsIWidget* kid = mFirstChild; kid; ) {
1393 nsIWidget* next = kid->GetNextSibling();
1394 static_cast<nsWindow*>(kid)->ClearCachedResources();
1395 kid = next;
1399 NS_IMETHODIMP
1400 nsWindow::SetParent(nsIWidget *aNewParent)
1402 NS_ENSURE_ARG_POINTER(aNewParent);
1404 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
1405 nsIWidget* parent = GetParent();
1406 if (parent) {
1407 parent->RemoveChild(this);
1409 ReparentNativeWidget(aNewParent);
1410 aNewParent->AddChild(this);
1411 return NS_OK;
1414 NS_IMETHODIMP
1415 nsWindow::SetModal(bool aModal)
1417 LOG(("nsWindow::SetModal [%p] %d, widget[%p]\n", (void *)this, aModal, mWidget));
1418 if (mWidget) {
1419 mWidget->setModality(aModal ? Qt::WindowModal : Qt::NonModal);
1422 return NS_OK;
1426 NS_IMETHODIMP
1427 nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
1428 nsIWidget *aWidget,
1429 bool aActivate)
1431 return NS_ERROR_NOT_IMPLEMENTED;
1434 NS_IMETHODIMP
1435 nsWindow::SetSizeMode(int32_t aMode)
1437 nsresult rv;
1439 LOG(("nsWindow::SetSizeMode [%p] %d\n", (void *)this, aMode));
1440 if (aMode != nsSizeMode_Minimized) {
1441 mWidget->requestActivate();
1444 // Save the requested state.
1445 rv = nsBaseWidget::SetSizeMode(aMode);
1447 // return if there's no shell or our current state is the same as
1448 // the mode we were just set to.
1449 if (!mWidget || mSizeState == mSizeMode) {
1450 return rv;
1453 switch (aMode) {
1454 case nsSizeMode_Maximized:
1455 mWidget->showMaximized();
1456 break;
1457 case nsSizeMode_Minimized:
1458 mWidget->showMinimized();
1459 break;
1460 case nsSizeMode_Fullscreen:
1461 mWidget->showFullScreen();
1462 break;
1464 default:
1465 // nsSizeMode_Normal, really.
1466 mWidget->show();
1467 break;
1470 mSizeState = mSizeMode;
1472 return rv;
1475 // Helper function to recursively find the first parent item that
1476 // is still visible (QGraphicsItem can be hidden even if they are
1477 // set to visible if one of their ancestors is invisible)
1478 /* static */
1479 void find_first_visible_parent(QWindow* aItem, QWindow*& aVisibleItem)
1481 NS_ENSURE_TRUE_VOID(aItem);
1483 aVisibleItem = nullptr;
1484 QWindow* parItem = nullptr;
1485 while (!aVisibleItem) {
1486 if (aItem->isVisible()) {
1487 aVisibleItem = aItem;
1489 else {
1490 parItem = aItem->parent();
1491 if (parItem) {
1492 aItem = parItem;
1494 else {
1495 aItem->setVisible(true);
1496 aVisibleItem = aItem;
1502 NS_IMETHODIMP
1503 nsWindow::GetScreenBounds(nsIntRect &aRect)
1505 aRect = nsIntRect(nsIntPoint(0, 0), mBounds.Size());
1506 if (mIsTopLevel) {
1507 QPoint pos = mWidget->position();
1508 aRect.MoveTo(pos.x(), pos.y());
1510 else {
1511 aRect.MoveTo(WidgetToScreenOffset());
1513 LOG(("GetScreenBounds %d %d | %d %d | %d %d\n",
1514 aRect.x, aRect.y,
1515 mBounds.width, mBounds.height,
1516 aRect.width, aRect.height));
1517 return NS_OK;
1520 NS_IMETHODIMP
1521 nsWindow::SetIcon(const nsAString& aIconSpec)
1523 if (!mWidget)
1524 return NS_OK;
1526 nsCOMPtr<nsIFile> iconFile;
1527 nsAutoCString path;
1528 nsTArray<nsCString> iconList;
1530 // Look for icons with the following suffixes appended to the base name.
1531 // The last two entries (for the old XPM format) will be ignored unless
1532 // no icons are found using the other suffixes. XPM icons are depricated.
1534 const char extensions[6][7] = { ".png", "16.png", "32.png", "48.png",
1535 ".xpm", "16.xpm" };
1537 for (uint32_t i = 0; i < ArrayLength(extensions); i++) {
1538 // Don't bother looking for XPM versions if we found a PNG.
1539 if (i == ArrayLength(extensions) - 2 && iconList.Length())
1540 break;
1542 nsAutoString extension;
1543 extension.AppendASCII(extensions[i]);
1545 ResolveIconName(aIconSpec, extension, getter_AddRefs(iconFile));
1546 if (iconFile) {
1547 iconFile->GetNativePath(path);
1548 iconList.AppendElement(path);
1552 // leave the default icon intact if no matching icons were found
1553 if (iconList.Length() == 0)
1554 return NS_OK;
1556 return SetWindowIconList(iconList);
1559 NS_IMETHODIMP
1560 nsWindow::CaptureMouse(bool aCapture)
1562 LOG(("CaptureMouse %p\n", (void *)this));
1564 if (!mWidget)
1565 return NS_OK;
1567 mWidget->setMouseGrabEnabled(aCapture);
1569 return NS_OK;
1572 bool
1573 nsWindow::CheckForRollup(double aMouseX, double aMouseY,
1574 bool aIsWheel)
1576 nsIRollupListener* rollupListener = GetActiveRollupListener();
1577 nsCOMPtr<nsIWidget> rollupWidget;
1578 if (rollupListener) {
1579 rollupWidget = rollupListener->GetRollupWidget();
1581 if (!rollupWidget) {
1582 nsBaseWidget::gRollupListener = nullptr;
1583 return false;
1586 bool retVal = false;
1587 MozQWidget *currentPopup =
1588 (MozQWidget *)rollupWidget->GetNativeData(NS_NATIVE_WINDOW);
1589 if (!is_mouse_in_window(currentPopup, aMouseX, aMouseY)) {
1590 bool rollup = true;
1591 if (aIsWheel) {
1592 rollup = rollupListener->ShouldRollupOnMouseWheelEvent();
1593 retVal = true;
1595 // if we're dealing with menus, we probably have submenus and
1596 // we don't want to rollup if the clickis in a parent menu of
1597 // the current submenu
1598 uint32_t popupsToRollup = UINT32_MAX;
1599 if (rollupListener) {
1600 nsAutoTArray<nsIWidget*, 5> widgetChain;
1601 uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain);
1602 for (uint32_t i=0; i<widgetChain.Length(); ++i) {
1603 nsIWidget* widget = widgetChain[i];
1604 MozQWidget* currWindow =
1605 (MozQWidget*) widget->GetNativeData(NS_NATIVE_WINDOW);
1606 if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) {
1607 if (i < sameTypeCount) {
1608 rollup = false;
1610 else {
1611 popupsToRollup = sameTypeCount;
1613 break;
1615 } // foreach parent menu widget
1616 } // if rollup listener knows about menus
1618 // if we've determined that we should still rollup, do it.
1619 if (rollup) {
1620 nsIntPoint pos(aMouseX, aMouseY);
1621 retVal = rollupListener->Rollup(popupsToRollup, true, &pos, nullptr);
1625 return retVal;
1628 /* static */
1629 bool
1630 is_mouse_in_window (MozQWidget* aWindow, double aMouseX, double aMouseY)
1632 return aWindow->geometry().contains(aMouseX, aMouseY);
1635 NS_IMETHODIMP
1636 nsWindow::GetAttention(int32_t aCycleCount)
1638 LOG(("nsWindow::GetAttention [%p]\n", (void *)this));
1639 return NS_ERROR_NOT_IMPLEMENTED;
1644 nsEventStatus
1645 nsWindow::OnCloseEvent(QCloseEvent *aEvent)
1647 if (!mWidgetListener)
1648 return nsEventStatus_eIgnore;
1649 mWidgetListener->RequestWindowClose(this);
1650 return nsEventStatus_eConsumeNoDefault;
1654 inline bool
1655 is_latin_shortcut_key(quint32 aKeyval)
1657 return ((Qt::Key_0 <= aKeyval && aKeyval <= Qt::Key_9) ||
1658 (Qt::Key_A <= aKeyval && aKeyval <= Qt::Key_Z));
1661 nsEventStatus
1662 nsWindow::DispatchCommandEvent(nsIAtom* aCommand)
1664 WidgetCommandEvent event(true, nsGkAtoms::onAppCommand, aCommand, this);
1666 nsEventStatus status;
1667 DispatchEvent(&event, status);
1669 return status;
1672 nsEventStatus
1673 nsWindow::DispatchContentCommandEvent(int32_t aMsg)
1675 WidgetContentCommandEvent event(true, aMsg, this);
1677 nsEventStatus status;
1678 DispatchEvent(&event, status);
1680 return status;
1684 static void
1685 GetBrandName(nsXPIDLString& brandName)
1687 nsCOMPtr<nsIStringBundleService> bundleService =
1688 mozilla::services::GetStringBundleService();
1690 nsCOMPtr<nsIStringBundle> bundle;
1691 if (bundleService) {
1692 bundleService->CreateBundle(
1693 "chrome://branding/locale/brand.properties",
1694 getter_AddRefs(bundle));
1697 if (bundle) {
1698 bundle->GetStringFromName(
1699 MOZ_UTF16("brandShortName"),
1700 getter_Copies(brandName));
1703 if (brandName.IsEmpty()) {
1704 brandName.AssignLiteral(MOZ_UTF16("Mozilla"));
1708 NS_IMETHODIMP
1709 nsWindow::SetWindowClass(const nsAString &xulWinType)
1711 if (!mWidget) {
1712 return NS_ERROR_FAILURE;
1715 nsXPIDLString brandName;
1716 GetBrandName(brandName);
1718 #ifdef MOZ_X11
1719 XClassHint *class_hint = XAllocClassHint();
1720 if (!class_hint) {
1721 return NS_ERROR_OUT_OF_MEMORY;
1723 const char *role = nullptr;
1724 class_hint->res_name = ToNewCString(xulWinType);
1725 if (!class_hint->res_name) {
1726 XFree(class_hint);
1727 return NS_ERROR_OUT_OF_MEMORY;
1729 class_hint->res_class = ToNewCString(brandName);
1730 if (!class_hint->res_class) {
1731 nsMemory::Free(class_hint->res_name);
1732 XFree(class_hint);
1733 return NS_ERROR_OUT_OF_MEMORY;
1736 // Parse res_name into a name and role. Characters other than
1737 // [A-Za-z0-9_-] are converted to '_'. Anything after the first
1738 // colon is assigned to role; if there's no colon, assign the
1739 // whole thing to both role and res_name.
1740 for (char *c = class_hint->res_name; *c; c++) {
1741 if (':' == *c) {
1742 *c = 0;
1743 role = c + 1;
1745 else if (!isascii(*c) || (!isalnum(*c) && ('_' != *c) && ('-' != *c)))
1746 *c = '_';
1748 class_hint->res_name[0] = toupper(class_hint->res_name[0]);
1749 if (!role) role = class_hint->res_name;
1751 QWindow *widget = mWidget;
1752 // If widget not show, handle might be null
1753 if (widget && widget->winId()) {
1754 XSetClassHint(gfxQtPlatform::GetXDisplay(widget),
1755 widget->winId(),
1756 class_hint);
1759 nsMemory::Free(class_hint->res_class);
1760 nsMemory::Free(class_hint->res_name);
1761 XFree(class_hint);
1762 #endif
1764 return NS_OK;
1767 void
1768 nsWindow::NativeResize(int32_t aWidth, int32_t aHeight, bool aRepaint)
1770 LOG(("nsWindow::NativeResize [%p] %d %d\n", (void *)this,
1771 aWidth, aHeight));
1773 mNeedsResize = false;
1775 mWidget->resize(aWidth, aHeight);
1777 if (aRepaint) {
1778 mWidget->renderLater();
1782 void
1783 nsWindow::NativeResize(int32_t aX, int32_t aY,
1784 int32_t aWidth, int32_t aHeight,
1785 bool aRepaint)
1787 LOG(("nsWindow::NativeResize [%p] %d %d %d %d\n", (void *)this,
1788 aX, aY, aWidth, aHeight));
1790 mNeedsResize = false;
1791 mNeedsMove = false;
1793 mWidget->setGeometry(aX, aY, aWidth, aHeight);
1795 if (aRepaint) {
1796 mWidget->renderLater();
1800 void
1801 nsWindow::NativeShow(bool aAction)
1803 if (aAction) {
1804 // On e10s, we never want the child process or plugin process
1805 // to go fullscreen because if we do the window because visible
1806 // do to disabled Qt-Xembed
1807 mWidget->show();
1808 // unset our flag now that our window has been shown
1809 mNeedsShow = false;
1811 else {
1812 mWidget->hide();
1816 NS_IMETHODIMP
1817 nsWindow::SetHasTransparentBackground(bool aTransparent)
1819 return NS_ERROR_NOT_IMPLEMENTED;
1822 NS_IMETHODIMP
1823 nsWindow::GetHasTransparentBackground(bool& aTransparent)
1825 aTransparent = mIsTransparent;
1826 return NS_OK;
1829 void *
1830 nsWindow::SetupPluginPort(void)
1832 NS_WARNING("Not implemented");
1833 return nullptr;
1836 nsresult
1837 nsWindow::SetWindowIconList(const nsTArray<nsCString> &aIconList)
1839 QIcon icon;
1841 for (uint32_t i = 0; i < aIconList.Length(); ++i) {
1842 const char *path = aIconList[i].get();
1843 LOG(("window [%p] Loading icon from %s\n", (void *)this, path));
1844 icon.addFile(path);
1847 mWidget->setIcon(icon);
1849 return NS_OK;
1852 void
1853 nsWindow::SetDefaultIcon(void)
1855 SetIcon(NS_LITERAL_STRING("default"));
1858 void nsWindow::QWidgetDestroyed()
1860 mWidget = nullptr;
1864 NS_IMETHODIMP
1865 nsWindow::HideWindowChrome(bool aShouldHide)
1867 if (!mWidget) {
1868 // Nothing to hide
1869 return NS_ERROR_FAILURE;
1872 // Sawfish, metacity, and presumably other window managers get
1873 // confused if we change the window decorations while the window
1874 // is visible.
1875 bool wasVisible = false;
1876 if (mWidget->isVisible()) {
1877 NativeShow(false);
1878 wasVisible = true;
1881 if (wasVisible) {
1882 NativeShow(true);
1885 return NS_OK;
1888 //////////////////////////////////////////////////////////////////////
1890 NS_IMETHODIMP_(bool)
1891 nsWindow::HasGLContext()
1893 return false;
1897 nsIWidget*
1898 nsWindow::GetParent(void)
1900 return mParent;
1903 float
1904 nsWindow::GetDPI()
1906 return qApp->primaryScreen()->logicalDotsPerInch();
1909 void
1910 nsWindow::OnDestroy(void)
1912 if (mOnDestroyCalled) {
1913 return;
1916 mOnDestroyCalled = true;
1918 // release references to children and device context
1919 nsBaseWidget::OnDestroy();
1921 // let go of our parent
1922 mParent = nullptr;
1924 nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
1925 NotifyWindowDestroyed();
1928 bool
1929 nsWindow::AreBoundsSane(void)
1931 if (mBounds.width > 0 && mBounds.height > 0) {
1932 return true;
1935 return false;
1938 void
1939 nsWindow::SetSoftwareKeyboardState(bool aOpen,
1940 const InputContextAction& aAction)
1942 if (aOpen) {
1943 NS_ENSURE_TRUE_VOID(mInputContext.mIMEState.mEnabled !=
1944 IMEState::DISABLED);
1946 // Ensure that opening the virtual keyboard is allowed for this specific
1947 // InputContext depending on the content.ime.strict.policy pref
1948 if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN &&
1949 Preferences::GetBool("content.ime.strict_policy", false) &&
1950 !aAction.ContentGotFocusByTrustedCause() &&
1951 !aAction.UserMightRequestOpenVKB()) {
1952 return;
1956 if (aOpen) {
1957 qApp->inputMethod()->show();
1958 } else {
1959 qApp->inputMethod()->hide();
1962 return;
1966 void
1967 nsWindow::ProcessMotionEvent()
1969 if (mMoveEvent.needDispatch) {
1970 WidgetMouseEvent event(true, NS_MOUSE_MOVE, this,
1971 WidgetMouseEvent::eReal);
1973 event.refPoint.x = nscoord(mMoveEvent.pos.x());
1974 event.refPoint.y = nscoord(mMoveEvent.pos.y());
1976 event.InitBasicModifiers(mMoveEvent.modifiers & Qt::ControlModifier,
1977 mMoveEvent.modifiers & Qt::AltModifier,
1978 mMoveEvent.modifiers & Qt::ShiftModifier,
1979 mMoveEvent.modifiers & Qt::MetaModifier);
1980 event.clickCount = 0;
1982 DispatchEvent(&event);
1983 mMoveEvent.needDispatch = false;
1986 mTimerStarted = false;