Merge m-c to fx-team.
[gecko.git] / widget / qt / nsWindow.cpp
blob1791e343abcb0bdf407992168e13363b22b14f5e
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/Util.h"
10 #include <QApplication>
11 #include <QDesktopWidget>
12 #include <QtGui/QCursor>
13 #include <QIcon>
14 #include <QGraphicsScene>
15 #include <QGraphicsView>
16 #include <QGraphicsSceneContextMenuEvent>
17 #include <QGraphicsSceneDragDropEvent>
18 #include <QGraphicsSceneMouseEvent>
19 #include <QGraphicsSceneHoverEvent>
20 #include <QGraphicsSceneWheelEvent>
21 #include <QGraphicsSceneResizeEvent>
22 #include <QStyleOptionGraphicsItem>
23 #include <QPaintEngine>
24 #include <QMimeData>
25 #include "mozqglwidgetwrapper.h"
27 #include <QtCore/QDebug>
28 #include <QtCore/QEvent>
29 #include <QtCore/QVariant>
30 #include <algorithm>
31 #if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0))
32 #include <QPinchGesture>
33 #include <QGestureRecognizer>
34 #include "mozSwipeGesture.h"
35 static Qt::GestureType gSwipeGestureId = Qt::CustomGesture;
37 // How many milliseconds mouseevents are blocked after receiving
38 // multitouch.
39 static const float GESTURES_BLOCK_MOUSE_FOR = 200;
40 #ifdef MOZ_ENABLE_QTMOBILITY
41 #include <QtSensors/QOrientationSensor>
42 using namespace QtMobility;
43 #endif // MOZ_ENABLE_QTMOBILITY
44 #endif // QT version check 4.6
46 #ifdef MOZ_X11
47 #include <X11/Xlib.h>
48 #endif //MOZ_X11
50 #include "nsXULAppAPI.h"
52 #include "prlink.h"
54 #include "nsWindow.h"
55 #include "mozqwidget.h"
57 #ifdef MOZ_ENABLE_QTMOBILITY
58 #include "mozqorientationsensorfilter.h"
59 #endif
61 #include "nsIdleService.h"
62 #include "nsRenderingContext.h"
63 #include "nsIRollupListener.h"
64 #include "nsWidgetsCID.h"
65 #include "nsQtKeyUtils.h"
66 #include "mozilla/Services.h"
67 #include "mozilla/Preferences.h"
68 #include "mozilla/Likely.h"
69 #include "mozilla/layers/LayersTypes.h"
70 #include "nsIWidgetListener.h"
72 #include "nsIStringBundle.h"
73 #include "nsGfxCIID.h"
75 #include "imgIContainer.h"
76 #include "nsGfxCIID.h"
77 #include "nsIInterfaceRequestorUtils.h"
78 #include "nsAutoPtr.h"
80 #include "gfxQtPlatform.h"
81 #ifdef MOZ_X11
82 #include "gfxXlibSurface.h"
83 #endif
84 #include "gfxQPainterSurface.h"
85 #include "gfxContext.h"
86 #include "gfxImageSurface.h"
88 #include "nsIDOMSimpleGestureEvent.h" //Gesture support
89 #include "nsIDOMWheelEvent.h"
91 #ifdef MOZ_X11
92 #include "keysym2ucs.h"
93 #endif
95 #include "gfxUtils.h"
96 #include "Layers.h"
97 #include "GLContextProvider.h"
98 #include "LayerManagerOGL.h"
99 #include "nsFastStartupQt.h"
101 // If embedding clients want to create widget without real parent window
102 // then nsIBaseWindow->Init() should have parent argument equal to PARENTLESS_WIDGET
103 #define PARENTLESS_WIDGET (void*)0x13579
105 #include "nsShmImage.h"
106 extern "C" {
107 #define PIXMAN_DONT_DEFINE_STDINT
108 #include "pixman.h"
111 using namespace mozilla;
112 using namespace mozilla::widget;
113 using mozilla::gl::GLContext;
114 using mozilla::layers::LayerManagerOGL;
116 // Cached offscreen surface
117 static nsRefPtr<gfxASurface> gBufferSurface;
118 #ifdef MOZ_HAVE_SHMIMAGE
119 // If we're using xshm rendering, mThebesSurface wraps gShmImage
120 nsRefPtr<nsShmImage> gShmImage;
121 #endif
123 static int gBufferPixmapUsageCount = 0;
124 static gfxIntSize gBufferMaxSize(0, 0);
126 // initialization static functions
127 static nsresult initialize_prefs (void);
129 static NS_DEFINE_IID(kCDragServiceCID, NS_DRAGSERVICE_CID);
131 #define NS_WINDOW_TITLE_MAX_LENGTH 4095
133 #define kWindowPositionSlop 20
135 // Qt
136 static const int WHEEL_DELTA = 120;
137 static bool gGlobalsInitialized = false;
139 static bool
140 is_mouse_in_window (MozQWidget* aWindow, double aMouseX, double aMouseY);
142 static bool sAltGrModifier = false;
144 #ifdef MOZ_ENABLE_QTMOBILITY
145 static QOrientationSensor *gOrientation = nullptr;
146 static MozQOrientationSensorFilter gOrientationFilter;
147 #endif
149 static bool
150 isContextMenuKeyEvent(const QKeyEvent *qe)
152 uint32_t kc = QtKeyCodeToDOMKeyCode(qe->key());
153 if (qe->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))
154 return false;
156 bool isShift = qe->modifiers() & Qt::ShiftModifier;
157 return (kc == NS_VK_F10 && isShift) ||
158 (kc == NS_VK_CONTEXT_MENU && !isShift);
161 static void
162 InitKeyEvent(nsKeyEvent &aEvent, QKeyEvent *aQEvent)
164 aEvent.InitBasicModifiers(aQEvent->modifiers() & Qt::ControlModifier,
165 aQEvent->modifiers() & Qt::AltModifier,
166 aQEvent->modifiers() & Qt::ShiftModifier,
167 aQEvent->modifiers() & Qt::MetaModifier);
168 aEvent.time = 0;
170 if (sAltGrModifier) {
171 aEvent.modifiers |= (widget::MODIFIER_CONTROL | widget::MODIFIER_ALT);
174 // The transformations above and in qt for the keyval are not invertible
175 // so link to the QKeyEvent (which will vanish soon after return from the
176 // event callback) to give plugins access to hardware_keycode and state.
177 // (An XEvent would be nice but the QKeyEvent is good enough.)
178 aEvent.pluginEvent = (void *)aQEvent;
181 nsWindow::nsWindow()
183 LOG(("%s [%p]\n", __PRETTY_FUNCTION__, (void *)this));
185 mIsTopLevel = false;
186 mIsDestroyed = false;
187 mIsShown = false;
188 mEnabled = true;
189 mWidget = nullptr;
190 mIsVisible = false;
191 mActivatePending = false;
192 mWindowType = eWindowType_child;
193 mSizeState = nsSizeMode_Normal;
194 mLastSizeMode = nsSizeMode_Normal;
195 mPluginType = PluginType_NONE;
196 mQCursor = Qt::ArrowCursor;
197 mNeedsResize = false;
198 mNeedsMove = false;
199 mListenForResizes = false;
200 mNeedsShow = false;
201 mGesturesCancelled = false;
202 mTimerStarted = false;
203 mPinchEvent.needDispatch = false;
204 mMoveEvent.needDispatch = false;
206 if (!gGlobalsInitialized) {
207 gfxPlatform::GetPlatform();
208 gGlobalsInitialized = true;
210 // It's OK if either of these fail, but it may not be one day.
211 initialize_prefs();
214 memset(mKeyDownFlags, 0, sizeof(mKeyDownFlags));
216 mIsTransparent = false;
218 mCursor = eCursor_standard;
220 gBufferPixmapUsageCount++;
222 #if (QT_VERSION > QT_VERSION_CHECK(4,6,0))
223 if (gSwipeGestureId == Qt::CustomGesture) {
224 // QGestureRecognizer takes ownership
225 MozSwipeGestureRecognizer* swipeRecognizer = new MozSwipeGestureRecognizer;
226 gSwipeGestureId = QGestureRecognizer::registerRecognizer(swipeRecognizer);
228 #endif
231 static inline gfxASurface::gfxImageFormat
232 _depth_to_gfximage_format(int32_t aDepth)
234 switch (aDepth) {
235 case 32:
236 return gfxASurface::ImageFormatARGB32;
237 case 24:
238 return gfxASurface::ImageFormatRGB24;
239 case 16:
240 return gfxASurface::ImageFormatRGB16_565;
241 default:
242 return gfxASurface::ImageFormatUnknown;
246 static inline QImage::Format
247 _gfximage_to_qformat(gfxASurface::gfxImageFormat aFormat)
249 switch (aFormat) {
250 case gfxASurface::ImageFormatARGB32:
251 return QImage::Format_ARGB32_Premultiplied;
252 case gfxASurface::ImageFormatRGB24:
253 return QImage::Format_ARGB32;
254 case gfxASurface::ImageFormatRGB16_565:
255 return QImage::Format_RGB16;
256 default:
257 return QImage::Format_Invalid;
261 static bool
262 UpdateOffScreenBuffers(int aDepth, QSize aSize, QWidget* aWidget = nullptr)
264 gfxIntSize size(aSize.width(), aSize.height());
265 if (gBufferSurface) {
266 if (gBufferMaxSize.width < size.width ||
267 gBufferMaxSize.height < size.height) {
268 gBufferSurface = nullptr;
269 } else
270 return true;
273 gBufferMaxSize.width = std::max(gBufferMaxSize.width, size.width);
274 gBufferMaxSize.height = std::max(gBufferMaxSize.height, size.height);
276 // Check if system depth has related gfxImage format
277 gfxASurface::gfxImageFormat format =
278 _depth_to_gfximage_format(aDepth);
280 // Use fallback RGB24 format, Qt will do conversion for us
281 if (format == gfxASurface::ImageFormatUnknown)
282 format = gfxASurface::ImageFormatRGB24;
284 #ifdef MOZ_HAVE_SHMIMAGE
285 if (aWidget) {
286 if (gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType() ==
287 gfxASurface::SurfaceTypeImage) {
288 gShmImage = nsShmImage::Create(gBufferMaxSize,
289 DefaultVisualOfScreen(gfxQtPlatform::GetXScreen(aWidget)),
290 aDepth);
291 gBufferSurface = gShmImage->AsSurface();
292 return true;
295 #endif
297 gBufferSurface = gfxPlatform::GetPlatform()->
298 CreateOffscreenSurface(gBufferMaxSize, gfxASurface::ContentFromFormat(format));
300 return true;
303 nsWindow::~nsWindow()
305 LOG(("%s [%p]\n", __PRETTY_FUNCTION__, (void *)this));
307 Destroy();
310 /* static */ void
311 nsWindow::ReleaseGlobals()
315 NS_IMPL_ISUPPORTS_INHERITED1(nsWindow, nsBaseWidget, nsISupportsWeakReference)
317 NS_IMETHODIMP
318 nsWindow::ConfigureChildren(const nsTArray<nsIWidget::Configuration>& aConfigurations)
320 for (uint32_t i = 0; i < aConfigurations.Length(); ++i) {
321 const Configuration& configuration = aConfigurations[i];
323 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
324 NS_ASSERTION(w->GetParent() == this,
325 "Configured widget is not a child");
327 if (w->mBounds.Size() != configuration.mBounds.Size()) {
328 w->Resize(configuration.mBounds.x, configuration.mBounds.y,
329 configuration.mBounds.width, configuration.mBounds.height,
330 true);
331 } else if (w->mBounds.TopLeft() != configuration.mBounds.TopLeft()) {
332 w->Move(configuration.mBounds.x, configuration.mBounds.y);
335 return NS_OK;
338 NS_IMETHODIMP
339 nsWindow::Destroy(void)
341 if (mIsDestroyed || !mWidget)
342 return NS_OK;
344 LOG(("nsWindow::Destroy [%p]\n", (void *)this));
345 mIsDestroyed = true;
347 if (gBufferPixmapUsageCount &&
348 --gBufferPixmapUsageCount == 0) {
350 gBufferSurface = nullptr;
351 #ifdef MOZ_HAVE_SHMIMAGE
352 gShmImage = nullptr;
353 #endif
354 #ifdef MOZ_ENABLE_QTMOBILITY
355 if (gOrientation) {
356 gOrientation->removeFilter(&gOrientationFilter);
357 gOrientation->stop();
358 delete gOrientation;
359 gOrientation = nullptr;
361 #endif
364 /** Need to clean our LayerManager up while still alive */
365 if (mLayerManager) {
366 nsRefPtr<GLContext> gl = nullptr;
367 if (mLayerManager->GetBackendType() == mozilla::layers::LAYERS_OPENGL) {
368 LayerManagerOGL *ogllm = static_cast<LayerManagerOGL*>(mLayerManager.get());
369 gl = ogllm->gl();
372 mLayerManager->Destroy();
374 if (gl) {
375 gl->MarkDestroyed();
378 mLayerManager = nullptr;
380 // It is safe to call DestroyeCompositor several times (here and
381 // in the parent class) since it will take effect only once.
382 // The reason we call it here is because on gtk platforms we need
383 // to destroy the compositor before we destroy the gdk window (which
384 // destroys the the gl context attached to it).
385 DestroyCompositor();
387 ClearCachedResources();
389 nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
390 if (rollupListener) {
391 nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
392 if (static_cast<nsIWidget *>(this) == rollupWidget) {
393 rollupListener->Rollup(0, nullptr);
397 Show(false);
399 // walk the list of children and call destroy on them. Have to be
400 // careful, though -- calling destroy on a kid may actually remove
401 // it from our child list, losing its sibling links.
402 for (nsIWidget* kid = mFirstChild; kid; ) {
403 nsIWidget* next = kid->GetNextSibling();
404 kid->Destroy();
405 kid = next;
408 // Destroy thebes surface now. Badness can happen if we destroy
409 // the surface after its X Window.
410 mThebesSurface = nullptr;
412 QWidget *view = nullptr;
413 QGraphicsScene *scene = nullptr;
414 if (mWidget) {
415 if (mIsTopLevel) {
416 view = GetViewWidget();
417 scene = mWidget->scene();
420 mWidget->dropReceiver();
422 // Call deleteLater instead of delete; Qt still needs the object
423 // to be valid even after sending it a Close event. We could
424 // also set WA_DeleteOnClose, but this gives us more control.
425 mWidget->deleteLater();
427 mWidget = nullptr;
429 OnDestroy();
431 // tear down some infrastructure after all event handling is finished
432 delete scene;
433 delete view;
435 return NS_OK;
438 void
439 nsWindow::ClearCachedResources()
441 if (mLayerManager &&
442 mLayerManager->GetBackendType() == mozilla::layers::LAYERS_BASIC) {
443 statimLayerManager->ClearCachedResources();
445 for (nsIWidget* kid = mFirstChild; kid; ) {
446 nsIWidget* next = kid->GetNextSibling();
447 static_cast<nsWindow*>(kid)->ClearCachedResources();
448 kid = next;
452 NS_IMETHODIMP
453 nsWindow::SetParent(nsIWidget *aNewParent)
455 NS_ENSURE_ARG_POINTER(aNewParent);
456 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
457 nsIWidget* parent = GetParent();
458 if (parent) {
459 parent->RemoveChild(this);
461 ReparentNativeWidget(aNewParent);
462 aNewParent->AddChild(this);
463 return NS_OK;
466 NS_IMETHODIMP
467 nsWindow::ReparentNativeWidget(nsIWidget *aNewParent)
469 NS_PRECONDITION(aNewParent, "");
471 MozQWidget* newParent = static_cast<MozQWidget*>(aNewParent->GetNativeData(NS_NATIVE_WINDOW));
472 NS_ASSERTION(newParent, "Parent widget has a null native window handle");
473 if (mWidget) {
474 mWidget->setParentItem(newParent);
476 return NS_OK;
479 NS_IMETHODIMP
480 nsWindow::SetModal(bool aModal)
482 LOG(("nsWindow::SetModal [%p] %d, widget[%p]\n", (void *)this, aModal, mWidget));
483 if (mWidget)
484 mWidget->setModal(aModal);
486 return NS_OK;
489 bool
490 nsWindow::IsVisible() const
492 return mIsShown;
495 NS_IMETHODIMP
496 nsWindow::ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY)
498 if (mWidget) {
499 int32_t screenWidth = QApplication::desktop()->width();
500 int32_t screenHeight = QApplication::desktop()->height();
502 if (aAllowSlop) {
503 if (*aX < (kWindowPositionSlop - mBounds.width))
504 *aX = kWindowPositionSlop - mBounds.width;
505 if (*aX > (screenWidth - kWindowPositionSlop))
506 *aX = screenWidth - kWindowPositionSlop;
507 if (*aY < (kWindowPositionSlop - mBounds.height))
508 *aY = kWindowPositionSlop - mBounds.height;
509 if (*aY > (screenHeight - kWindowPositionSlop))
510 *aY = screenHeight - kWindowPositionSlop;
511 } else {
512 if (*aX < 0)
513 *aX = 0;
514 if (*aX > (screenWidth - mBounds.width))
515 *aX = screenWidth - mBounds.width;
516 if (*aY < 0)
517 *aY = 0;
518 if (*aY > (screenHeight - mBounds.height))
519 *aY = screenHeight - mBounds.height;
523 return NS_OK;
526 NS_IMETHODIMP
527 nsWindow::Move(double aX, double aY)
529 LOG(("nsWindow::Move [%p] %f %f\n", (void *)this,
530 aX, aY));
532 int32_t x = NSToIntRound(aX);
533 int32_t y = NSToIntRound(aY);
535 if (mIsTopLevel) {
536 SetSizeMode(nsSizeMode_Normal);
539 if (x == mBounds.x && y == mBounds.y)
540 return NS_OK;
542 mNeedsMove = false;
544 // update the bounds
545 QPointF pos( x, y );
546 if (mIsTopLevel) {
547 QWidget *widget = GetViewWidget();
548 NS_ENSURE_TRUE(widget, NS_OK);
549 widget->move(x, y);
551 else if (mWidget) {
552 // the position of the widget is set relative to the parent
553 // so we map the coordinates accordingly
554 pos = mWidget->mapFromScene(pos);
555 pos = mWidget->mapToParent(pos);
556 mWidget->setPos(pos);
559 mBounds.x = pos.x();
560 mBounds.y = pos.y();
562 NotifyRollupGeometryChange();
563 return NS_OK;
566 NS_IMETHODIMP
567 nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
568 nsIWidget *aWidget,
569 bool aActivate)
571 return NS_ERROR_NOT_IMPLEMENTED;
574 NS_IMETHODIMP
575 nsWindow::SetSizeMode(int32_t aMode)
577 nsresult rv;
579 LOG(("nsWindow::SetSizeMode [%p] %d\n", (void *)this, aMode));
580 if (aMode != nsSizeMode_Minimized) {
581 GetViewWidget()->activateWindow();
584 // Save the requested state.
585 rv = nsBaseWidget::SetSizeMode(aMode);
587 // return if there's no shell or our current state is the same as
588 // the mode we were just set to.
589 if (!mWidget || mSizeState == mSizeMode) {
590 return rv;
593 QWidget *widget = GetViewWidget();
594 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
596 switch (aMode) {
597 case nsSizeMode_Maximized:
598 widget->showMaximized();
599 break;
600 case nsSizeMode_Minimized:
601 widget->showMinimized();
602 break;
603 case nsSizeMode_Fullscreen:
604 widget->showFullScreen();
605 break;
607 default:
608 // nsSizeMode_Normal, really.
609 widget->showNormal();
610 break;
613 mSizeState = mSizeMode;
615 return rv;
618 // Helper function to recursively find the first parent item that
619 // is still visible (QGraphicsItem can be hidden even if they are
620 // set to visible if one of their ancestors is invisible)
621 static void find_first_visible_parent(QGraphicsItem* aItem, QGraphicsItem*& aVisibleItem)
623 NS_ENSURE_TRUE_VOID(aItem);
625 aVisibleItem = nullptr;
626 QGraphicsItem* parItem = nullptr;
627 while (!aVisibleItem) {
628 if (aItem->isVisible())
629 aVisibleItem = aItem;
630 else {
631 parItem = aItem->parentItem();
632 if (parItem)
633 aItem = parItem;
634 else {
635 aItem->setVisible(true);
636 aVisibleItem = aItem;
642 NS_IMETHODIMP
643 nsWindow::SetFocus(bool aRaise)
645 // Make sure that our owning widget has focus. If it doesn't try to
646 // grab it. Note that we don't set our focus flag in this case.
647 LOGFOCUS((" SetFocus [%p]\n", (void *)this));
649 if (!mWidget)
650 return NS_ERROR_FAILURE;
652 if (mWidget->hasFocus())
653 return NS_OK;
655 // Because QGraphicsItem cannot get the focus if they are
656 // invisible, we look up the chain, for the lowest visible
657 // parent and focus that one
658 QGraphicsItem* realFocusItem = nullptr;
659 find_first_visible_parent(mWidget, realFocusItem);
661 if (!realFocusItem || realFocusItem->hasFocus())
662 return NS_OK;
664 if (aRaise) {
665 // the raising has to happen on the view widget
666 QWidget *widget = GetViewWidget();
667 if (widget)
668 widget->raise();
669 realFocusItem->setFocus(Qt::ActiveWindowFocusReason);
671 else
672 realFocusItem->setFocus(Qt::OtherFocusReason);
674 // XXXndeakin why is this here? It should dispatch only when the OS
675 // notifies us.
676 DispatchActivateEvent();
678 return NS_OK;
681 NS_IMETHODIMP
682 nsWindow::GetScreenBounds(nsIntRect &aRect)
684 aRect = nsIntRect(nsIntPoint(0, 0), mBounds.Size());
685 if (mIsTopLevel) {
686 QWidget *widget = GetViewWidget();
687 NS_ENSURE_TRUE(widget, NS_OK);
688 QPoint pos = widget->pos();
689 aRect.MoveTo(pos.x(), pos.y());
691 else {
692 aRect.MoveTo(WidgetToScreenOffset());
694 LOG(("GetScreenBounds %d %d | %d %d | %d %d\n",
695 aRect.x, aRect.y,
696 mBounds.width, mBounds.height,
697 aRect.width, aRect.height));
698 return NS_OK;
701 NS_IMETHODIMP
702 nsWindow::SetForegroundColor(const nscolor &aColor)
704 return NS_ERROR_NOT_IMPLEMENTED;
707 NS_IMETHODIMP
708 nsWindow::SetBackgroundColor(const nscolor &aColor)
710 return NS_ERROR_NOT_IMPLEMENTED;
713 NS_IMETHODIMP
714 nsWindow::SetCursor(nsCursor aCursor)
716 if (mCursor == aCursor)
717 return NS_OK;
719 mCursor = aCursor;
720 if (mWidget)
721 mWidget->SetCursor(mCursor);
722 return NS_OK;
725 NS_IMETHODIMP
726 nsWindow::SetCursor(imgIContainer* aCursor,
727 uint32_t aHotspotX, uint32_t aHotspotY)
729 return NS_ERROR_NOT_AVAILABLE;
732 NS_IMETHODIMP
733 nsWindow::Invalidate(const nsIntRect &aRect)
735 LOGDRAW(("Invalidate (rect) [%p,%p]: %d %d %d %d\n", (void *)this,
736 (void*)mWidget,aRect.x, aRect.y, aRect.width, aRect.height));
738 if (!mWidget)
739 return NS_OK;
741 mDirtyScrollArea = mDirtyScrollArea.united(QRect(aRect.x, aRect.y, aRect.width, aRect.height));
743 mWidget->update(aRect.x, aRect.y, aRect.width, aRect.height);
745 return NS_OK;
748 // Returns the graphics view widget for this nsWindow by iterating
749 // the chain of parents until a toplevel window with a view/scene is found.
750 // (This function always returns something or asserts if the precondition
751 // is not met)
752 QWidget* nsWindow::GetViewWidget()
754 NS_ASSERTION(mWidget, "Calling GetViewWidget without mWidget created");
755 if (!mWidget || !mWidget->scene() || !mWidget->scene()->views().size())
756 return nullptr;
758 NS_ASSERTION(mWidget->scene()->views().size() == 1, "Not exactly one view for our scene!");
759 return mWidget->scene()->views()[0];
762 void*
763 nsWindow::GetNativeData(uint32_t aDataType)
765 switch (aDataType) {
766 case NS_NATIVE_WINDOW:
767 case NS_NATIVE_WIDGET: {
768 if (!mWidget)
769 return nullptr;
771 return mWidget;
772 break;
775 case NS_NATIVE_PLUGIN_PORT:
776 return SetupPluginPort();
777 break;
779 case NS_NATIVE_DISPLAY:
781 #ifdef MOZ_X11
782 return gfxQtPlatform::GetXDisplay(GetViewWidget());
783 #else
784 return nullptr;
785 #endif
787 break;
789 case NS_NATIVE_GRAPHIC: {
790 return nullptr;
791 break;
794 case NS_NATIVE_SHELLWIDGET: {
795 QWidget* widget = nullptr;
796 if (mWidget && mWidget->scene())
797 widget = mWidget->scene()->views()[0]->viewport();
798 return (void *) widget;
801 case NS_NATIVE_SHAREABLE_WINDOW: {
802 QWidget *widget = GetViewWidget();
803 return widget ? (void*)widget->winId() : nullptr;
806 default:
807 NS_WARNING("nsWindow::GetNativeData called with bad value");
808 return nullptr;
812 NS_IMETHODIMP
813 nsWindow::SetTitle(const nsAString& aTitle)
815 QString qStr(QString::fromUtf16(aTitle.BeginReading(), aTitle.Length()));
816 if (mIsTopLevel) {
817 QWidget *widget = GetViewWidget();
818 if (widget)
819 widget->setWindowTitle(qStr);
821 else if (mWidget)
822 mWidget->setWindowTitle(qStr);
824 return NS_OK;
827 NS_IMETHODIMP
828 nsWindow::SetIcon(const nsAString& aIconSpec)
830 if (!mWidget)
831 return NS_OK;
833 nsCOMPtr<nsIFile> iconFile;
834 nsAutoCString path;
835 nsTArray<nsCString> iconList;
837 // Look for icons with the following suffixes appended to the base name.
838 // The last two entries (for the old XPM format) will be ignored unless
839 // no icons are found using the other suffixes. XPM icons are depricated.
841 const char extensions[6][7] = { ".png", "16.png", "32.png", "48.png",
842 ".xpm", "16.xpm" };
844 for (uint32_t i = 0; i < ArrayLength(extensions); i++) {
845 // Don't bother looking for XPM versions if we found a PNG.
846 if (i == ArrayLength(extensions) - 2 && iconList.Length())
847 break;
849 nsAutoString extension;
850 extension.AppendASCII(extensions[i]);
852 ResolveIconName(aIconSpec, extension, getter_AddRefs(iconFile));
853 if (iconFile) {
854 iconFile->GetNativePath(path);
855 iconList.AppendElement(path);
859 // leave the default icon intact if no matching icons were found
860 if (iconList.Length() == 0)
861 return NS_OK;
863 return SetWindowIconList(iconList);
866 nsIntPoint
867 nsWindow::WidgetToScreenOffset()
869 NS_ENSURE_TRUE(mWidget, nsIntPoint(0,0));
871 QPointF origin(0, 0);
872 origin = mWidget->mapToScene(origin);
874 return nsIntPoint(origin.x(), origin.y());
877 NS_IMETHODIMP
878 nsWindow::EnableDragDrop(bool aEnable)
880 mWidget->setAcceptDrops(aEnable);
881 return NS_OK;
884 NS_IMETHODIMP
885 nsWindow::CaptureMouse(bool aCapture)
887 LOG(("CaptureMouse %p\n", (void *)this));
889 if (!mWidget)
890 return NS_OK;
892 QWidget *widget = GetViewWidget();
893 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
895 if (aCapture)
896 widget->grabMouse();
897 else
898 widget->releaseMouse();
900 return NS_OK;
903 NS_IMETHODIMP
904 nsWindow::CaptureRollupEvents(nsIRollupListener *aListener,
905 bool aDoCapture)
907 if (!mWidget)
908 return NS_OK;
910 LOG(("CaptureRollupEvents %p\n", (void *)this));
912 gRollupListener = aDoCapture ? aListener : nullptr;
913 return NS_OK;
916 bool
917 nsWindow::CheckForRollup(double aMouseX, double aMouseY,
918 bool aIsWheel)
920 nsIRollupListener* rollupListener = GetActiveRollupListener();
921 nsCOMPtr<nsIWidget> rollupWidget;
922 if (rollupListener) {
923 rollupWidget = rollupListener->GetRollupWidget();
925 if (!rollupWidget) {
926 nsBaseWidget::gRollupListener = nullptr;
927 return false;
930 bool retVal = false;
931 MozQWidget *currentPopup =
932 (MozQWidget *)rollupWidget->GetNativeData(NS_NATIVE_WINDOW);
933 if (!is_mouse_in_window(currentPopup, aMouseX, aMouseY)) {
934 bool rollup = true;
935 if (aIsWheel) {
936 rollup = rollupListener->ShouldRollupOnMouseWheelEvent();
937 retVal = true;
939 // if we're dealing with menus, we probably have submenus and
940 // we don't want to rollup if the clickis in a parent menu of
941 // the current submenu
942 uint32_t popupsToRollup = UINT32_MAX;
943 if (rollupListener) {
944 nsAutoTArray<nsIWidget*, 5> widgetChain;
945 uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain);
946 for (uint32_t i=0; i<widgetChain.Length(); ++i) {
947 nsIWidget* widget = widgetChain[i];
948 MozQWidget* currWindow =
949 (MozQWidget*) widget->GetNativeData(NS_NATIVE_WINDOW);
950 if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) {
951 if (i < sameTypeCount) {
952 rollup = false;
954 else {
955 popupsToRollup = sameTypeCount;
957 break;
959 } // foreach parent menu widget
960 } // if rollup listener knows about menus
962 // if we've determined that we should still rollup, do it.
963 if (rollup) {
964 retVal = rollupListener->Rollup(popupsToRollup, nullptr);
968 return retVal;
971 /* static */
972 bool
973 is_mouse_in_window (MozQWidget* aWindow, double aMouseX, double aMouseY)
975 return aWindow->geometry().contains( aMouseX, aMouseY );
978 NS_IMETHODIMP
979 nsWindow::GetAttention(int32_t aCycleCount)
981 LOG(("nsWindow::GetAttention [%p]\n", (void *)this));
982 return NS_ERROR_NOT_IMPLEMENTED;
985 #ifdef MOZ_X11
986 static already_AddRefed<gfxASurface>
987 GetSurfaceForQWidget(QWidget* aDrawable)
989 nsRefPtr<gfxASurface> result =
990 new gfxXlibSurface(gfxQtPlatform::GetXDisplay(aDrawable),
991 aDrawable->winId(),
992 DefaultVisualOfScreen(gfxQtPlatform::GetXScreen(aDrawable)),
993 gfxIntSize(aDrawable->size().width(),
994 aDrawable->size().height()));
995 return result.forget();
997 #endif
999 bool
1000 nsWindow::DoPaint(QPainter* aPainter, const QStyleOptionGraphicsItem* aOption, QWidget* aWidget)
1002 if (mIsDestroyed) {
1003 LOG(("Expose event on destroyed window [%p] window %p\n",
1004 (void *)this, mWidget));
1005 return false;
1008 // Call WillPaintWindow to allow scripts etc. to run before we paint
1010 if (mWidgetListener)
1011 mWidgetListener->WillPaintWindow(this);
1014 if (!mWidget)
1015 return false;
1017 QRectF r;
1018 if (aOption)
1019 r = aOption->exposedRect;
1020 else
1021 r = mWidget->boundingRect();
1023 if (r.isEmpty())
1024 return nsEventStatus_eIgnore;
1026 if (!mDirtyScrollArea.isEmpty())
1027 mDirtyScrollArea = QRegion();
1029 bool painted = false;
1030 nsIntRect rect(r.x(), r.y(), r.width(), r.height());
1032 nsFastStartup* startup = nsFastStartup::GetSingleton();
1033 if (startup) {
1034 startup->RemoveFakeLayout();
1037 if (GetLayerManager(nullptr)->GetBackendType() == mozilla::layers::LAYERS_OPENGL) {
1038 aPainter->beginNativePainting();
1039 nsIntRegion region(rect);
1040 static_cast<mozilla::layers::LayerManagerOGL*>(GetLayerManager(nullptr))->
1041 SetClippingRegion(region);
1043 gfxMatrix matr;
1044 matr.Translate(gfxPoint(aPainter->transform().dx(), aPainter->transform().dy()));
1045 #ifdef MOZ_ENABLE_QTMOBILITY
1046 // This is needed for rotate transformation on MeeGo
1047 // This will work very slow if pixman does not handle rotation very well
1048 matr.Rotate((M_PI/180) * gOrientationFilter.GetWindowRotationAngle());
1049 static_cast<mozilla::layers::LayerManagerOGL*>(GetLayerManager(nullptr))->
1050 SetWorldTransform(matr);
1051 #endif //MOZ_ENABLE_QTMOBILITY
1053 if (mWidgetListener)
1054 painted = mWidgetListener->PaintWindow(this, region);
1055 aPainter->endNativePainting();
1056 if (mWidgetListener)
1057 mWidgetListener->DidPaintWindow();
1058 return painted;
1061 gfxQtPlatform::RenderMode renderMode = gfxQtPlatform::GetPlatform()->GetRenderMode();
1062 int depth = aPainter->device()->depth();
1064 nsRefPtr<gfxASurface> targetSurface = nullptr;
1065 if (renderMode == gfxQtPlatform::RENDER_BUFFERED) {
1066 // Prepare offscreen buffers iamge or xlib, depends from paintEngineType
1067 if (!UpdateOffScreenBuffers(depth, QSize(r.width(), r.height())))
1068 return false;
1070 targetSurface = gBufferSurface;
1072 #ifdef CAIRO_HAS_QT_SURFACE
1073 } else if (renderMode == gfxQtPlatform::RENDER_QPAINTER) {
1074 targetSurface = new gfxQPainterSurface(aPainter);
1075 #endif
1076 } else if (renderMode == gfxQtPlatform::RENDER_DIRECT) {
1077 if (!UpdateOffScreenBuffers(depth, aWidget->size(), aWidget)) {
1078 return false;
1080 targetSurface = gBufferSurface;
1083 if (MOZ_UNLIKELY(!targetSurface))
1084 return false;
1086 nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
1088 // We will paint to 0, 0 position in offscrenn buffer
1089 if (renderMode == gfxQtPlatform::RENDER_BUFFERED) {
1090 ctx->Translate(gfxPoint(-r.x(), -r.y()));
1092 else if (renderMode == gfxQtPlatform::RENDER_DIRECT) {
1093 gfxMatrix matr;
1094 matr.Translate(gfxPoint(aPainter->transform().dx(), aPainter->transform().dy()));
1095 #ifdef MOZ_ENABLE_QTMOBILITY
1096 // This is needed for rotate transformation on MeeGo
1097 // This will work very slow if pixman does not handle rotation very well
1098 matr.Rotate((M_PI/180) * gOrientationFilter.GetWindowRotationAngle());
1099 NS_ASSERTION(PIXMAN_VERSION > PIXMAN_VERSION_ENCODE(0, 21, 2) ||
1100 !gOrientationFilter.GetWindowRotationAngle(),
1101 "Old pixman and rotate transform, it is going to be slow");
1102 #endif //MOZ_ENABLE_QTMOBILITY
1104 ctx->SetMatrix(matr);
1108 AutoLayerManagerSetup
1109 setupLayerManager(this, ctx, mozilla::layers::BUFFER_NONE);
1110 if (mWidgetListener) {
1111 nsIntRegion region(rect);
1112 painted = mWidgetListener->PaintWindow(this, region);
1116 // DispatchEvent can Destroy us (bug 378273), avoid doing any paint
1117 // operations below if that happened - it will lead to XError and exit().
1118 if (MOZ_UNLIKELY(mIsDestroyed))
1119 return painted;
1121 if (!painted)
1122 return false;
1124 LOGDRAW(("[%p] draw done\n", this));
1126 // Handle buffered painting mode
1127 if (renderMode == gfxQtPlatform::RENDER_BUFFERED) {
1128 #if defined(MOZ_X11) && defined(Q_WS_X11)
1129 if (gBufferSurface->GetType() == gfxASurface::SurfaceTypeXlib) {
1130 // Paint offscreen pixmap to QPainter
1131 static QPixmap gBufferPixmap;
1132 Drawable draw = static_cast<gfxXlibSurface*>(gBufferSurface.get())->XDrawable();
1133 if (gBufferPixmap.handle() != draw)
1134 gBufferPixmap = QPixmap::fromX11Pixmap(draw, QPixmap::ExplicitlyShared);
1135 XSync(static_cast<gfxXlibSurface*>(gBufferSurface.get())->XDisplay(), False);
1136 aPainter->drawPixmap(QPoint(rect.x, rect.y), gBufferPixmap,
1137 QRect(0, 0, rect.width, rect.height));
1139 } else
1140 #endif
1141 if (gBufferSurface->GetType() == gfxASurface::SurfaceTypeImage) {
1142 // in raster mode we can just wrap gBufferImage as QImage and paint directly
1143 gfxImageSurface *imgs = static_cast<gfxImageSurface*>(gBufferSurface.get());
1144 QImage img(imgs->Data(),
1145 imgs->Width(),
1146 imgs->Height(),
1147 imgs->Stride(),
1148 _gfximage_to_qformat(imgs->Format()));
1149 aPainter->drawImage(QPoint(rect.x, rect.y), img,
1150 QRect(0, 0, rect.width, rect.height));
1152 } else if (renderMode == gfxQtPlatform::RENDER_DIRECT) {
1153 QRect trans = aPainter->transform().mapRect(r).toRect();
1154 #ifdef MOZ_X11
1155 if (gBufferSurface->GetType() == gfxASurface::SurfaceTypeXlib) {
1156 nsRefPtr<gfxASurface> widgetSurface = GetSurfaceForQWidget(aWidget);
1157 nsRefPtr<gfxContext> ctx = new gfxContext(widgetSurface);
1158 ctx->SetSource(gBufferSurface);
1159 ctx->Rectangle(gfxRect(trans.x(), trans.y(), trans.width(), trans.height()), true);
1160 ctx->Clip();
1161 ctx->Fill();
1162 } else
1163 #endif
1164 if (gBufferSurface->GetType() == gfxASurface::SurfaceTypeImage) {
1165 #ifdef MOZ_HAVE_SHMIMAGE
1166 if (gShmImage) {
1167 gShmImage->Put(aWidget, trans);
1168 } else
1169 #endif
1171 // Qt should take care about optimized rendering on QImage into painter device (gl/fb/image et.c.)
1172 gfxImageSurface *imgs = static_cast<gfxImageSurface*>(gBufferSurface.get());
1173 QImage img(imgs->Data(),
1174 imgs->Width(),
1175 imgs->Height(),
1176 imgs->Stride(),
1177 _gfximage_to_qformat(imgs->Format()));
1178 aPainter->drawImage(trans, img, trans);
1183 ctx = nullptr;
1184 targetSurface = nullptr;
1185 if (mWidgetListener)
1186 mWidgetListener->DidPaintWindow();
1188 // check the return value!
1189 return painted;
1192 nsEventStatus
1193 nsWindow::OnMoveEvent(QGraphicsSceneHoverEvent *aEvent)
1195 LOG(("configure event [%p] %d %d\n", (void *)this,
1196 aEvent->pos().x(), aEvent->pos().y()));
1198 // can we shortcut?
1199 if (!mWidget || !mWidgetListener)
1200 return nsEventStatus_eIgnore;
1202 if ((mBounds.x == aEvent->pos().x() &&
1203 mBounds.y == aEvent->pos().y()))
1205 return nsEventStatus_eIgnore;
1208 bool moved = mWidgetListener->WindowMoved(this, aEvent->pos().x(), aEvent->pos().y());
1209 return moved ? nsEventStatus_eConsumeNoDefault : nsEventStatus_eIgnore;
1212 nsEventStatus
1213 nsWindow::OnResizeEvent(QGraphicsSceneResizeEvent *aEvent)
1215 nsIntRect rect;
1217 // Generate XPFE resize event
1218 GetBounds(rect);
1220 rect.width = aEvent->newSize().width();
1221 rect.height = aEvent->newSize().height();
1223 mBounds.width = rect.width;
1224 mBounds.height = rect.height;
1226 nsEventStatus status;
1227 DispatchResizeEvent(rect, status);
1228 return status;
1231 nsEventStatus
1232 nsWindow::OnCloseEvent(QCloseEvent *aEvent)
1234 if (!mWidgetListener)
1235 return nsEventStatus_eIgnore;
1236 mWidgetListener->RequestWindowClose(this);
1237 return nsEventStatus_eConsumeNoDefault;
1240 nsEventStatus
1241 nsWindow::OnEnterNotifyEvent(QGraphicsSceneHoverEvent *aEvent)
1243 nsMouseEvent event(true, NS_MOUSE_ENTER, this, nsMouseEvent::eReal);
1245 event.refPoint.x = nscoord(aEvent->pos().x());
1246 event.refPoint.y = nscoord(aEvent->pos().y());
1248 LOG(("OnEnterNotify: %p\n", (void *)this));
1250 return DispatchEvent(&event);
1253 nsEventStatus
1254 nsWindow::OnLeaveNotifyEvent(QGraphicsSceneHoverEvent *aEvent)
1256 nsMouseEvent event(true, NS_MOUSE_EXIT, this, nsMouseEvent::eReal);
1258 event.refPoint.x = nscoord(aEvent->pos().x());
1259 event.refPoint.y = nscoord(aEvent->pos().y());
1261 LOG(("OnLeaveNotify: %p\n", (void *)this));
1263 return DispatchEvent(&event);
1266 // Block the mouse events if user was recently executing gestures;
1267 // otherwise there will be also some panning during/after gesture
1268 #if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0))
1269 #define CHECK_MOUSE_BLOCKED { \
1270 if (mLastMultiTouchTime.isValid()) { \
1271 if (mLastMultiTouchTime.elapsed() < GESTURES_BLOCK_MOUSE_FOR) \
1272 return nsEventStatus_eIgnore; \
1273 else \
1274 mLastMultiTouchTime = QTime(); \
1277 #else
1278 define CHECK_MOUSE_BLOCKED {}
1279 #endif
1281 nsEventStatus
1282 nsWindow::OnMotionNotifyEvent(QPointF aPos, Qt::KeyboardModifiers aModifiers)
1284 UserActivity();
1286 CHECK_MOUSE_BLOCKED
1288 mMoveEvent.pos = aPos;
1289 mMoveEvent.modifiers = aModifiers;
1290 mMoveEvent.needDispatch = true;
1291 DispatchMotionToMainThread();
1293 return nsEventStatus_eIgnore;
1296 void
1297 nsWindow::InitButtonEvent(nsMouseEvent &aMoveEvent,
1298 QGraphicsSceneMouseEvent *aEvent, int aClickCount)
1300 aMoveEvent.refPoint.x = nscoord(aEvent->pos().x());
1301 aMoveEvent.refPoint.y = nscoord(aEvent->pos().y());
1303 aMoveEvent.InitBasicModifiers(aEvent->modifiers() & Qt::ControlModifier,
1304 aEvent->modifiers() & Qt::AltModifier,
1305 aEvent->modifiers() & Qt::ShiftModifier,
1306 aEvent->modifiers() & Qt::MetaModifier);
1307 aMoveEvent.clickCount = aClickCount;
1310 nsEventStatus
1311 nsWindow::OnButtonPressEvent(QGraphicsSceneMouseEvent *aEvent)
1313 // The user has done something.
1314 UserActivity();
1316 CHECK_MOUSE_BLOCKED
1318 QPointF pos = aEvent->pos();
1320 // we check against the widgets geometry, so use parent coordinates
1321 // for the check
1322 if (mWidget)
1323 pos = mWidget->mapToParent(pos);
1325 if (CheckForRollup( pos.x(), pos.y(), false))
1326 return nsEventStatus_eIgnore;
1328 uint16_t domButton;
1329 switch (aEvent->button()) {
1330 case Qt::MidButton:
1331 domButton = nsMouseEvent::eMiddleButton;
1332 break;
1333 case Qt::RightButton:
1334 domButton = nsMouseEvent::eRightButton;
1335 break;
1336 default:
1337 domButton = nsMouseEvent::eLeftButton;
1338 break;
1341 nsMouseEvent event(true, NS_MOUSE_BUTTON_DOWN, this, nsMouseEvent::eReal);
1342 event.button = domButton;
1343 InitButtonEvent(event, aEvent, 1);
1345 LOG(("%s [%p] button: %d\n", __PRETTY_FUNCTION__, (void*)this, domButton));
1347 nsEventStatus status = DispatchEvent(&event);
1349 // right menu click on linux should also pop up a context menu
1350 if (domButton == nsMouseEvent::eRightButton &&
1351 MOZ_LIKELY(!mIsDestroyed)) {
1352 nsMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this,
1353 nsMouseEvent::eReal);
1354 InitButtonEvent(contextMenuEvent, aEvent, 1);
1355 DispatchEvent(&contextMenuEvent, status);
1358 return status;
1361 nsEventStatus
1362 nsWindow::OnButtonReleaseEvent(QGraphicsSceneMouseEvent *aEvent)
1364 UserActivity();
1365 CHECK_MOUSE_BLOCKED
1367 // The user has done something.
1368 UserActivity();
1370 uint16_t domButton;
1372 switch (aEvent->button()) {
1373 case Qt::MidButton:
1374 domButton = nsMouseEvent::eMiddleButton;
1375 break;
1376 case Qt::RightButton:
1377 domButton = nsMouseEvent::eRightButton;
1378 break;
1379 default:
1380 domButton = nsMouseEvent::eLeftButton;
1381 break;
1384 LOG(("%s [%p] button: %d\n", __PRETTY_FUNCTION__, (void*)this, domButton));
1386 nsMouseEvent event(true, NS_MOUSE_BUTTON_UP, this, nsMouseEvent::eReal);
1387 event.button = domButton;
1388 InitButtonEvent(event, aEvent, 1);
1390 nsEventStatus status = DispatchEvent(&event);
1392 return status;
1395 nsEventStatus
1396 nsWindow::OnMouseDoubleClickEvent(QGraphicsSceneMouseEvent *aEvent)
1398 uint32_t eventType;
1400 switch (aEvent->button()) {
1401 case Qt::MidButton:
1402 eventType = nsMouseEvent::eMiddleButton;
1403 break;
1404 case Qt::RightButton:
1405 eventType = nsMouseEvent::eRightButton;
1406 break;
1407 default:
1408 eventType = nsMouseEvent::eLeftButton;
1409 break;
1412 nsMouseEvent event(true, NS_MOUSE_DOUBLECLICK, this, nsMouseEvent::eReal);
1413 event.button = eventType;
1415 InitButtonEvent(event, aEvent, 2);
1416 //pressed
1417 return DispatchEvent(&event);
1420 nsEventStatus
1421 nsWindow::OnFocusInEvent(QEvent *aEvent)
1423 LOGFOCUS(("OnFocusInEvent [%p]\n", (void *)this));
1425 if (!mWidget)
1426 return nsEventStatus_eIgnore;
1428 DispatchActivateEventOnTopLevelWindow();
1430 LOGFOCUS(("Events sent from focus in event [%p]\n", (void *)this));
1431 return nsEventStatus_eIgnore;
1434 nsEventStatus
1435 nsWindow::OnFocusOutEvent(QEvent *aEvent)
1437 LOGFOCUS(("OnFocusOutEvent [%p]\n", (void *)this));
1439 if (!mWidget)
1440 return nsEventStatus_eIgnore;
1442 DispatchDeactivateEventOnTopLevelWindow();
1444 LOGFOCUS(("Done with container focus out [%p]\n", (void *)this));
1445 return nsEventStatus_eIgnore;
1448 inline bool
1449 is_latin_shortcut_key(quint32 aKeyval)
1451 return ((Qt::Key_0 <= aKeyval && aKeyval <= Qt::Key_9) ||
1452 (Qt::Key_A <= aKeyval && aKeyval <= Qt::Key_Z));
1455 nsEventStatus
1456 nsWindow::DispatchCommandEvent(nsIAtom* aCommand)
1458 nsCommandEvent event(true, nsGkAtoms::onAppCommand, aCommand, this);
1460 nsEventStatus status;
1461 DispatchEvent(&event, status);
1463 return status;
1466 nsEventStatus
1467 nsWindow::DispatchContentCommandEvent(int32_t aMsg)
1469 nsContentCommandEvent event(true, aMsg, this);
1471 nsEventStatus status;
1472 DispatchEvent(&event, status);
1474 return status;
1477 nsEventStatus
1478 nsWindow::OnKeyPressEvent(QKeyEvent *aEvent)
1480 LOGFOCUS(("OnKeyPressEvent [%p]\n", (void *)this));
1482 // The user has done something.
1483 UserActivity();
1485 if (aEvent->key() == Qt::Key_AltGr) {
1486 sAltGrModifier = true;
1489 #ifdef MOZ_X11
1490 // before we dispatch a key, check if it's the context menu key.
1491 // If so, send a context menu key event instead.
1492 if (isContextMenuKeyEvent(aEvent)) {
1493 nsMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this,
1494 nsMouseEvent::eReal,
1495 nsMouseEvent::eContextMenuKey);
1496 //keyEventToContextMenuEvent(&event, &contextMenuEvent);
1497 return DispatchEvent(&contextMenuEvent);
1500 uint32_t domCharCode = 0;
1501 uint32_t domKeyCode = QtKeyCodeToDOMKeyCode(aEvent->key());
1503 // get keymap and modifier map from the Xserver
1504 Display *display = mozilla::DefaultXDisplay();
1505 int x_min_keycode = 0, x_max_keycode = 0, xkeysyms_per_keycode;
1506 XDisplayKeycodes(display, &x_min_keycode, &x_max_keycode);
1507 XModifierKeymap *xmodmap = XGetModifierMapping(display);
1508 if (!xmodmap)
1509 return nsEventStatus_eIgnore;
1511 KeySym *xkeymap = XGetKeyboardMapping(display, x_min_keycode, x_max_keycode - x_min_keycode,
1512 &xkeysyms_per_keycode);
1513 if (!xkeymap) {
1514 XFreeModifiermap(xmodmap);
1515 return nsEventStatus_eIgnore;
1518 // create modifier masks
1519 qint32 shift_mask = 0, shift_lock_mask = 0, caps_lock_mask = 0, num_lock_mask = 0;
1521 for (int i = 0; i < 8 * xmodmap->max_keypermod; ++i) {
1522 qint32 maskbit = 1 << (i / xmodmap->max_keypermod);
1523 KeyCode modkeycode = xmodmap->modifiermap[i];
1524 if (modkeycode == NoSymbol) {
1525 continue;
1528 quint32 mapindex = (modkeycode - x_min_keycode) * xkeysyms_per_keycode;
1529 for (int j = 0; j < xkeysyms_per_keycode; ++j) {
1530 KeySym modkeysym = xkeymap[mapindex + j];
1531 switch (modkeysym) {
1532 case XK_Num_Lock:
1533 num_lock_mask |= maskbit;
1534 break;
1535 case XK_Caps_Lock:
1536 caps_lock_mask |= maskbit;
1537 break;
1538 case XK_Shift_Lock:
1539 shift_lock_mask |= maskbit;
1540 break;
1541 case XK_Shift_L:
1542 case XK_Shift_R:
1543 shift_mask |= maskbit;
1544 break;
1548 // indicate whether is down or not
1549 bool shift_state = ((shift_mask & aEvent->nativeModifiers()) != 0) ^
1550 (bool)(shift_lock_mask & aEvent->nativeModifiers());
1551 bool capslock_state = (bool)(caps_lock_mask & aEvent->nativeModifiers());
1553 // try to find a keysym that we can translate to a DOMKeyCode
1554 // this is needed because some of Qt's keycodes cannot be translated
1555 // TODO: use US keyboard keymap instead of localised keymap
1556 if (!domKeyCode &&
1557 aEvent->nativeScanCode() >= (quint32)x_min_keycode &&
1558 aEvent->nativeScanCode() <= (quint32)x_max_keycode) {
1559 int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode;
1560 for(int i = 0; (i < xkeysyms_per_keycode) && (domKeyCode == (quint32)NoSymbol); ++i) {
1561 domKeyCode = QtKeyCodeToDOMKeyCode(xkeymap[index + i]);
1565 // store character in domCharCode
1566 if (aEvent->text().length() && aEvent->text()[0].isPrint())
1567 domCharCode = (int32_t) aEvent->text()[0].unicode();
1569 KeyNameIndex keyNameIndex =
1570 domCharCode ? KEY_NAME_INDEX_PrintableKey :
1571 QtKeyCodeToDOMKeyNameIndex(aEvent->key());
1573 // If the key isn't autorepeat, we need to send the initial down event
1574 if (!aEvent->isAutoRepeat() && !IsKeyDown(domKeyCode)) {
1575 // send the key down event
1577 SetKeyDownFlag(domKeyCode);
1579 nsKeyEvent downEvent(true, NS_KEY_DOWN, this);
1580 InitKeyEvent(downEvent, aEvent);
1582 downEvent.keyCode = domKeyCode;
1583 downEvent.mKeyNameIndex = keyNameIndex;
1585 nsEventStatus status = DispatchEvent(&downEvent);
1587 // DispatchEvent can Destroy us (bug 378273)
1588 if (MOZ_UNLIKELY(mIsDestroyed)) {
1589 qWarning() << "Returning[" << __LINE__ << "]: " << "Window destroyed";
1590 return status;
1593 // If prevent default on keydown, don't dispatch keypress event
1594 if (status == nsEventStatus_eConsumeNoDefault) {
1595 return nsEventStatus_eConsumeNoDefault;
1599 // Don't pass modifiers as NS_KEY_PRESS events.
1600 // Instead of selectively excluding some keys from NS_KEY_PRESS events,
1601 // we instead selectively include (as per MSDN spec
1602 // ( http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keypress%28VS.71%29.aspx );
1603 // no official spec covers KeyPress events).
1604 if (aEvent->key() == Qt::Key_Shift ||
1605 aEvent->key() == Qt::Key_Control ||
1606 aEvent->key() == Qt::Key_Meta ||
1607 aEvent->key() == Qt::Key_Alt ||
1608 aEvent->key() == Qt::Key_AltGr) {
1610 return nsEventStatus_eIgnore;
1613 // Look for specialized app-command keys
1614 switch (aEvent->key()) {
1615 case Qt::Key_Back:
1616 return DispatchCommandEvent(nsGkAtoms::Back);
1617 case Qt::Key_Forward:
1618 return DispatchCommandEvent(nsGkAtoms::Forward);
1619 case Qt::Key_Refresh:
1620 return DispatchCommandEvent(nsGkAtoms::Reload);
1621 case Qt::Key_Stop:
1622 return DispatchCommandEvent(nsGkAtoms::Stop);
1623 case Qt::Key_Search:
1624 return DispatchCommandEvent(nsGkAtoms::Search);
1625 case Qt::Key_Favorites:
1626 return DispatchCommandEvent(nsGkAtoms::Bookmarks);
1627 case Qt::Key_HomePage:
1628 return DispatchCommandEvent(nsGkAtoms::Home);
1629 case Qt::Key_Copy:
1630 case Qt::Key_F16: // F16, F20, F18, F14 are old keysyms for Copy Cut Paste Undo
1631 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_COPY);
1632 case Qt::Key_Cut:
1633 case Qt::Key_F20:
1634 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_CUT);
1635 case Qt::Key_Paste:
1636 case Qt::Key_F18:
1637 case Qt::Key_F9:
1638 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_PASTE);
1639 case Qt::Key_F14:
1640 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_UNDO);
1643 // Qt::Key_Redo and Qt::Key_Undo are not available yet.
1644 if (aEvent->nativeVirtualKey() == 0xff66) {
1645 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_REDO);
1647 if (aEvent->nativeVirtualKey() == 0xff65) {
1648 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_UNDO);
1651 nsKeyEvent event(true, NS_KEY_PRESS, this);
1652 InitKeyEvent(event, aEvent);
1654 // If there is no charcode attainable from the text, try to
1655 // generate it from the keycode. Check shift state for case
1656 // Also replace the charcode if ControlModifier is the only
1657 // pressed Modifier
1658 if ((!domCharCode) &&
1659 (QApplication::keyboardModifiers() &
1660 (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) {
1662 // get a character from X11 key map
1663 KeySym keysym = aEvent->nativeVirtualKey();
1664 if (keysym) {
1665 domCharCode = (uint32_t) keysym2ucs(keysym);
1666 if (domCharCode == -1 || !QChar((quint32)domCharCode).isPrint()) {
1667 domCharCode = 0;
1671 // if Ctrl is pressed and domCharCode is not a ASCII character
1672 if (domCharCode > 0xFF && (QApplication::keyboardModifiers() & Qt::ControlModifier)) {
1673 // replace Unicode character
1674 int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode;
1675 for (int i = 0; i < xkeysyms_per_keycode; ++i) {
1676 if (xkeymap[index + i] <= 0xFF && !shift_state) {
1677 domCharCode = (uint32_t) QChar::toLower((uint) xkeymap[index + i]);
1678 break;
1683 } else { // The key event should cause a character input.
1684 // At that time, we need to reset the modifiers
1685 // because nsEditor will not accept a key event
1686 // for text input if one or more modifiers are set.
1687 event.modifiers &= ~(widget::MODIFIER_CONTROL |
1688 widget::MODIFIER_ALT |
1689 widget::MODIFIER_META);
1692 KeySym keysym = NoSymbol;
1693 int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode;
1694 for (int i = 0; i < xkeysyms_per_keycode; ++i) {
1695 if (xkeymap[index + i] == aEvent->nativeVirtualKey()) {
1696 if ((i % 2) == 0) { // shifted char
1697 keysym = xkeymap[index + i + 1];
1698 break;
1699 } else { // unshifted char
1700 keysym = xkeymap[index + i - 1];
1701 break;
1704 if (xkeysyms_per_keycode - 1 == i) {
1705 qWarning() << "Symbol '" << aEvent->nativeVirtualKey() << "' not found";
1708 QChar unshiftedChar(domCharCode);
1709 long ucs = keysym2ucs(keysym);
1710 ucs = ucs == -1 ? 0 : ucs;
1711 QChar shiftedChar((uint)ucs);
1713 // append alternativeCharCodes if modifier is pressed
1714 // append an additional alternativeCharCodes if domCharCode is not a Latin character
1715 // and if one of these modifiers is pressed (i.e. Ctrl, Alt, Meta)
1716 if (domCharCode &&
1717 (QApplication::keyboardModifiers() &
1718 (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) {
1720 event.charCode = domCharCode;
1721 event.keyCode = 0;
1722 nsAlternativeCharCode altCharCode(0, 0);
1723 // if character has a lower and upper representation
1724 if ((unshiftedChar.isUpper() || unshiftedChar.isLower()) &&
1725 unshiftedChar.toLower() == shiftedChar.toLower()) {
1726 if (shift_state ^ capslock_state) {
1727 altCharCode.mUnshiftedCharCode = (uint32_t) QChar::toUpper((uint)domCharCode);
1728 altCharCode.mShiftedCharCode = (uint32_t) QChar::toLower((uint)domCharCode);
1729 } else {
1730 altCharCode.mUnshiftedCharCode = (uint32_t) QChar::toLower((uint)domCharCode);
1731 altCharCode.mShiftedCharCode = (uint32_t) QChar::toUpper((uint)domCharCode);
1733 } else {
1734 altCharCode.mUnshiftedCharCode = (uint32_t) unshiftedChar.unicode();
1735 altCharCode.mShiftedCharCode = (uint32_t) shiftedChar.unicode();
1738 // append alternative char code to event
1739 if ((altCharCode.mUnshiftedCharCode && altCharCode.mUnshiftedCharCode != domCharCode) ||
1740 (altCharCode.mShiftedCharCode && altCharCode.mShiftedCharCode != domCharCode)) {
1741 event.alternativeCharCodes.AppendElement(altCharCode);
1744 // check if the alternative char codes are latin-1
1745 if (altCharCode.mUnshiftedCharCode > 0xFF || altCharCode.mShiftedCharCode > 0xFF) {
1746 altCharCode.mUnshiftedCharCode = altCharCode.mShiftedCharCode = 0;
1748 // find latin char for keycode
1749 KeySym keysym = NoSymbol;
1750 int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode;
1751 // find first shifted and unshifted Latin-Char in XKeyMap
1752 for (int i = 0; i < xkeysyms_per_keycode; ++i) {
1753 keysym = xkeymap[index + i];
1754 if (keysym && keysym <= 0xFF) {
1755 if ((shift_state && (i % 2 == 1)) ||
1756 (!shift_state && (i % 2 == 0))) {
1757 altCharCode.mUnshiftedCharCode = altCharCode.mUnshiftedCharCode ?
1758 altCharCode.mUnshiftedCharCode :
1759 keysym;
1760 } else {
1761 altCharCode.mShiftedCharCode = altCharCode.mShiftedCharCode ?
1762 altCharCode.mShiftedCharCode :
1763 keysym;
1765 if (altCharCode.mUnshiftedCharCode && altCharCode.mShiftedCharCode) {
1766 break;
1771 if (altCharCode.mUnshiftedCharCode || altCharCode.mShiftedCharCode) {
1772 event.alternativeCharCodes.AppendElement(altCharCode);
1775 } else {
1776 event.charCode = domCharCode;
1779 if (xmodmap) {
1780 XFreeModifiermap(xmodmap);
1782 if (xkeymap) {
1783 XFree(xkeymap);
1786 event.keyCode = domCharCode ? 0 : domKeyCode;
1787 event.mKeyNameIndex = keyNameIndex;
1788 // send the key press event
1789 return DispatchEvent(&event);
1790 #else
1792 //:TODO: fix shortcuts hebrew for non X11,
1793 //see Bug 562195##51
1795 // before we dispatch a key, check if it's the context menu key.
1796 // If so, send a context menu key event instead.
1797 if (isContextMenuKeyEvent(aEvent)) {
1798 nsMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this,
1799 nsMouseEvent::eReal,
1800 nsMouseEvent::eContextMenuKey);
1801 //keyEventToContextMenuEvent(&event, &contextMenuEvent);
1802 return DispatchEvent(&contextMenuEvent);
1805 uint32_t domCharCode = 0;
1806 uint32_t domKeyCode = QtKeyCodeToDOMKeyCode(aEvent->key());
1808 if (aEvent->text().length() && aEvent->text()[0].isPrint())
1809 domCharCode = (int32_t) aEvent->text()[0].unicode();
1811 KeyNameIndex keyNameIndex =
1812 domCharCode ? KEY_NAME_INDEX_PrintableKey :
1813 QtKeyCodeToDOMKeyNameIndex(aEvent->key());
1815 // If the key isn't autorepeat, we need to send the initial down event
1816 if (!aEvent->isAutoRepeat() && !IsKeyDown(domKeyCode)) {
1817 // send the key down event
1819 SetKeyDownFlag(domKeyCode);
1821 nsKeyEvent downEvent(true, NS_KEY_DOWN, this);
1822 InitKeyEvent(downEvent, aEvent);
1824 downEvent.keyCode = domKeyCode;
1825 downEvent.mKeyNameIndex = keyNameIndex;
1827 nsEventStatus status = DispatchEvent(&downEvent);
1829 // If prevent default on keydown, don't dispatch keypress event
1830 if (status == nsEventStatus_eConsumeNoDefault) {
1831 return nsEventStatus_eConsumeNoDefault;
1835 nsKeyEvent event(true, NS_KEY_PRESS, this);
1836 InitKeyEvent(event, aEvent);
1838 event.charCode = domCharCode;
1840 event.keyCode = domCharCode ? 0 : domKeyCode;
1841 event.mKeyNameIndex = keyNameIndex;
1843 // send the key press event
1844 return DispatchEvent(&event);
1845 #endif
1848 nsEventStatus
1849 nsWindow::OnKeyReleaseEvent(QKeyEvent *aEvent)
1851 LOGFOCUS(("OnKeyReleaseEvent [%p]\n", (void *)this));
1853 // The user has done something.
1854 UserActivity();
1856 if (isContextMenuKeyEvent(aEvent)) {
1857 // er, what do we do here? DoDefault or NoDefault?
1858 return nsEventStatus_eConsumeDoDefault;
1861 uint32_t domKeyCode = QtKeyCodeToDOMKeyCode(aEvent->key());
1863 #ifdef MOZ_X11
1864 if (!domKeyCode) {
1865 // get keymap from the Xserver
1866 Display *display = mozilla::DefaultXDisplay();
1867 int x_min_keycode = 0, x_max_keycode = 0, xkeysyms_per_keycode;
1868 XDisplayKeycodes(display, &x_min_keycode, &x_max_keycode);
1869 KeySym *xkeymap = XGetKeyboardMapping(display, x_min_keycode, x_max_keycode - x_min_keycode,
1870 &xkeysyms_per_keycode);
1872 if (aEvent->nativeScanCode() >= (quint32)x_min_keycode &&
1873 aEvent->nativeScanCode() <= (quint32)x_max_keycode) {
1874 int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode;
1875 for(int i = 0; (i < xkeysyms_per_keycode) && (domKeyCode == (quint32)NoSymbol); ++i) {
1876 domKeyCode = QtKeyCodeToDOMKeyCode(xkeymap[index + i]);
1880 if (xkeymap) {
1881 XFree(xkeymap);
1884 #endif // MOZ_X11
1886 // send the key event as a key up event
1887 nsKeyEvent event(true, NS_KEY_UP, this);
1888 InitKeyEvent(event, aEvent);
1890 if (aEvent->key() == Qt::Key_AltGr) {
1891 sAltGrModifier = false;
1894 event.keyCode = domKeyCode;
1895 event.mKeyNameIndex =
1896 (aEvent->text().length() && aEvent->text()[0].isPrint()) ?
1897 KEY_NAME_INDEX_PrintableKey :
1898 QtKeyCodeToDOMKeyNameIndex(aEvent->key());
1900 // unset the key down flag
1901 ClearKeyDownFlag(event.keyCode);
1903 return DispatchEvent(&event);
1906 nsEventStatus
1907 nsWindow::OnScrollEvent(QGraphicsSceneWheelEvent *aEvent)
1909 // check to see if we should rollup
1910 WheelEvent wheelEvent(true, NS_WHEEL_WHEEL, this);
1911 wheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE;
1913 // negative values for aEvent->delta indicate downward scrolling;
1914 // this is opposite Gecko usage.
1915 // TODO: Store the unused delta values due to fraction round and add it
1916 // to next event. The stored values should be reset by other
1917 // direction scroll event.
1918 int32_t delta = (int)(aEvent->delta() / WHEEL_DELTA) * -3;
1920 switch (aEvent->orientation()) {
1921 case Qt::Vertical:
1922 wheelEvent.deltaY = wheelEvent.lineOrPageDeltaY = delta;
1923 break;
1924 case Qt::Horizontal:
1925 wheelEvent.deltaX = wheelEvent.lineOrPageDeltaX = delta;
1926 break;
1927 default:
1928 Q_ASSERT(0);
1929 break;
1932 wheelEvent.refPoint.x = nscoord(aEvent->scenePos().x());
1933 wheelEvent.refPoint.y = nscoord(aEvent->scenePos().y());
1935 wheelEvent.InitBasicModifiers(aEvent->modifiers() & Qt::ControlModifier,
1936 aEvent->modifiers() & Qt::AltModifier,
1937 aEvent->modifiers() & Qt::ShiftModifier,
1938 aEvent->modifiers() & Qt::MetaModifier);
1939 wheelEvent.time = 0;
1941 return DispatchEvent(&wheelEvent);
1945 nsEventStatus
1946 nsWindow::showEvent(QShowEvent *)
1948 LOG(("%s [%p]\n", __PRETTY_FUNCTION__,(void *)this));
1949 mIsVisible = true;
1950 return nsEventStatus_eConsumeDoDefault;
1953 nsEventStatus
1954 nsWindow::hideEvent(QHideEvent *)
1956 LOG(("%s [%p]\n", __PRETTY_FUNCTION__,(void *)this));
1957 mIsVisible = false;
1958 return nsEventStatus_eConsumeDoDefault;
1961 //Gestures are only supported in 4.6.0 >
1962 #if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0))
1963 nsEventStatus nsWindow::OnTouchEvent(QTouchEvent *event, bool &handled)
1965 handled = false;
1966 const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
1968 if (event->type() == QEvent::TouchBegin) {
1969 handled = true;
1970 for (int i = touchPoints.count() -1; i >= 0; i--) {
1971 QPointF fpos = touchPoints[i].pos();
1972 nsGestureNotifyEvent gestureNotifyEvent(true, NS_GESTURENOTIFY_EVENT_START, this);
1973 gestureNotifyEvent.refPoint = LayoutDeviceIntPoint(fpos.x(), fpos.y());
1974 DispatchEvent(&gestureNotifyEvent);
1977 else if (event->type() == QEvent::TouchEnd) {
1978 mGesturesCancelled = false;
1979 mPinchEvent.needDispatch = false;
1982 if (touchPoints.count() > 0) {
1983 // Remember start touch point in order to use it for
1984 // distance calculation in NS_SIMPLE_GESTURE_MAGNIFY_UPDATE
1985 mPinchEvent.touchPoint = touchPoints.at(0).pos();
1988 return nsEventStatus_eIgnore;
1991 nsEventStatus
1992 nsWindow::OnGestureEvent(QGestureEvent* event, bool &handled) {
1994 handled = false;
1995 if (mGesturesCancelled) {
1996 return nsEventStatus_eIgnore;
1999 nsEventStatus result = nsEventStatus_eIgnore;
2001 QGesture* gesture = event->gesture(Qt::PinchGesture);
2003 if (gesture) {
2004 QPinchGesture* pinch = static_cast<QPinchGesture*>(gesture);
2005 handled = true;
2007 mPinchEvent.centerPoint =
2008 mWidget->mapFromScene(event->mapToGraphicsScene(pinch->centerPoint()));
2009 nsIntPoint centerPoint(mPinchEvent.centerPoint.x(),
2010 mPinchEvent.centerPoint.y());
2012 if (pinch->state() == Qt::GestureStarted) {
2013 event->accept();
2014 mPinchEvent.startDistance = DistanceBetweenPoints(mPinchEvent.centerPoint, mPinchEvent.touchPoint) * 2;
2015 mPinchEvent.prevDistance = mPinchEvent.startDistance;
2016 result = DispatchGestureEvent(NS_SIMPLE_GESTURE_MAGNIFY_START,
2017 0, 0, centerPoint);
2019 else if (pinch->state() == Qt::GestureUpdated) {
2020 mPinchEvent.needDispatch = true;
2021 mPinchEvent.delta = 0;
2022 DispatchMotionToMainThread();
2024 else if (pinch->state() == Qt::GestureFinished) {
2025 double distance = DistanceBetweenPoints(mPinchEvent.centerPoint, mPinchEvent.touchPoint) * 2;
2026 double delta = distance - mPinchEvent.startDistance;
2027 result = DispatchGestureEvent(NS_SIMPLE_GESTURE_MAGNIFY,
2028 0, delta, centerPoint);
2029 mPinchEvent.needDispatch = false;
2031 else {
2032 handled = false;
2035 //Disable mouse events when gestures are used, because they cause problems with
2036 //Fennec
2037 mLastMultiTouchTime.start();
2040 gesture = event->gesture(gSwipeGestureId);
2041 if (gesture) {
2042 if (gesture->state() == Qt::GestureStarted) {
2043 event->accept();
2045 if (gesture->state() == Qt::GestureFinished) {
2046 event->accept();
2047 handled = true;
2049 MozSwipeGesture* swipe = static_cast<MozSwipeGesture*>(gesture);
2050 nsIntPoint hotspot;
2051 hotspot.x = swipe->hotSpot().x();
2052 hotspot.y = swipe->hotSpot().y();
2054 // Cancel pinch gesture
2055 mGesturesCancelled = true;
2056 mPinchEvent.needDispatch = false;
2058 double distance = DistanceBetweenPoints(swipe->hotSpot(), mPinchEvent.touchPoint) * 2;
2059 double delta = distance - mPinchEvent.startDistance;
2061 DispatchGestureEvent(NS_SIMPLE_GESTURE_MAGNIFY, 0, delta / 2, hotspot);
2063 result = DispatchGestureEvent(NS_SIMPLE_GESTURE_SWIPE,
2064 swipe->Direction(), 0, hotspot);
2066 mLastMultiTouchTime.start();
2069 return result;
2072 nsEventStatus
2073 nsWindow::DispatchGestureEvent(uint32_t aMsg, uint32_t aDirection,
2074 double aDelta, const nsIntPoint& aRefPoint)
2076 nsSimpleGestureEvent mozGesture(true, aMsg, this, 0, 0.0);
2077 mozGesture.direction = aDirection;
2078 mozGesture.delta = aDelta;
2079 mozGesture.refPoint = LayoutDeviceIntPoint::FromUntyped(aRefPoint);
2081 Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers();
2083 mozGesture.InitBasicModifiers(modifiers & Qt::ControlModifier,
2084 modifiers & Qt::AltModifier,
2085 modifiers & Qt::ShiftModifier,
2086 false);
2087 mozGesture.button = 0;
2088 mozGesture.time = 0;
2090 return DispatchEvent(&mozGesture);
2094 double
2095 nsWindow::DistanceBetweenPoints(const QPointF &aFirstPoint, const QPointF &aSecondPoint)
2097 double result = 0;
2098 double deltaX = abs(aFirstPoint.x() - aSecondPoint.x());
2099 double deltaY = abs(aFirstPoint.y() - aSecondPoint.y());
2100 result = sqrt(deltaX*deltaX + deltaY*deltaY);
2101 return result;
2104 #endif //qt version check
2106 void
2107 nsWindow::ThemeChanged()
2109 NotifyThemeChanged();
2112 nsEventStatus
2113 nsWindow::OnDragMotionEvent(QGraphicsSceneDragDropEvent *aEvent)
2115 LOG(("nsWindow::OnDragMotionSignal\n"));
2117 nsMouseEvent event(true, NS_DRAGDROP_OVER, 0,
2118 nsMouseEvent::eReal);
2119 return nsEventStatus_eIgnore;
2122 nsEventStatus
2123 nsWindow::OnDragLeaveEvent(QGraphicsSceneDragDropEvent *aEvent)
2125 // XXX Do we want to pass this on only if the event's subwindow is null?
2126 LOG(("nsWindow::OnDragLeaveSignal(%p)\n", this));
2127 nsMouseEvent event(true, NS_DRAGDROP_EXIT, this, nsMouseEvent::eReal);
2129 return DispatchEvent(&event);
2132 nsEventStatus
2133 nsWindow::OnDragDropEvent(QGraphicsSceneDragDropEvent *aDropEvent)
2135 if (aDropEvent->proposedAction() == Qt::CopyAction)
2137 printf("text version of the data: %s\n", aDropEvent->mimeData()->text().toUtf8().data());
2138 aDropEvent->acceptProposedAction();
2141 LOG(("nsWindow::OnDragDropSignal\n"));
2142 nsMouseEvent event(true, NS_DRAGDROP_OVER, 0,
2143 nsMouseEvent::eReal);
2144 return nsEventStatus_eIgnore;
2147 nsEventStatus
2148 nsWindow::OnDragEnter(QGraphicsSceneDragDropEvent *aDragEvent)
2150 // Is it some format we think we can support?
2151 if ( aDragEvent->mimeData()->hasFormat(kURLMime)
2152 || aDragEvent->mimeData()->hasFormat(kURLDataMime)
2153 || aDragEvent->mimeData()->hasFormat(kURLDescriptionMime)
2154 || aDragEvent->mimeData()->hasFormat(kHTMLMime)
2155 || aDragEvent->mimeData()->hasFormat(kUnicodeMime)
2156 || aDragEvent->mimeData()->hasFormat(kTextMime)
2159 aDragEvent->acceptProposedAction();
2162 // XXX Do we want to pass this on only if the event's subwindow is null?
2164 LOG(("nsWindow::OnDragEnter(%p)\n", this));
2166 nsMouseEvent event(true, NS_DRAGDROP_ENTER, this, nsMouseEvent::eReal);
2167 return DispatchEvent(&event);
2170 static void
2171 GetBrandName(nsXPIDLString& brandName)
2173 nsCOMPtr<nsIStringBundleService> bundleService =
2174 mozilla::services::GetStringBundleService();
2176 nsCOMPtr<nsIStringBundle> bundle;
2177 if (bundleService)
2178 bundleService->CreateBundle(
2179 "chrome://branding/locale/brand.properties",
2180 getter_AddRefs(bundle));
2182 if (bundle)
2183 bundle->GetStringFromName(
2184 NS_LITERAL_STRING("brandShortName").get(),
2185 getter_Copies(brandName));
2187 if (brandName.IsEmpty())
2188 brandName.Assign(NS_LITERAL_STRING("Mozilla"));
2192 nsresult
2193 nsWindow::Create(nsIWidget *aParent,
2194 nsNativeWidget aNativeParent,
2195 const nsIntRect &aRect,
2196 nsDeviceContext *aContext,
2197 nsWidgetInitData *aInitData)
2199 // only set the base parent if we're not going to be a dialog or a
2200 // toplevel
2201 nsIWidget *baseParent = aParent;
2203 if (aInitData &&
2204 (aInitData->mWindowType == eWindowType_dialog ||
2205 aInitData->mWindowType == eWindowType_toplevel ||
2206 aInitData->mWindowType == eWindowType_invisible)) {
2208 baseParent = nullptr;
2209 // also drop native parent for toplevel windows
2210 aNativeParent = nullptr;
2213 // initialize all the common bits of this class
2214 BaseCreate(baseParent, aRect, aContext, aInitData);
2216 // and do our common creation
2217 mParent = aParent;
2219 // save our bounds
2220 mBounds = aRect;
2222 // find native parent
2223 MozQWidget *parent = nullptr;
2225 if (aParent != nullptr)
2226 parent = static_cast<MozQWidget*>(aParent->GetNativeData(NS_NATIVE_WIDGET));
2228 // ok, create our QGraphicsWidget
2229 mWidget = createQWidget(parent, aNativeParent, aInitData);
2231 if (!mWidget)
2232 return NS_ERROR_OUT_OF_MEMORY;
2234 LOG(("Create: nsWindow [%p] [%p]\n", (void *)this, (void *)mWidget));
2236 // resize so that everything is set to the right dimensions
2237 Resize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, false);
2239 // check if we should listen for resizes
2240 mListenForResizes = (aNativeParent ||
2241 (aInitData && aInitData->mListenForResizes));
2243 return NS_OK;
2246 already_AddRefed<nsIWidget>
2247 nsWindow::CreateChild(const nsIntRect& aRect,
2248 nsDeviceContext* aContext,
2249 nsWidgetInitData* aInitData,
2250 bool /*aForceUseIWidgetParent*/)
2252 //We need to force parent widget, otherwise GetTopLevelWindow doesn't work
2253 return nsBaseWidget::CreateChild(aRect,
2254 aContext,
2255 aInitData,
2256 true); // Force parent
2260 NS_IMETHODIMP
2261 nsWindow::SetWindowClass(const nsAString &xulWinType)
2263 if (!mWidget)
2264 return NS_ERROR_FAILURE;
2266 nsXPIDLString brandName;
2267 GetBrandName(brandName);
2269 #ifdef MOZ_X11
2270 XClassHint *class_hint = XAllocClassHint();
2271 if (!class_hint)
2272 return NS_ERROR_OUT_OF_MEMORY;
2273 const char *role = NULL;
2274 class_hint->res_name = ToNewCString(xulWinType);
2275 if (!class_hint->res_name) {
2276 XFree(class_hint);
2277 return NS_ERROR_OUT_OF_MEMORY;
2279 class_hint->res_class = ToNewCString(brandName);
2280 if (!class_hint->res_class) {
2281 nsMemory::Free(class_hint->res_name);
2282 XFree(class_hint);
2283 return NS_ERROR_OUT_OF_MEMORY;
2286 // Parse res_name into a name and role. Characters other than
2287 // [A-Za-z0-9_-] are converted to '_'. Anything after the first
2288 // colon is assigned to role; if there's no colon, assign the
2289 // whole thing to both role and res_name.
2290 for (char *c = class_hint->res_name; *c; c++) {
2291 if (':' == *c) {
2292 *c = 0;
2293 role = c + 1;
2295 else if (!isascii(*c) || (!isalnum(*c) && ('_' != *c) && ('-' != *c)))
2296 *c = '_';
2298 class_hint->res_name[0] = toupper(class_hint->res_name[0]);
2299 if (!role) role = class_hint->res_name;
2301 QWidget *widget = GetViewWidget();
2302 // If widget not show, handle might be null
2303 if (widget && widget->winId())
2304 XSetClassHint(gfxQtPlatform::GetXDisplay(widget),
2305 widget->winId(),
2306 class_hint);
2308 nsMemory::Free(class_hint->res_class);
2309 nsMemory::Free(class_hint->res_name);
2310 XFree(class_hint);
2311 #endif
2313 return NS_OK;
2316 void
2317 nsWindow::NativeResize(int32_t aWidth, int32_t aHeight, bool aRepaint)
2319 LOG(("nsWindow::NativeResize [%p] %d %d\n", (void *)this,
2320 aWidth, aHeight));
2322 mNeedsResize = false;
2324 if (mIsTopLevel) {
2325 QGraphicsView *widget = qobject_cast<QGraphicsView*>(GetViewWidget());
2326 NS_ENSURE_TRUE_VOID(widget);
2327 // map from in-scene widget to scene, from scene to view.
2328 QRect r = widget->mapFromScene(mWidget->mapToScene(QRect(0, 0, aWidth, aHeight))).boundingRect();
2329 // going from QPolygon to QRect includes the points, adding one to width and height
2330 r.adjust(0, 0, -1, -1);
2331 widget->resize(r.width(), r.height());
2333 else {
2334 mWidget->resize(aWidth, aHeight);
2337 if (aRepaint)
2338 mWidget->update();
2341 void
2342 nsWindow::NativeResize(int32_t aX, int32_t aY,
2343 int32_t aWidth, int32_t aHeight,
2344 bool aRepaint)
2346 LOG(("nsWindow::NativeResize [%p] %d %d %d %d\n", (void *)this,
2347 aX, aY, aWidth, aHeight));
2349 mNeedsResize = false;
2350 mNeedsMove = false;
2352 if (mIsTopLevel) {
2353 QGraphicsView *widget = qobject_cast<QGraphicsView*>(GetViewWidget());
2354 NS_ENSURE_TRUE_VOID(widget);
2355 // map from in-scene widget to scene, from scene to view.
2356 QRect r = widget->mapFromScene(mWidget->mapToScene(QRect(aX, aY, aWidth, aHeight))).boundingRect();
2357 // going from QPolygon to QRect includes the points, adding one to width and height
2358 r.adjust(0, 0, -1, -1);
2359 widget->setGeometry(r.x(), r.y(), r.width(), r.height());
2361 else {
2362 mWidget->setGeometry(aX, aY, aWidth, aHeight);
2365 if (aRepaint)
2366 mWidget->update();
2369 void
2370 nsWindow::NativeShow(bool aAction)
2372 if (aAction) {
2373 QWidget *widget = GetViewWidget();
2374 // On e10s, we never want the child process or plugin process
2375 // to go fullscreen because if we do the window because visible
2376 // do to disabled Qt-Xembed
2377 if (widget &&
2378 !widget->isVisible())
2379 MakeFullScreen(mSizeMode == nsSizeMode_Fullscreen);
2380 mWidget->show();
2382 // unset our flag now that our window has been shown
2383 mNeedsShow = false;
2385 else
2386 mWidget->hide();
2389 NS_IMETHODIMP
2390 nsWindow::SetHasTransparentBackground(bool aTransparent)
2392 return NS_ERROR_NOT_IMPLEMENTED;
2395 NS_IMETHODIMP
2396 nsWindow::GetHasTransparentBackground(bool& aTransparent)
2398 aTransparent = mIsTransparent;
2399 return NS_OK;
2402 void *
2403 nsWindow::SetupPluginPort(void)
2405 NS_WARNING("Not implemented");
2406 return nullptr;
2409 nsresult
2410 nsWindow::SetWindowIconList(const nsTArray<nsCString> &aIconList)
2412 QIcon icon;
2414 for (uint32_t i = 0; i < aIconList.Length(); ++i) {
2415 const char *path = aIconList[i].get();
2416 LOG(("window [%p] Loading icon from %s\n", (void *)this, path));
2417 icon.addFile(path);
2420 QWidget *widget = GetViewWidget();
2421 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
2422 widget->setWindowIcon(icon);
2424 return NS_OK;
2427 void
2428 nsWindow::SetDefaultIcon(void)
2430 SetIcon(NS_LITERAL_STRING("default"));
2433 void nsWindow::QWidgetDestroyed()
2435 mWidget = nullptr;
2438 NS_IMETHODIMP
2439 nsWindow::MakeFullScreen(bool aFullScreen)
2441 QWidget *widget = GetViewWidget();
2442 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
2443 if (aFullScreen) {
2444 if (mSizeMode != nsSizeMode_Fullscreen)
2445 mLastSizeMode = mSizeMode;
2447 mSizeMode = nsSizeMode_Fullscreen;
2448 widget->showFullScreen();
2450 else {
2451 mSizeMode = mLastSizeMode;
2453 switch (mSizeMode) {
2454 case nsSizeMode_Maximized:
2455 widget->showMaximized();
2456 break;
2457 case nsSizeMode_Minimized:
2458 widget->showMinimized();
2459 break;
2460 case nsSizeMode_Normal:
2461 widget->showNormal();
2462 break;
2463 default:
2464 widget->showNormal();
2465 break;
2469 NS_ASSERTION(mLastSizeMode != nsSizeMode_Fullscreen,
2470 "mLastSizeMode should never be fullscreen");
2471 return nsBaseWidget::MakeFullScreen(aFullScreen);
2474 NS_IMETHODIMP
2475 nsWindow::HideWindowChrome(bool aShouldHide)
2477 if (!mWidget) {
2478 // Nothing to hide
2479 return NS_ERROR_FAILURE;
2482 // Sawfish, metacity, and presumably other window managers get
2483 // confused if we change the window decorations while the window
2484 // is visible.
2485 bool wasVisible = false;
2486 if (mWidget->isVisible()) {
2487 NativeShow(false);
2488 wasVisible = true;
2491 if (wasVisible) {
2492 NativeShow(true);
2495 // For some window managers, adding or removing window decorations
2496 // requires unmapping and remapping our toplevel window. Go ahead
2497 // and flush the queue here so that we don't end up with a BadWindow
2498 // error later when this happens (when the persistence timer fires
2499 // and GetWindowPos is called)
2500 QWidget *widget = GetViewWidget();
2501 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
2502 #ifdef MOZ_X11
2503 XSync(gfxQtPlatform::GetXDisplay(widget), False);
2504 #endif
2506 return NS_OK;
2509 //////////////////////////////////////////////////////////////////////
2510 // These are all of our drag and drop operations
2512 void
2513 nsWindow::InitDragEvent(nsMouseEvent &aEvent)
2515 // set the keyboard modifiers
2518 // This will update the drag action based on the information in the
2519 // drag context.
2521 /* static */
2522 nsresult
2523 initialize_prefs(void)
2525 // check to see if we should set our raise pref
2526 return NS_OK;
2529 inline bool
2530 is_context_menu_key(const nsKeyEvent& aKeyEvent)
2532 return ((aKeyEvent.keyCode == NS_VK_F10 && aKeyEvent.IsShift() &&
2533 !aKeyEvent.IsControl() && !aKeyEvent.IsMeta() &&
2534 !aKeyEvent.IsAlt()) ||
2535 (aKeyEvent.keyCode == NS_VK_CONTEXT_MENU && !aKeyEvent.IsShift() &&
2536 !aKeyEvent.IsControl() && !aKeyEvent.IsMeta() &&
2537 !aKeyEvent.IsAlt()));
2540 void
2541 key_event_to_context_menu_event(nsMouseEvent &aEvent,
2542 QKeyEvent *aGdkEvent)
2544 aEvent.refPoint = LayoutDeviceIntPoint(0, 0);
2545 aEvent.modifiers = 0;
2546 aEvent.time = 0;
2547 aEvent.clickCount = 1;
2550 // nsChildWindow class
2552 nsChildWindow::nsChildWindow()
2556 nsChildWindow::~nsChildWindow()
2560 nsPopupWindow::nsPopupWindow()
2562 #ifdef DEBUG_WIDGETS
2563 qDebug("===================== popup!");
2564 #endif
2567 nsPopupWindow::~nsPopupWindow()
2571 NS_IMETHODIMP_(bool)
2572 nsWindow::HasGLContext()
2574 return MozQGLWidgetWrapper::hasGLContext(qobject_cast<QGraphicsView*>(GetViewWidget()));
2577 MozQWidget*
2578 nsWindow::createQWidget(MozQWidget *parent,
2579 nsNativeWidget nativeParent,
2580 nsWidgetInitData *aInitData)
2582 const char *windowName = NULL;
2583 Qt::WindowFlags flags = Qt::Widget;
2584 QWidget *parentWidget = (parent && parent->getReceiver()) ?
2585 parent->getReceiver()->GetViewWidget() : nullptr;
2587 #ifdef DEBUG_WIDGETS
2588 qDebug("NEW WIDGET\n\tparent is %p (%s)", (void*)parent,
2589 parent ? qPrintable(parent->objectName()) : "null");
2590 #endif
2592 // ok, create our windows
2593 switch (mWindowType) {
2594 case eWindowType_dialog:
2595 windowName = "topLevelDialog";
2596 mIsTopLevel = true;
2597 flags |= Qt::Dialog;
2598 break;
2599 case eWindowType_popup:
2600 windowName = "topLevelPopup";
2601 break;
2602 case eWindowType_toplevel:
2603 windowName = "topLevelWindow";
2604 mIsTopLevel = true;
2605 break;
2606 case eWindowType_invisible:
2607 windowName = "topLevelInvisible";
2608 break;
2609 case eWindowType_child:
2610 case eWindowType_plugin:
2611 default: // sheet
2612 windowName = "paintArea";
2613 break;
2616 MozQWidget* parentQWidget = nullptr;
2617 if (parent) {
2618 parentQWidget = parent;
2619 } else if (nativeParent && nativeParent != PARENTLESS_WIDGET) {
2620 parentQWidget = static_cast<MozQWidget*>(nativeParent);
2622 MozQWidget * widget = new MozQWidget(this, parentQWidget);
2623 if (!widget)
2624 return nullptr;
2625 widget->setObjectName(QString(windowName));
2627 // make only child and plugin windows focusable
2628 if (eWindowType_child == mWindowType || eWindowType_plugin == mWindowType) {
2629 widget->setFlag(QGraphicsItem::ItemIsFocusable);
2630 widget->setFocusPolicy(Qt::WheelFocus);
2633 // create a QGraphicsView if this is a new toplevel window
2635 if (mIsTopLevel) {
2636 QGraphicsView* newView =
2637 nsFastStartup::GetStartupGraphicsView(parentWidget, widget);
2639 if (mWindowType == eWindowType_dialog) {
2640 newView->setWindowModality(Qt::WindowModal);
2643 if (gfxQtPlatform::GetPlatform()->GetRenderMode() == gfxQtPlatform::RENDER_DIRECT) {
2644 // Disable double buffer and system background rendering
2645 #if defined(MOZ_X11) && (QT_VERSION < QT_VERSION_CHECK(5,0,0))
2646 newView->viewport()->setAttribute(Qt::WA_PaintOnScreen, true);
2647 #endif
2648 newView->viewport()->setAttribute(Qt::WA_NoSystemBackground, true);
2650 // Enable gestures:
2651 #if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0))
2652 #if defined MOZ_ENABLE_MEEGOTOUCH
2653 // Disable default Gesture filters (speedup filtering)
2654 newView->viewport()->ungrabGesture(Qt::PanGesture);
2655 newView->viewport()->ungrabGesture(Qt::TapGesture);
2656 newView->viewport()->ungrabGesture(Qt::TapAndHoldGesture);
2657 newView->viewport()->ungrabGesture(Qt::SwipeGesture);
2658 #endif
2660 // Enable required filters
2661 newView->viewport()->grabGesture(Qt::PinchGesture);
2662 newView->viewport()->grabGesture(gSwipeGestureId);
2663 #endif
2664 newView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
2665 newView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
2667 #if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0))
2668 // Top level widget is just container, and should not be painted
2669 widget->setFlag(QGraphicsItem::ItemHasNoContents);
2670 #endif
2672 #ifdef MOZ_X11
2673 if (newView->effectiveWinId()) {
2674 XSetWindowBackgroundPixmap(mozilla::DefaultXDisplay(),
2675 newView->effectiveWinId(), None);
2677 #endif
2680 if (mWindowType == eWindowType_popup) {
2681 widget->setZValue(100);
2683 // XXX is this needed for Qt?
2684 // gdk does not automatically set the cursor for "temporary"
2685 // windows, which are what gtk uses for popups.
2686 SetCursor(eCursor_standard);
2687 } else if (mIsTopLevel) {
2688 SetDefaultIcon();
2690 #if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0))
2691 #if defined MOZ_ENABLE_MEEGOTOUCH
2692 // Disable default Gesture filters (speedup filtering)
2693 widget->ungrabGesture(Qt::PanGesture);
2694 widget->ungrabGesture(Qt::TapGesture);
2695 widget->ungrabGesture(Qt::TapAndHoldGesture);
2696 widget->ungrabGesture(Qt::SwipeGesture);
2697 #endif
2698 widget->grabGesture(Qt::PinchGesture);
2699 widget->grabGesture(gSwipeGestureId);
2700 #endif
2702 return widget;
2705 // return the gfxASurface for rendering to this widget
2706 gfxASurface*
2707 nsWindow::GetThebesSurface()
2709 /* This is really a dummy surface; this is only used when doing reflow, because
2710 * we need a RenderingContext to measure text against.
2712 if (mThebesSurface)
2713 return mThebesSurface;
2715 #ifdef CAIRO_HAS_QT_SURFACE
2716 gfxQtPlatform::RenderMode renderMode = gfxQtPlatform::GetPlatform()->GetRenderMode();
2717 if (renderMode == gfxQtPlatform::RENDER_QPAINTER) {
2718 mThebesSurface = new gfxQPainterSurface(gfxIntSize(1, 1), gfxASurface::CONTENT_COLOR);
2720 #endif
2721 if (!mThebesSurface) {
2722 gfxASurface::gfxImageFormat imageFormat = gfxASurface::ImageFormatRGB24;
2723 mThebesSurface = new gfxImageSurface(gfxIntSize(1, 1), imageFormat);
2726 return mThebesSurface;
2729 NS_IMETHODIMP
2730 nsWindow::BeginResizeDrag(nsGUIEvent* aEvent, int32_t aHorizontal, int32_t aVertical)
2732 NS_ENSURE_ARG_POINTER(aEvent);
2734 if (aEvent->eventStructType != NS_MOUSE_EVENT) {
2735 // you can only begin a resize drag with a mouse event
2736 return NS_ERROR_INVALID_ARG;
2739 nsMouseEvent* mouse_event = static_cast<nsMouseEvent*>(aEvent);
2741 if (mouse_event->button != nsMouseEvent::eLeftButton) {
2742 // you can only begin a resize drag with the left mouse button
2743 return NS_ERROR_INVALID_ARG;
2746 return NS_OK;
2749 nsEventStatus
2750 nsWindow::contextMenuEvent(QGraphicsSceneContextMenuEvent *)
2752 return nsEventStatus_eIgnore;
2755 nsEventStatus
2756 nsWindow::imComposeEvent(QInputMethodEvent *event, bool &handled)
2758 // XXX Needs to check whether this widget has been destroyed or not after
2759 // each DispatchEvent().
2761 nsCompositionEvent start(true, NS_COMPOSITION_START, this);
2762 DispatchEvent(&start);
2764 nsAutoString compositionStr(event->commitString().utf16());
2766 if (!compositionStr.IsEmpty()) {
2767 nsCompositionEvent update(true, NS_COMPOSITION_UPDATE, this);
2768 update.data = compositionStr;
2769 DispatchEvent(&update);
2772 nsTextEvent text(true, NS_TEXT_TEXT, this);
2773 text.theText = compositionStr;
2774 DispatchEvent(&text);
2776 nsCompositionEvent end(true, NS_COMPOSITION_END, this);
2777 end.data = compositionStr;
2778 DispatchEvent(&end);
2780 return nsEventStatus_eIgnore;
2783 nsIWidget *
2784 nsWindow::GetParent(void)
2786 return mParent;
2789 float
2790 nsWindow::GetDPI()
2792 QDesktopWidget* rootWindow = QApplication::desktop();
2793 double heightInches = rootWindow->heightMM()/25.4;
2794 if (heightInches < 0.25) {
2795 // Something's broken, but we'd better not crash.
2796 return 96.0f;
2799 return float(rootWindow->height()/heightInches);
2802 void
2803 nsWindow::DispatchActivateEvent(void)
2805 if (mWidgetListener)
2806 mWidgetListener->WindowActivated();
2809 void
2810 nsWindow::DispatchDeactivateEvent(void)
2812 if (mWidgetListener)
2813 mWidgetListener->WindowDeactivated();
2816 void
2817 nsWindow::DispatchActivateEventOnTopLevelWindow(void)
2819 nsWindow * topLevelWindow = static_cast<nsWindow*>(GetTopLevelWidget());
2820 if (topLevelWindow != nullptr)
2821 topLevelWindow->DispatchActivateEvent();
2824 void
2825 nsWindow::DispatchDeactivateEventOnTopLevelWindow(void)
2827 nsWindow * topLevelWindow = static_cast<nsWindow*>(GetTopLevelWidget());
2828 if (topLevelWindow != nullptr)
2829 topLevelWindow->DispatchDeactivateEvent();
2832 void
2833 nsWindow::DispatchResizeEvent(nsIntRect &aRect, nsEventStatus &aStatus)
2835 aStatus = nsEventStatus_eIgnore;
2836 if (mWidgetListener &&
2837 mWidgetListener->WindowResized(this, aRect.width, aRect.height))
2838 aStatus = nsEventStatus_eConsumeNoDefault;
2841 NS_IMETHODIMP
2842 nsWindow::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus &aStatus)
2844 #ifdef DEBUG
2845 debug_DumpEvent(stdout, aEvent->widget, aEvent,
2846 nsAutoCString("something"), 0);
2847 #endif
2849 aStatus = nsEventStatus_eIgnore;
2851 // send it to the standard callback
2852 if (mWidgetListener)
2853 aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
2855 return NS_OK;
2858 NS_IMETHODIMP
2859 nsWindow::Show(bool aState)
2861 LOG(("nsWindow::Show [%p] state %d\n", (void *)this, aState));
2862 if (aState == mIsShown)
2863 return NS_OK;
2865 // Clear our cached resources when the window is hidden.
2866 if (mIsShown && !aState) {
2867 ClearCachedResources();
2870 mIsShown = aState;
2872 #ifdef MOZ_ENABLE_QTMOBILITY
2873 if (mWidget &&
2874 (mWindowType == eWindowType_toplevel ||
2875 mWindowType == eWindowType_dialog ||
2876 mWindowType == eWindowType_popup))
2878 if (!gOrientation) {
2879 gOrientation = new QOrientationSensor();
2880 gOrientation->addFilter(&gOrientationFilter);
2881 gOrientation->start();
2882 if (!gOrientation->isActive()) {
2883 qWarning("Orientationsensor didn't start!");
2885 gOrientationFilter.filter(gOrientation->reading());
2887 QObject::connect((QObject*) &gOrientationFilter, SIGNAL(orientationChanged()),
2888 mWidget, SLOT(orientationChanged()));
2891 #endif
2893 if ((aState && !AreBoundsSane()) || !mWidget) {
2894 LOG(("\tbounds are insane or window hasn't been created yet\n"));
2895 mNeedsShow = true;
2896 return NS_OK;
2899 if (aState) {
2900 if (mNeedsMove) {
2901 NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height,
2902 false);
2903 } else if (mNeedsResize) {
2904 NativeResize(mBounds.width, mBounds.height, false);
2907 else
2908 // If someone is hiding this widget, clear any needing show flag.
2909 mNeedsShow = false;
2911 NativeShow(aState);
2913 return NS_OK;
2916 NS_IMETHODIMP
2917 nsWindow::Resize(double aWidth, double aHeight, bool aRepaint)
2919 mBounds.width = NSToIntRound(aWidth);
2920 mBounds.height = NSToIntRound(aHeight);
2922 if (!mWidget)
2923 return NS_OK;
2925 if (mIsShown) {
2926 if (AreBoundsSane()) {
2927 if (mIsTopLevel || mNeedsShow)
2928 NativeResize(mBounds.x, mBounds.y,
2929 mBounds.width, mBounds.height, aRepaint);
2930 else
2931 NativeResize(mBounds.width, mBounds.height, aRepaint);
2933 // Does it need to be shown because it was previously insane?
2934 if (mNeedsShow)
2935 NativeShow(true);
2937 else {
2938 // If someone has set this so that the needs show flag is false
2939 // and it needs to be hidden, update the flag and hide the
2940 // window. This flag will be cleared the next time someone
2941 // hides the window or shows it. It also prevents us from
2942 // calling NativeShow(false) excessively on the window which
2943 // causes unneeded X traffic.
2944 if (!mNeedsShow) {
2945 mNeedsShow = true;
2946 NativeShow(false);
2950 else if (AreBoundsSane() && mListenForResizes) {
2951 // For widgets that we listen for resizes for (widgets created
2952 // with native parents) we apparently _always_ have to resize. I
2953 // dunno why, but apparently we're lame like that.
2954 NativeResize(mBounds.width, mBounds.height, aRepaint);
2956 else {
2957 mNeedsResize = true;
2960 // synthesize a resize event if this isn't a toplevel
2961 if (mIsTopLevel || mListenForResizes) {
2962 nsEventStatus status;
2963 DispatchResizeEvent(mBounds, status);
2966 NotifyRollupGeometryChange();
2967 return NS_OK;
2970 NS_IMETHODIMP
2971 nsWindow::Resize(double aX, double aY, double aWidth, double aHeight,
2972 bool aRepaint)
2974 mBounds.x = NSToIntRound(aX);
2975 mBounds.y = NSToIntRound(aY);
2976 mBounds.width = NSToIntRound(aWidth);
2977 mBounds.height = NSToIntRound(aHeight);
2979 mPlaced = true;
2981 if (!mWidget)
2982 return NS_OK;
2984 // Has this widget been set to visible?
2985 if (mIsShown) {
2986 // Are the bounds sane?
2987 if (AreBoundsSane()) {
2988 // Yep? Resize the window
2989 NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height,
2990 aRepaint);
2991 // Does it need to be shown because it was previously insane?
2992 if (mNeedsShow)
2993 NativeShow(true);
2995 else {
2996 // If someone has set this so that the needs show flag is false
2997 // and it needs to be hidden, update the flag and hide the
2998 // window. This flag will be cleared the next time someone
2999 // hides the window or shows it. It also prevents us from
3000 // calling NativeShow(false) excessively on the window which
3001 // causes unneeded X traffic.
3002 if (!mNeedsShow) {
3003 mNeedsShow = true;
3004 NativeShow(false);
3008 // If the widget hasn't been shown, mark the widget as needing to be
3009 // resized before it is shown
3010 else if (AreBoundsSane() && mListenForResizes) {
3011 // For widgets that we listen for resizes for (widgets created
3012 // with native parents) we apparently _always_ have to resize. I
3013 // dunno why, but apparently we're lame like that.
3014 NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height,
3015 aRepaint);
3017 else {
3018 mNeedsResize = true;
3019 mNeedsMove = true;
3022 if (mIsTopLevel || mListenForResizes) {
3023 // synthesize a resize event
3024 nsEventStatus status;
3025 DispatchResizeEvent(mBounds, status);
3028 if (aRepaint)
3029 mWidget->update();
3031 NotifyRollupGeometryChange();
3032 return NS_OK;
3035 NS_IMETHODIMP
3036 nsWindow::Enable(bool aState)
3038 mEnabled = aState;
3040 return NS_OK;
3043 bool
3044 nsWindow::IsEnabled() const
3046 return mEnabled;
3049 void
3050 nsWindow::OnDestroy(void)
3052 if (mOnDestroyCalled)
3053 return;
3055 mOnDestroyCalled = true;
3057 // release references to children and device context
3058 nsBaseWidget::OnDestroy();
3060 // let go of our parent
3061 mParent = nullptr;
3063 nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
3064 NotifyWindowDestroyed();
3067 bool
3068 nsWindow::AreBoundsSane(void)
3070 if (mBounds.width > 0 && mBounds.height > 0)
3071 return true;
3073 return false;
3076 NS_IMETHODIMP_(void)
3077 nsWindow::SetInputContext(const InputContext& aContext,
3078 const InputContextAction& aAction)
3080 NS_ENSURE_TRUE_VOID(mWidget);
3082 // SetSoftwareKeyboardState uses mInputContext,
3083 // so, before calling that, record aContext in mInputContext.
3084 mInputContext = aContext;
3086 switch (mInputContext.mIMEState.mEnabled) {
3087 case IMEState::ENABLED:
3088 case IMEState::PASSWORD:
3089 case IMEState::PLUGIN:
3090 SetSoftwareKeyboardState(true, aAction);
3091 break;
3092 default:
3093 SetSoftwareKeyboardState(false, aAction);
3094 break;
3098 NS_IMETHODIMP_(InputContext)
3099 nsWindow::GetInputContext()
3101 mInputContext.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
3102 // Our qt widget looks like using only one context per process.
3103 // However, it's better to set the context's pointer.
3104 #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
3105 mInputContext.mNativeIMEContext = qApp->inputContext();
3106 #else
3107 mInputContext.mNativeIMEContext = qApp->inputMethod();
3108 #endif
3109 return mInputContext;
3112 void
3113 nsWindow::SetSoftwareKeyboardState(bool aOpen,
3114 const InputContextAction& aAction)
3116 if (aOpen) {
3117 NS_ENSURE_TRUE_VOID(mInputContext.mIMEState.mEnabled !=
3118 IMEState::DISABLED);
3120 // Ensure that opening the virtual keyboard is allowed for this specific
3121 // InputContext depending on the content.ime.strict.policy pref
3122 if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN &&
3123 Preferences::GetBool("content.ime.strict_policy", false) &&
3124 !aAction.ContentGotFocusByTrustedCause() &&
3125 !aAction.UserMightRequestOpenVKB()) {
3126 return;
3130 if (aOpen) {
3131 // VKB open need to be delayed in order to give
3132 // to plugins chance prevent VKB from opening
3133 int32_t openDelay =
3134 Preferences::GetInt("ui.vkb.open.delay", 200);
3135 MozQWidget::requestVKB(openDelay, mWidget);
3136 } else {
3137 MozQWidget::hideVKB();
3139 return;
3142 void
3143 nsWindow::UserActivity()
3145 if (!mIdleService) {
3146 mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
3149 if (mIdleService) {
3150 mIdleService->ResetIdleTimeOut(0);
3154 uint32_t
3155 nsWindow::GetGLFrameBufferFormat()
3157 if (mLayerManager &&
3158 mLayerManager->GetBackendType() == mozilla::layers::LAYERS_OPENGL) {
3159 return MozQGLWidgetWrapper::isRGBAContext() ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
3161 return LOCAL_GL_NONE;