Bug 867104 - Add a crashtest. r=ehsan
[gecko.git] / widget / qt / nsWindow.cpp
blob0414c2b7be66390cdb4c3de6114803e5c05112c3
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 #if MOZ_PLATFORM_MAEMO > 5
92 #include "nsIDOMWindow.h"
93 #include "nsIDOMElement.h"
94 #include "nsIFocusManager.h"
95 #endif
97 #ifdef MOZ_X11
98 #include "keysym2ucs.h"
99 #if MOZ_PLATFORM_MAEMO == 6
100 #include <X11/Xatom.h>
101 static Atom sPluginIMEAtom = nullptr;
102 #define PLUGIN_VKB_REQUEST_PROP "_NPAPI_PLUGIN_REQUEST_VKB"
103 #include <QThread>
104 #endif
105 #endif //MOZ_X11
107 #include "gfxUtils.h"
108 #include "Layers.h"
109 #include "GLContextProvider.h"
110 #include "BasicLayers.h"
111 #include "LayerManagerOGL.h"
112 #include "nsFastStartupQt.h"
114 // If embedding clients want to create widget without real parent window
115 // then nsIBaseWindow->Init() should have parent argument equal to PARENTLESS_WIDGET
116 #define PARENTLESS_WIDGET (void*)0x13579
118 #include "nsShmImage.h"
119 extern "C" {
120 #define PIXMAN_DONT_DEFINE_STDINT
121 #include "pixman.h"
124 using namespace mozilla;
125 using namespace mozilla::widget;
126 using mozilla::gl::GLContext;
127 using mozilla::layers::LayerManagerOGL;
129 // Cached offscreen surface
130 static nsRefPtr<gfxASurface> gBufferSurface;
131 #ifdef MOZ_HAVE_SHMIMAGE
132 // If we're using xshm rendering, mThebesSurface wraps gShmImage
133 nsRefPtr<nsShmImage> gShmImage;
134 #endif
136 static int gBufferPixmapUsageCount = 0;
137 static gfxIntSize gBufferMaxSize(0, 0);
139 // initialization static functions
140 static nsresult initialize_prefs (void);
142 static NS_DEFINE_IID(kCDragServiceCID, NS_DRAGSERVICE_CID);
144 #define NS_WINDOW_TITLE_MAX_LENGTH 4095
146 #define kWindowPositionSlop 20
148 // Qt
149 static const int WHEEL_DELTA = 120;
150 static bool gGlobalsInitialized = false;
152 static bool
153 is_mouse_in_window (MozQWidget* aWindow, double aMouseX, double aMouseY);
155 static bool sAltGrModifier = false;
157 #ifdef MOZ_ENABLE_QTMOBILITY
158 static QOrientationSensor *gOrientation = nullptr;
159 static MozQOrientationSensorFilter gOrientationFilter;
160 #endif
162 static bool
163 isContextMenuKeyEvent(const QKeyEvent *qe)
165 uint32_t kc = QtKeyCodeToDOMKeyCode(qe->key());
166 if (qe->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))
167 return false;
169 bool isShift = qe->modifiers() & Qt::ShiftModifier;
170 return (kc == NS_VK_F10 && isShift) ||
171 (kc == NS_VK_CONTEXT_MENU && !isShift);
174 static void
175 InitKeyEvent(nsKeyEvent &aEvent, QKeyEvent *aQEvent)
177 aEvent.InitBasicModifiers(aQEvent->modifiers() & Qt::ControlModifier,
178 aQEvent->modifiers() & Qt::AltModifier,
179 aQEvent->modifiers() & Qt::ShiftModifier,
180 aQEvent->modifiers() & Qt::MetaModifier);
182 // TODO: Needs to set .location for desktop Qt build.
183 #ifdef MOZ_PLATFORM_MAEMO
184 aEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_MOBILE;
185 #endif
186 aEvent.time = 0;
188 if (sAltGrModifier) {
189 aEvent.modifiers |= (widget::MODIFIER_CONTROL | widget::MODIFIER_ALT);
192 // The transformations above and in qt for the keyval are not invertible
193 // so link to the QKeyEvent (which will vanish soon after return from the
194 // event callback) to give plugins access to hardware_keycode and state.
195 // (An XEvent would be nice but the QKeyEvent is good enough.)
196 aEvent.pluginEvent = (void *)aQEvent;
199 nsWindow::nsWindow()
201 LOG(("%s [%p]\n", __PRETTY_FUNCTION__, (void *)this));
203 mIsTopLevel = false;
204 mIsDestroyed = false;
205 mIsShown = false;
206 mEnabled = true;
207 mWidget = nullptr;
208 mIsVisible = false;
209 mActivatePending = false;
210 mWindowType = eWindowType_child;
211 mSizeState = nsSizeMode_Normal;
212 mLastSizeMode = nsSizeMode_Normal;
213 mPluginType = PluginType_NONE;
214 mQCursor = Qt::ArrowCursor;
215 mNeedsResize = false;
216 mNeedsMove = false;
217 mListenForResizes = false;
218 mNeedsShow = false;
219 mGesturesCancelled = false;
220 mTimerStarted = false;
221 mPinchEvent.needDispatch = false;
222 mMoveEvent.needDispatch = false;
224 if (!gGlobalsInitialized) {
225 gfxPlatform::GetPlatform();
226 gGlobalsInitialized = true;
228 #if defined(MOZ_X11) && (MOZ_PLATFORM_MAEMO == 6)
229 // This cannot be called on non-main thread
230 if (QThread::currentThread() == qApp->thread()) {
231 sPluginIMEAtom = XInternAtom(mozilla::DefaultXDisplay(), PLUGIN_VKB_REQUEST_PROP, False);
233 #endif
234 // It's OK if either of these fail, but it may not be one day.
235 initialize_prefs();
238 memset(mKeyDownFlags, 0, sizeof(mKeyDownFlags));
240 mIsTransparent = false;
242 mCursor = eCursor_standard;
244 gBufferPixmapUsageCount++;
246 #if (QT_VERSION > QT_VERSION_CHECK(4,6,0))
247 if (gSwipeGestureId == Qt::CustomGesture) {
248 // QGestureRecognizer takes ownership
249 MozSwipeGestureRecognizer* swipeRecognizer = new MozSwipeGestureRecognizer;
250 gSwipeGestureId = QGestureRecognizer::registerRecognizer(swipeRecognizer);
252 #endif
255 static inline gfxASurface::gfxImageFormat
256 _depth_to_gfximage_format(int32_t aDepth)
258 switch (aDepth) {
259 case 32:
260 return gfxASurface::ImageFormatARGB32;
261 case 24:
262 return gfxASurface::ImageFormatRGB24;
263 case 16:
264 return gfxASurface::ImageFormatRGB16_565;
265 default:
266 return gfxASurface::ImageFormatUnknown;
270 static inline QImage::Format
271 _gfximage_to_qformat(gfxASurface::gfxImageFormat aFormat)
273 switch (aFormat) {
274 case gfxASurface::ImageFormatARGB32:
275 return QImage::Format_ARGB32_Premultiplied;
276 case gfxASurface::ImageFormatRGB24:
277 return QImage::Format_ARGB32;
278 case gfxASurface::ImageFormatRGB16_565:
279 return QImage::Format_RGB16;
280 default:
281 return QImage::Format_Invalid;
285 static bool
286 UpdateOffScreenBuffers(int aDepth, QSize aSize, QWidget* aWidget = nullptr)
288 gfxIntSize size(aSize.width(), aSize.height());
289 if (gBufferSurface) {
290 if (gBufferMaxSize.width < size.width ||
291 gBufferMaxSize.height < size.height) {
292 gBufferSurface = nullptr;
293 } else
294 return true;
297 gBufferMaxSize.width = std::max(gBufferMaxSize.width, size.width);
298 gBufferMaxSize.height = std::max(gBufferMaxSize.height, size.height);
300 // Check if system depth has related gfxImage format
301 gfxASurface::gfxImageFormat format =
302 _depth_to_gfximage_format(aDepth);
304 // Use fallback RGB24 format, Qt will do conversion for us
305 if (format == gfxASurface::ImageFormatUnknown)
306 format = gfxASurface::ImageFormatRGB24;
308 #ifdef MOZ_HAVE_SHMIMAGE
309 if (aWidget) {
310 if (gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType() ==
311 gfxASurface::SurfaceTypeImage) {
312 gShmImage = nsShmImage::Create(gBufferMaxSize,
313 DefaultVisualOfScreen(gfxQtPlatform::GetXScreen(aWidget)),
314 aDepth);
315 gBufferSurface = gShmImage->AsSurface();
316 return true;
319 #endif
321 gBufferSurface = gfxPlatform::GetPlatform()->
322 CreateOffscreenSurface(gBufferMaxSize, gfxASurface::ContentFromFormat(format));
324 return true;
327 nsWindow::~nsWindow()
329 LOG(("%s [%p]\n", __PRETTY_FUNCTION__, (void *)this));
331 Destroy();
334 /* static */ void
335 nsWindow::ReleaseGlobals()
339 NS_IMPL_ISUPPORTS_INHERITED1(nsWindow, nsBaseWidget, nsISupportsWeakReference)
341 NS_IMETHODIMP
342 nsWindow::ConfigureChildren(const nsTArray<nsIWidget::Configuration>& aConfigurations)
344 for (uint32_t i = 0; i < aConfigurations.Length(); ++i) {
345 const Configuration& configuration = aConfigurations[i];
347 nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
348 NS_ASSERTION(w->GetParent() == this,
349 "Configured widget is not a child");
351 if (w->mBounds.Size() != configuration.mBounds.Size()) {
352 w->Resize(configuration.mBounds.x, configuration.mBounds.y,
353 configuration.mBounds.width, configuration.mBounds.height,
354 true);
355 } else if (w->mBounds.TopLeft() != configuration.mBounds.TopLeft()) {
356 w->Move(configuration.mBounds.x, configuration.mBounds.y);
359 return NS_OK;
362 NS_IMETHODIMP
363 nsWindow::Destroy(void)
365 if (mIsDestroyed || !mWidget)
366 return NS_OK;
368 LOG(("nsWindow::Destroy [%p]\n", (void *)this));
369 mIsDestroyed = true;
371 if (gBufferPixmapUsageCount &&
372 --gBufferPixmapUsageCount == 0) {
374 gBufferSurface = nullptr;
375 #ifdef MOZ_HAVE_SHMIMAGE
376 gShmImage = nullptr;
377 #endif
378 #ifdef MOZ_ENABLE_QTMOBILITY
379 if (gOrientation) {
380 gOrientation->removeFilter(&gOrientationFilter);
381 gOrientation->stop();
382 delete gOrientation;
383 gOrientation = nullptr;
385 #endif
388 /** Need to clean our LayerManager up while still alive */
389 if (mLayerManager) {
390 nsRefPtr<GLContext> gl = nullptr;
391 if (mLayerManager->GetBackendType() == mozilla::layers::LAYERS_OPENGL) {
392 LayerManagerOGL *ogllm = static_cast<LayerManagerOGL*>(mLayerManager.get());
393 gl = ogllm->gl();
396 mLayerManager->Destroy();
398 if (gl) {
399 gl->MarkDestroyed();
402 mLayerManager = nullptr;
404 // It is safe to call DestroyeCompositor several times (here and
405 // in the parent class) since it will take effect only once.
406 // The reason we call it here is because on gtk platforms we need
407 // to destroy the compositor before we destroy the gdk window (which
408 // destroys the the gl context attached to it).
409 DestroyCompositor();
411 ClearCachedResources();
413 nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
414 if (rollupListener) {
415 nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
416 if (static_cast<nsIWidget *>(this) == rollupWidget) {
417 rollupListener->Rollup(0, nullptr);
421 Show(false);
423 // walk the list of children and call destroy on them. Have to be
424 // careful, though -- calling destroy on a kid may actually remove
425 // it from our child list, losing its sibling links.
426 for (nsIWidget* kid = mFirstChild; kid; ) {
427 nsIWidget* next = kid->GetNextSibling();
428 kid->Destroy();
429 kid = next;
432 // Destroy thebes surface now. Badness can happen if we destroy
433 // the surface after its X Window.
434 mThebesSurface = nullptr;
436 QWidget *view = nullptr;
437 QGraphicsScene *scene = nullptr;
438 if (mWidget) {
439 if (mIsTopLevel) {
440 view = GetViewWidget();
441 scene = mWidget->scene();
444 mWidget->dropReceiver();
446 // Call deleteLater instead of delete; Qt still needs the object
447 // to be valid even after sending it a Close event. We could
448 // also set WA_DeleteOnClose, but this gives us more control.
449 mWidget->deleteLater();
451 mWidget = nullptr;
453 OnDestroy();
455 // tear down some infrastructure after all event handling is finished
456 delete scene;
457 delete view;
459 return NS_OK;
462 void
463 nsWindow::ClearCachedResources()
465 if (mLayerManager &&
466 mLayerManager->GetBackendType() == mozilla::layers::LAYERS_BASIC) {
467 static_cast<mozilla::layers::BasicLayerManager*> (mLayerManager.get())->
468 ClearCachedResources();
470 for (nsIWidget* kid = mFirstChild; kid; ) {
471 nsIWidget* next = kid->GetNextSibling();
472 static_cast<nsWindow*>(kid)->ClearCachedResources();
473 kid = next;
477 NS_IMETHODIMP
478 nsWindow::SetParent(nsIWidget *aNewParent)
480 NS_ENSURE_ARG_POINTER(aNewParent);
481 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
482 nsIWidget* parent = GetParent();
483 if (parent) {
484 parent->RemoveChild(this);
486 ReparentNativeWidget(aNewParent);
487 aNewParent->AddChild(this);
488 return NS_OK;
491 NS_IMETHODIMP
492 nsWindow::ReparentNativeWidget(nsIWidget *aNewParent)
494 NS_PRECONDITION(aNewParent, "");
496 MozQWidget* newParent = static_cast<MozQWidget*>(aNewParent->GetNativeData(NS_NATIVE_WINDOW));
497 NS_ASSERTION(newParent, "Parent widget has a null native window handle");
498 if (mWidget) {
499 mWidget->setParentItem(newParent);
501 return NS_OK;
504 NS_IMETHODIMP
505 nsWindow::SetModal(bool aModal)
507 LOG(("nsWindow::SetModal [%p] %d, widget[%p]\n", (void *)this, aModal, mWidget));
508 if (mWidget)
509 mWidget->setModal(aModal);
511 return NS_OK;
514 bool
515 nsWindow::IsVisible() const
517 return mIsShown;
520 NS_IMETHODIMP
521 nsWindow::ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY)
523 if (mWidget) {
524 int32_t screenWidth = QApplication::desktop()->width();
525 int32_t screenHeight = QApplication::desktop()->height();
527 if (aAllowSlop) {
528 if (*aX < (kWindowPositionSlop - mBounds.width))
529 *aX = kWindowPositionSlop - mBounds.width;
530 if (*aX > (screenWidth - kWindowPositionSlop))
531 *aX = screenWidth - kWindowPositionSlop;
532 if (*aY < (kWindowPositionSlop - mBounds.height))
533 *aY = kWindowPositionSlop - mBounds.height;
534 if (*aY > (screenHeight - kWindowPositionSlop))
535 *aY = screenHeight - kWindowPositionSlop;
536 } else {
537 if (*aX < 0)
538 *aX = 0;
539 if (*aX > (screenWidth - mBounds.width))
540 *aX = screenWidth - mBounds.width;
541 if (*aY < 0)
542 *aY = 0;
543 if (*aY > (screenHeight - mBounds.height))
544 *aY = screenHeight - mBounds.height;
548 return NS_OK;
551 NS_IMETHODIMP
552 nsWindow::Move(double aX, double aY)
554 LOG(("nsWindow::Move [%p] %f %f\n", (void *)this,
555 aX, aY));
557 int32_t x = NSToIntRound(aX);
558 int32_t y = NSToIntRound(aY);
560 if (mIsTopLevel) {
561 SetSizeMode(nsSizeMode_Normal);
564 if (x == mBounds.x && y == mBounds.y)
565 return NS_OK;
567 mNeedsMove = false;
569 // update the bounds
570 QPointF pos( x, y );
571 if (mIsTopLevel) {
572 QWidget *widget = GetViewWidget();
573 NS_ENSURE_TRUE(widget, NS_OK);
574 widget->move(x, y);
576 else if (mWidget) {
577 // the position of the widget is set relative to the parent
578 // so we map the coordinates accordingly
579 pos = mWidget->mapFromScene(pos);
580 pos = mWidget->mapToParent(pos);
581 mWidget->setPos(pos);
584 mBounds.x = pos.x();
585 mBounds.y = pos.y();
587 NotifyRollupGeometryChange();
588 return NS_OK;
591 NS_IMETHODIMP
592 nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
593 nsIWidget *aWidget,
594 bool aActivate)
596 return NS_ERROR_NOT_IMPLEMENTED;
599 NS_IMETHODIMP
600 nsWindow::SetSizeMode(int32_t aMode)
602 nsresult rv;
604 LOG(("nsWindow::SetSizeMode [%p] %d\n", (void *)this, aMode));
605 if (aMode != nsSizeMode_Minimized) {
606 GetViewWidget()->activateWindow();
609 // Save the requested state.
610 rv = nsBaseWidget::SetSizeMode(aMode);
612 // return if there's no shell or our current state is the same as
613 // the mode we were just set to.
614 if (!mWidget || mSizeState == mSizeMode) {
615 return rv;
618 QWidget *widget = GetViewWidget();
619 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
621 switch (aMode) {
622 case nsSizeMode_Maximized:
623 widget->showMaximized();
624 break;
625 case nsSizeMode_Minimized:
626 widget->showMinimized();
627 break;
628 case nsSizeMode_Fullscreen:
629 widget->showFullScreen();
630 break;
632 default:
633 // nsSizeMode_Normal, really.
634 widget->showNormal();
635 break;
638 mSizeState = mSizeMode;
640 return rv;
643 // Helper function to recursively find the first parent item that
644 // is still visible (QGraphicsItem can be hidden even if they are
645 // set to visible if one of their ancestors is invisible)
646 static void find_first_visible_parent(QGraphicsItem* aItem, QGraphicsItem*& aVisibleItem)
648 NS_ENSURE_TRUE_VOID(aItem);
650 aVisibleItem = nullptr;
651 QGraphicsItem* parItem = nullptr;
652 while (!aVisibleItem) {
653 if (aItem->isVisible())
654 aVisibleItem = aItem;
655 else {
656 parItem = aItem->parentItem();
657 if (parItem)
658 aItem = parItem;
659 else {
660 aItem->setVisible(true);
661 aVisibleItem = aItem;
667 NS_IMETHODIMP
668 nsWindow::SetFocus(bool aRaise)
670 // Make sure that our owning widget has focus. If it doesn't try to
671 // grab it. Note that we don't set our focus flag in this case.
672 LOGFOCUS((" SetFocus [%p]\n", (void *)this));
674 if (!mWidget)
675 return NS_ERROR_FAILURE;
677 if (mWidget->hasFocus())
678 return NS_OK;
680 // Because QGraphicsItem cannot get the focus if they are
681 // invisible, we look up the chain, for the lowest visible
682 // parent and focus that one
683 QGraphicsItem* realFocusItem = nullptr;
684 find_first_visible_parent(mWidget, realFocusItem);
686 if (!realFocusItem || realFocusItem->hasFocus())
687 return NS_OK;
689 if (aRaise) {
690 // the raising has to happen on the view widget
691 QWidget *widget = GetViewWidget();
692 if (widget)
693 widget->raise();
694 realFocusItem->setFocus(Qt::ActiveWindowFocusReason);
696 else
697 realFocusItem->setFocus(Qt::OtherFocusReason);
699 // XXXndeakin why is this here? It should dispatch only when the OS
700 // notifies us.
701 DispatchActivateEvent();
703 return NS_OK;
706 NS_IMETHODIMP
707 nsWindow::GetScreenBounds(nsIntRect &aRect)
709 aRect = nsIntRect(nsIntPoint(0, 0), mBounds.Size());
710 if (mIsTopLevel) {
711 QWidget *widget = GetViewWidget();
712 NS_ENSURE_TRUE(widget, NS_OK);
713 QPoint pos = widget->pos();
714 aRect.MoveTo(pos.x(), pos.y());
716 else {
717 aRect.MoveTo(WidgetToScreenOffset());
719 LOG(("GetScreenBounds %d %d | %d %d | %d %d\n",
720 aRect.x, aRect.y,
721 mBounds.width, mBounds.height,
722 aRect.width, aRect.height));
723 return NS_OK;
726 NS_IMETHODIMP
727 nsWindow::SetForegroundColor(const nscolor &aColor)
729 return NS_ERROR_NOT_IMPLEMENTED;
732 NS_IMETHODIMP
733 nsWindow::SetBackgroundColor(const nscolor &aColor)
735 return NS_ERROR_NOT_IMPLEMENTED;
738 NS_IMETHODIMP
739 nsWindow::SetCursor(nsCursor aCursor)
741 if (mCursor == aCursor)
742 return NS_OK;
744 mCursor = aCursor;
745 if (mWidget)
746 mWidget->SetCursor(mCursor);
747 return NS_OK;
750 NS_IMETHODIMP
751 nsWindow::SetCursor(imgIContainer* aCursor,
752 uint32_t aHotspotX, uint32_t aHotspotY)
754 return NS_ERROR_NOT_AVAILABLE;
757 NS_IMETHODIMP
758 nsWindow::Invalidate(const nsIntRect &aRect)
760 LOGDRAW(("Invalidate (rect) [%p,%p]: %d %d %d %d\n", (void *)this,
761 (void*)mWidget,aRect.x, aRect.y, aRect.width, aRect.height));
763 if (!mWidget)
764 return NS_OK;
766 mDirtyScrollArea = mDirtyScrollArea.united(QRect(aRect.x, aRect.y, aRect.width, aRect.height));
768 mWidget->update(aRect.x, aRect.y, aRect.width, aRect.height);
770 return NS_OK;
773 // Returns the graphics view widget for this nsWindow by iterating
774 // the chain of parents until a toplevel window with a view/scene is found.
775 // (This function always returns something or asserts if the precondition
776 // is not met)
777 QWidget* nsWindow::GetViewWidget()
779 NS_ASSERTION(mWidget, "Calling GetViewWidget without mWidget created");
780 if (!mWidget || !mWidget->scene() || !mWidget->scene()->views().size())
781 return nullptr;
783 NS_ASSERTION(mWidget->scene()->views().size() == 1, "Not exactly one view for our scene!");
784 return mWidget->scene()->views()[0];
787 void*
788 nsWindow::GetNativeData(uint32_t aDataType)
790 switch (aDataType) {
791 case NS_NATIVE_WINDOW:
792 case NS_NATIVE_WIDGET: {
793 if (!mWidget)
794 return nullptr;
796 return mWidget;
797 break;
800 case NS_NATIVE_PLUGIN_PORT:
801 return SetupPluginPort();
802 break;
804 case NS_NATIVE_DISPLAY:
806 #ifdef MOZ_X11
807 return gfxQtPlatform::GetXDisplay(GetViewWidget());
808 #else
809 return nullptr;
810 #endif
812 break;
814 case NS_NATIVE_GRAPHIC: {
815 return nullptr;
816 break;
819 case NS_NATIVE_SHELLWIDGET: {
820 QWidget* widget = nullptr;
821 if (mWidget && mWidget->scene())
822 widget = mWidget->scene()->views()[0]->viewport();
823 return (void *) widget;
826 case NS_NATIVE_SHAREABLE_WINDOW: {
827 QWidget *widget = GetViewWidget();
828 return widget ? (void*)widget->winId() : nullptr;
831 default:
832 NS_WARNING("nsWindow::GetNativeData called with bad value");
833 return nullptr;
837 NS_IMETHODIMP
838 nsWindow::SetTitle(const nsAString& aTitle)
840 QString qStr(QString::fromUtf16(aTitle.BeginReading(), aTitle.Length()));
841 if (mIsTopLevel) {
842 QWidget *widget = GetViewWidget();
843 if (widget)
844 widget->setWindowTitle(qStr);
846 else if (mWidget)
847 mWidget->setWindowTitle(qStr);
849 return NS_OK;
852 NS_IMETHODIMP
853 nsWindow::SetIcon(const nsAString& aIconSpec)
855 if (!mWidget)
856 return NS_OK;
858 nsCOMPtr<nsIFile> iconFile;
859 nsAutoCString path;
860 nsTArray<nsCString> iconList;
862 // Look for icons with the following suffixes appended to the base name.
863 // The last two entries (for the old XPM format) will be ignored unless
864 // no icons are found using the other suffixes. XPM icons are depricated.
866 const char extensions[6][7] = { ".png", "16.png", "32.png", "48.png",
867 ".xpm", "16.xpm" };
869 for (uint32_t i = 0; i < ArrayLength(extensions); i++) {
870 // Don't bother looking for XPM versions if we found a PNG.
871 if (i == ArrayLength(extensions) - 2 && iconList.Length())
872 break;
874 nsAutoString extension;
875 extension.AppendASCII(extensions[i]);
877 ResolveIconName(aIconSpec, extension, getter_AddRefs(iconFile));
878 if (iconFile) {
879 iconFile->GetNativePath(path);
880 iconList.AppendElement(path);
884 // leave the default icon intact if no matching icons were found
885 if (iconList.Length() == 0)
886 return NS_OK;
888 return SetWindowIconList(iconList);
891 nsIntPoint
892 nsWindow::WidgetToScreenOffset()
894 NS_ENSURE_TRUE(mWidget, nsIntPoint(0,0));
896 QPointF origin(0, 0);
897 origin = mWidget->mapToScene(origin);
899 return nsIntPoint(origin.x(), origin.y());
902 NS_IMETHODIMP
903 nsWindow::EnableDragDrop(bool aEnable)
905 mWidget->setAcceptDrops(aEnable);
906 return NS_OK;
909 NS_IMETHODIMP
910 nsWindow::CaptureMouse(bool aCapture)
912 LOG(("CaptureMouse %p\n", (void *)this));
914 if (!mWidget)
915 return NS_OK;
917 QWidget *widget = GetViewWidget();
918 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
920 if (aCapture)
921 widget->grabMouse();
922 else
923 widget->releaseMouse();
925 return NS_OK;
928 NS_IMETHODIMP
929 nsWindow::CaptureRollupEvents(nsIRollupListener *aListener,
930 bool aDoCapture)
932 if (!mWidget)
933 return NS_OK;
935 LOG(("CaptureRollupEvents %p\n", (void *)this));
937 gRollupListener = aDoCapture ? aListener : nullptr;
938 return NS_OK;
941 bool
942 nsWindow::CheckForRollup(double aMouseX, double aMouseY,
943 bool aIsWheel)
945 nsIRollupListener* rollupListener = GetActiveRollupListener();
946 nsCOMPtr<nsIWidget> rollupWidget;
947 if (rollupListener) {
948 rollupWidget = rollupListener->GetRollupWidget();
950 if (!rollupWidget) {
951 nsBaseWidget::gRollupListener = nullptr;
952 return false;
955 bool retVal = false;
956 MozQWidget *currentPopup =
957 (MozQWidget *)rollupWidget->GetNativeData(NS_NATIVE_WINDOW);
958 if (!is_mouse_in_window(currentPopup, aMouseX, aMouseY)) {
959 bool rollup = true;
960 if (aIsWheel) {
961 rollup = rollupListener->ShouldRollupOnMouseWheelEvent();
962 retVal = true;
964 // if we're dealing with menus, we probably have submenus and
965 // we don't want to rollup if the clickis in a parent menu of
966 // the current submenu
967 uint32_t popupsToRollup = UINT32_MAX;
968 if (rollupListener) {
969 nsAutoTArray<nsIWidget*, 5> widgetChain;
970 uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain);
971 for (uint32_t i=0; i<widgetChain.Length(); ++i) {
972 nsIWidget* widget = widgetChain[i];
973 MozQWidget* currWindow =
974 (MozQWidget*) widget->GetNativeData(NS_NATIVE_WINDOW);
975 if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) {
976 if (i < sameTypeCount) {
977 rollup = false;
979 else {
980 popupsToRollup = sameTypeCount;
982 break;
984 } // foreach parent menu widget
985 } // if rollup listener knows about menus
987 // if we've determined that we should still rollup, do it.
988 if (rollup) {
989 retVal = rollupListener->Rollup(popupsToRollup, nullptr);
993 return retVal;
996 /* static */
997 bool
998 is_mouse_in_window (MozQWidget* aWindow, double aMouseX, double aMouseY)
1000 return aWindow->geometry().contains( aMouseX, aMouseY );
1003 NS_IMETHODIMP
1004 nsWindow::GetAttention(int32_t aCycleCount)
1006 LOG(("nsWindow::GetAttention [%p]\n", (void *)this));
1007 return NS_ERROR_NOT_IMPLEMENTED;
1010 #ifdef MOZ_X11
1011 static already_AddRefed<gfxASurface>
1012 GetSurfaceForQWidget(QWidget* aDrawable)
1014 gfxASurface* result =
1015 new gfxXlibSurface(gfxQtPlatform::GetXDisplay(aDrawable),
1016 aDrawable->winId(),
1017 DefaultVisualOfScreen(gfxQtPlatform::GetXScreen(aDrawable)),
1018 gfxIntSize(aDrawable->size().width(),
1019 aDrawable->size().height()));
1020 NS_IF_ADDREF(result);
1021 return result;
1023 #endif
1025 bool
1026 nsWindow::DoPaint(QPainter* aPainter, const QStyleOptionGraphicsItem* aOption, QWidget* aWidget)
1028 if (mIsDestroyed) {
1029 LOG(("Expose event on destroyed window [%p] window %p\n",
1030 (void *)this, mWidget));
1031 return false;
1034 // Call WillPaintWindow to allow scripts etc. to run before we paint
1036 if (mWidgetListener)
1037 mWidgetListener->WillPaintWindow(this);
1040 if (!mWidget)
1041 return false;
1043 QRectF r;
1044 if (aOption)
1045 r = aOption->exposedRect;
1046 else
1047 r = mWidget->boundingRect();
1049 if (r.isEmpty())
1050 return nsEventStatus_eIgnore;
1052 if (!mDirtyScrollArea.isEmpty())
1053 mDirtyScrollArea = QRegion();
1055 bool painted = false;
1056 nsIntRect rect(r.x(), r.y(), r.width(), r.height());
1058 nsFastStartup* startup = nsFastStartup::GetSingleton();
1059 if (startup) {
1060 startup->RemoveFakeLayout();
1063 if (GetLayerManager(nullptr)->GetBackendType() == mozilla::layers::LAYERS_OPENGL) {
1064 aPainter->beginNativePainting();
1065 nsIntRegion region(rect);
1066 static_cast<mozilla::layers::LayerManagerOGL*>(GetLayerManager(nullptr))->
1067 SetClippingRegion(region);
1069 gfxMatrix matr;
1070 matr.Translate(gfxPoint(aPainter->transform().dx(), aPainter->transform().dy()));
1071 #ifdef MOZ_ENABLE_QTMOBILITY
1072 // This is needed for rotate transformation on MeeGo
1073 // This will work very slow if pixman does not handle rotation very well
1074 matr.Rotate((M_PI/180) * gOrientationFilter.GetWindowRotationAngle());
1075 static_cast<mozilla::layers::LayerManagerOGL*>(GetLayerManager(nullptr))->
1076 SetWorldTransform(matr);
1077 #endif //MOZ_ENABLE_QTMOBILITY
1079 if (mWidgetListener)
1080 painted = mWidgetListener->PaintWindow(this, region, 0);
1081 aPainter->endNativePainting();
1082 if (mWidgetListener)
1083 mWidgetListener->DidPaintWindow();
1084 return painted;
1087 gfxQtPlatform::RenderMode renderMode = gfxQtPlatform::GetPlatform()->GetRenderMode();
1088 int depth = aPainter->device()->depth();
1090 nsRefPtr<gfxASurface> targetSurface = nullptr;
1091 if (renderMode == gfxQtPlatform::RENDER_BUFFERED) {
1092 // Prepare offscreen buffers iamge or xlib, depends from paintEngineType
1093 if (!UpdateOffScreenBuffers(depth, QSize(r.width(), r.height())))
1094 return false;
1096 targetSurface = gBufferSurface;
1098 #ifdef CAIRO_HAS_QT_SURFACE
1099 } else if (renderMode == gfxQtPlatform::RENDER_QPAINTER) {
1100 targetSurface = new gfxQPainterSurface(aPainter);
1101 #endif
1102 } else if (renderMode == gfxQtPlatform::RENDER_DIRECT) {
1103 if (!UpdateOffScreenBuffers(depth, aWidget->size(), aWidget)) {
1104 return false;
1106 targetSurface = gBufferSurface;
1109 if (MOZ_UNLIKELY(!targetSurface))
1110 return false;
1112 nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
1114 // We will paint to 0, 0 position in offscrenn buffer
1115 if (renderMode == gfxQtPlatform::RENDER_BUFFERED) {
1116 ctx->Translate(gfxPoint(-r.x(), -r.y()));
1118 else if (renderMode == gfxQtPlatform::RENDER_DIRECT) {
1119 gfxMatrix matr;
1120 matr.Translate(gfxPoint(aPainter->transform().dx(), aPainter->transform().dy()));
1121 #ifdef MOZ_ENABLE_QTMOBILITY
1122 // This is needed for rotate transformation on MeeGo
1123 // This will work very slow if pixman does not handle rotation very well
1124 matr.Rotate((M_PI/180) * gOrientationFilter.GetWindowRotationAngle());
1125 NS_ASSERTION(PIXMAN_VERSION > PIXMAN_VERSION_ENCODE(0, 21, 2) ||
1126 !gOrientationFilter.GetWindowRotationAngle(),
1127 "Old pixman and rotate transform, it is going to be slow");
1128 #endif //MOZ_ENABLE_QTMOBILITY
1130 ctx->SetMatrix(matr);
1134 AutoLayerManagerSetup
1135 setupLayerManager(this, ctx, mozilla::layers::BUFFER_NONE);
1136 if (mWidgetListener) {
1137 nsIntRegion region(rect);
1138 painted = mWidgetListener->PaintWindow(this, region, 0);
1142 // DispatchEvent can Destroy us (bug 378273), avoid doing any paint
1143 // operations below if that happened - it will lead to XError and exit().
1144 if (MOZ_UNLIKELY(mIsDestroyed))
1145 return painted;
1147 if (!painted)
1148 return false;
1150 LOGDRAW(("[%p] draw done\n", this));
1152 // Handle buffered painting mode
1153 if (renderMode == gfxQtPlatform::RENDER_BUFFERED) {
1154 #if defined(MOZ_X11) && defined(Q_WS_X11)
1155 if (gBufferSurface->GetType() == gfxASurface::SurfaceTypeXlib) {
1156 // Paint offscreen pixmap to QPainter
1157 static QPixmap gBufferPixmap;
1158 Drawable draw = static_cast<gfxXlibSurface*>(gBufferSurface.get())->XDrawable();
1159 if (gBufferPixmap.handle() != draw)
1160 gBufferPixmap = QPixmap::fromX11Pixmap(draw, QPixmap::ExplicitlyShared);
1161 XSync(static_cast<gfxXlibSurface*>(gBufferSurface.get())->XDisplay(), False);
1162 aPainter->drawPixmap(QPoint(rect.x, rect.y), gBufferPixmap,
1163 QRect(0, 0, rect.width, rect.height));
1165 } else
1166 #endif
1167 if (gBufferSurface->GetType() == gfxASurface::SurfaceTypeImage) {
1168 // in raster mode we can just wrap gBufferImage as QImage and paint directly
1169 gfxImageSurface *imgs = static_cast<gfxImageSurface*>(gBufferSurface.get());
1170 QImage img(imgs->Data(),
1171 imgs->Width(),
1172 imgs->Height(),
1173 imgs->Stride(),
1174 _gfximage_to_qformat(imgs->Format()));
1175 aPainter->drawImage(QPoint(rect.x, rect.y), img,
1176 QRect(0, 0, rect.width, rect.height));
1178 } else if (renderMode == gfxQtPlatform::RENDER_DIRECT) {
1179 QRect trans = aPainter->transform().mapRect(r).toRect();
1180 #ifdef MOZ_X11
1181 if (gBufferSurface->GetType() == gfxASurface::SurfaceTypeXlib) {
1182 nsRefPtr<gfxASurface> widgetSurface = GetSurfaceForQWidget(aWidget);
1183 nsRefPtr<gfxContext> ctx = new gfxContext(widgetSurface);
1184 ctx->SetSource(gBufferSurface);
1185 ctx->Rectangle(gfxRect(trans.x(), trans.y(), trans.width(), trans.height()), true);
1186 ctx->Clip();
1187 ctx->Fill();
1188 } else
1189 #endif
1190 if (gBufferSurface->GetType() == gfxASurface::SurfaceTypeImage) {
1191 #ifdef MOZ_HAVE_SHMIMAGE
1192 if (gShmImage) {
1193 gShmImage->Put(aWidget, trans);
1194 } else
1195 #endif
1197 // Qt should take care about optimized rendering on QImage into painter device (gl/fb/image et.c.)
1198 gfxImageSurface *imgs = static_cast<gfxImageSurface*>(gBufferSurface.get());
1199 QImage img(imgs->Data(),
1200 imgs->Width(),
1201 imgs->Height(),
1202 imgs->Stride(),
1203 _gfximage_to_qformat(imgs->Format()));
1204 aPainter->drawImage(trans, img, trans);
1209 ctx = nullptr;
1210 targetSurface = nullptr;
1211 if (mWidgetListener)
1212 mWidgetListener->DidPaintWindow();
1214 // check the return value!
1215 return painted;
1218 nsEventStatus
1219 nsWindow::OnMoveEvent(QGraphicsSceneHoverEvent *aEvent)
1221 LOG(("configure event [%p] %d %d\n", (void *)this,
1222 aEvent->pos().x(), aEvent->pos().y()));
1224 // can we shortcut?
1225 if (!mWidget || !mWidgetListener)
1226 return nsEventStatus_eIgnore;
1228 if ((mBounds.x == aEvent->pos().x() &&
1229 mBounds.y == aEvent->pos().y()))
1231 return nsEventStatus_eIgnore;
1234 bool moved = mWidgetListener->WindowMoved(this, aEvent->pos().x(), aEvent->pos().y());
1235 return moved ? nsEventStatus_eConsumeNoDefault : nsEventStatus_eIgnore;
1238 nsEventStatus
1239 nsWindow::OnResizeEvent(QGraphicsSceneResizeEvent *aEvent)
1241 nsIntRect rect;
1243 // Generate XPFE resize event
1244 GetBounds(rect);
1246 rect.width = aEvent->newSize().width();
1247 rect.height = aEvent->newSize().height();
1249 mBounds.width = rect.width;
1250 mBounds.height = rect.height;
1252 nsEventStatus status;
1253 DispatchResizeEvent(rect, status);
1254 return status;
1257 nsEventStatus
1258 nsWindow::OnCloseEvent(QCloseEvent *aEvent)
1260 if (!mWidgetListener)
1261 return nsEventStatus_eIgnore;
1262 mWidgetListener->RequestWindowClose(this);
1263 return nsEventStatus_eConsumeNoDefault;
1266 nsEventStatus
1267 nsWindow::OnEnterNotifyEvent(QGraphicsSceneHoverEvent *aEvent)
1269 nsMouseEvent event(true, NS_MOUSE_ENTER, this, nsMouseEvent::eReal);
1271 event.refPoint.x = nscoord(aEvent->pos().x());
1272 event.refPoint.y = nscoord(aEvent->pos().y());
1274 LOG(("OnEnterNotify: %p\n", (void *)this));
1276 return DispatchEvent(&event);
1279 nsEventStatus
1280 nsWindow::OnLeaveNotifyEvent(QGraphicsSceneHoverEvent *aEvent)
1282 nsMouseEvent event(true, NS_MOUSE_EXIT, this, nsMouseEvent::eReal);
1284 event.refPoint.x = nscoord(aEvent->pos().x());
1285 event.refPoint.y = nscoord(aEvent->pos().y());
1287 LOG(("OnLeaveNotify: %p\n", (void *)this));
1289 return DispatchEvent(&event);
1292 // Block the mouse events if user was recently executing gestures;
1293 // otherwise there will be also some panning during/after gesture
1294 #if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0))
1295 #define CHECK_MOUSE_BLOCKED { \
1296 if (mLastMultiTouchTime.isValid()) { \
1297 if (mLastMultiTouchTime.elapsed() < GESTURES_BLOCK_MOUSE_FOR) \
1298 return nsEventStatus_eIgnore; \
1299 else \
1300 mLastMultiTouchTime = QTime(); \
1303 #else
1304 define CHECK_MOUSE_BLOCKED {}
1305 #endif
1307 nsEventStatus
1308 nsWindow::OnMotionNotifyEvent(QPointF aPos, Qt::KeyboardModifiers aModifiers)
1310 UserActivity();
1312 CHECK_MOUSE_BLOCKED
1314 mMoveEvent.pos = aPos;
1315 mMoveEvent.modifiers = aModifiers;
1316 mMoveEvent.needDispatch = true;
1317 DispatchMotionToMainThread();
1319 return nsEventStatus_eIgnore;
1322 void
1323 nsWindow::InitButtonEvent(nsMouseEvent &aMoveEvent,
1324 QGraphicsSceneMouseEvent *aEvent, int aClickCount)
1326 aMoveEvent.refPoint.x = nscoord(aEvent->pos().x());
1327 aMoveEvent.refPoint.y = nscoord(aEvent->pos().y());
1329 aMoveEvent.InitBasicModifiers(aEvent->modifiers() & Qt::ControlModifier,
1330 aEvent->modifiers() & Qt::AltModifier,
1331 aEvent->modifiers() & Qt::ShiftModifier,
1332 aEvent->modifiers() & Qt::MetaModifier);
1333 aMoveEvent.clickCount = aClickCount;
1336 nsEventStatus
1337 nsWindow::OnButtonPressEvent(QGraphicsSceneMouseEvent *aEvent)
1339 // The user has done something.
1340 UserActivity();
1342 CHECK_MOUSE_BLOCKED
1344 QPointF pos = aEvent->pos();
1346 // we check against the widgets geometry, so use parent coordinates
1347 // for the check
1348 if (mWidget)
1349 pos = mWidget->mapToParent(pos);
1351 if (CheckForRollup( pos.x(), pos.y(), false))
1352 return nsEventStatus_eIgnore;
1354 uint16_t domButton;
1355 switch (aEvent->button()) {
1356 case Qt::MidButton:
1357 domButton = nsMouseEvent::eMiddleButton;
1358 break;
1359 case Qt::RightButton:
1360 domButton = nsMouseEvent::eRightButton;
1361 break;
1362 default:
1363 domButton = nsMouseEvent::eLeftButton;
1364 break;
1367 nsMouseEvent event(true, NS_MOUSE_BUTTON_DOWN, this, nsMouseEvent::eReal);
1368 event.button = domButton;
1369 InitButtonEvent(event, aEvent, 1);
1371 LOG(("%s [%p] button: %d\n", __PRETTY_FUNCTION__, (void*)this, domButton));
1373 nsEventStatus status = DispatchEvent(&event);
1375 // right menu click on linux should also pop up a context menu
1376 if (domButton == nsMouseEvent::eRightButton &&
1377 MOZ_LIKELY(!mIsDestroyed)) {
1378 nsMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this,
1379 nsMouseEvent::eReal);
1380 InitButtonEvent(contextMenuEvent, aEvent, 1);
1381 DispatchEvent(&contextMenuEvent, status);
1384 return status;
1387 nsEventStatus
1388 nsWindow::OnButtonReleaseEvent(QGraphicsSceneMouseEvent *aEvent)
1390 UserActivity();
1391 CHECK_MOUSE_BLOCKED
1393 // The user has done something.
1394 UserActivity();
1396 uint16_t domButton;
1398 switch (aEvent->button()) {
1399 case Qt::MidButton:
1400 domButton = nsMouseEvent::eMiddleButton;
1401 break;
1402 case Qt::RightButton:
1403 domButton = nsMouseEvent::eRightButton;
1404 break;
1405 default:
1406 domButton = nsMouseEvent::eLeftButton;
1407 break;
1410 LOG(("%s [%p] button: %d\n", __PRETTY_FUNCTION__, (void*)this, domButton));
1412 nsMouseEvent event(true, NS_MOUSE_BUTTON_UP, this, nsMouseEvent::eReal);
1413 event.button = domButton;
1414 InitButtonEvent(event, aEvent, 1);
1416 nsEventStatus status = DispatchEvent(&event);
1418 return status;
1421 nsEventStatus
1422 nsWindow::OnMouseDoubleClickEvent(QGraphicsSceneMouseEvent *aEvent)
1424 uint32_t eventType;
1426 switch (aEvent->button()) {
1427 case Qt::MidButton:
1428 eventType = nsMouseEvent::eMiddleButton;
1429 break;
1430 case Qt::RightButton:
1431 eventType = nsMouseEvent::eRightButton;
1432 break;
1433 default:
1434 eventType = nsMouseEvent::eLeftButton;
1435 break;
1438 nsMouseEvent event(true, NS_MOUSE_DOUBLECLICK, this, nsMouseEvent::eReal);
1439 event.button = eventType;
1441 InitButtonEvent(event, aEvent, 2);
1442 //pressed
1443 return DispatchEvent(&event);
1446 nsEventStatus
1447 nsWindow::OnFocusInEvent(QEvent *aEvent)
1449 LOGFOCUS(("OnFocusInEvent [%p]\n", (void *)this));
1451 if (!mWidget)
1452 return nsEventStatus_eIgnore;
1454 DispatchActivateEventOnTopLevelWindow();
1456 LOGFOCUS(("Events sent from focus in event [%p]\n", (void *)this));
1457 return nsEventStatus_eIgnore;
1460 nsEventStatus
1461 nsWindow::OnFocusOutEvent(QEvent *aEvent)
1463 LOGFOCUS(("OnFocusOutEvent [%p]\n", (void *)this));
1465 if (!mWidget)
1466 return nsEventStatus_eIgnore;
1468 #if MOZ_PLATFORM_MAEMO > 5
1469 if (((QFocusEvent*)aEvent)->reason() == Qt::OtherFocusReason
1470 && mWidget->isVKBOpen()) {
1471 // We assume that the VKB was open in this case, because of the focus
1472 // reason and clear the focus in the active window.
1473 nsCOMPtr<nsIFocusManager> fm = do_GetService("@mozilla.org/focus-manager;1");
1474 if (fm) {
1475 nsCOMPtr<nsIDOMWindow> domWindow;
1476 fm->GetActiveWindow(getter_AddRefs(domWindow));
1477 fm->ClearFocus(domWindow);
1480 return nsEventStatus_eIgnore;
1482 #endif
1484 DispatchDeactivateEventOnTopLevelWindow();
1486 LOGFOCUS(("Done with container focus out [%p]\n", (void *)this));
1487 return nsEventStatus_eIgnore;
1490 inline bool
1491 is_latin_shortcut_key(quint32 aKeyval)
1493 return ((Qt::Key_0 <= aKeyval && aKeyval <= Qt::Key_9) ||
1494 (Qt::Key_A <= aKeyval && aKeyval <= Qt::Key_Z));
1497 nsEventStatus
1498 nsWindow::DispatchCommandEvent(nsIAtom* aCommand)
1500 nsCommandEvent event(true, nsGkAtoms::onAppCommand, aCommand, this);
1502 nsEventStatus status;
1503 DispatchEvent(&event, status);
1505 return status;
1508 nsEventStatus
1509 nsWindow::DispatchContentCommandEvent(int32_t aMsg)
1511 nsContentCommandEvent event(true, aMsg, this);
1513 nsEventStatus status;
1514 DispatchEvent(&event, status);
1516 return status;
1519 nsEventStatus
1520 nsWindow::OnKeyPressEvent(QKeyEvent *aEvent)
1522 LOGFOCUS(("OnKeyPressEvent [%p]\n", (void *)this));
1524 // The user has done something.
1525 UserActivity();
1527 bool setNoDefault = false;
1529 if (aEvent->key() == Qt::Key_AltGr) {
1530 sAltGrModifier = true;
1533 #ifdef MOZ_X11
1534 // before we dispatch a key, check if it's the context menu key.
1535 // If so, send a context menu key event instead.
1536 if (isContextMenuKeyEvent(aEvent)) {
1537 nsMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this,
1538 nsMouseEvent::eReal,
1539 nsMouseEvent::eContextMenuKey);
1540 //keyEventToContextMenuEvent(&event, &contextMenuEvent);
1541 return DispatchEvent(&contextMenuEvent);
1544 uint32_t domCharCode = 0;
1545 uint32_t domKeyCode = QtKeyCodeToDOMKeyCode(aEvent->key());
1547 // get keymap and modifier map from the Xserver
1548 Display *display = mozilla::DefaultXDisplay();
1549 int x_min_keycode = 0, x_max_keycode = 0, xkeysyms_per_keycode;
1550 XDisplayKeycodes(display, &x_min_keycode, &x_max_keycode);
1551 XModifierKeymap *xmodmap = XGetModifierMapping(display);
1552 if (!xmodmap)
1553 return nsEventStatus_eIgnore;
1555 KeySym *xkeymap = XGetKeyboardMapping(display, x_min_keycode, x_max_keycode - x_min_keycode,
1556 &xkeysyms_per_keycode);
1557 if (!xkeymap) {
1558 XFreeModifiermap(xmodmap);
1559 return nsEventStatus_eIgnore;
1562 // create modifier masks
1563 qint32 shift_mask = 0, shift_lock_mask = 0, caps_lock_mask = 0, num_lock_mask = 0;
1565 for (int i = 0; i < 8 * xmodmap->max_keypermod; ++i) {
1566 qint32 maskbit = 1 << (i / xmodmap->max_keypermod);
1567 KeyCode modkeycode = xmodmap->modifiermap[i];
1568 if (modkeycode == NoSymbol) {
1569 continue;
1572 quint32 mapindex = (modkeycode - x_min_keycode) * xkeysyms_per_keycode;
1573 for (int j = 0; j < xkeysyms_per_keycode; ++j) {
1574 KeySym modkeysym = xkeymap[mapindex + j];
1575 switch (modkeysym) {
1576 case XK_Num_Lock:
1577 num_lock_mask |= maskbit;
1578 break;
1579 case XK_Caps_Lock:
1580 caps_lock_mask |= maskbit;
1581 break;
1582 case XK_Shift_Lock:
1583 shift_lock_mask |= maskbit;
1584 break;
1585 case XK_Shift_L:
1586 case XK_Shift_R:
1587 shift_mask |= maskbit;
1588 break;
1592 // indicate whether is down or not
1593 bool shift_state = ((shift_mask & aEvent->nativeModifiers()) != 0) ^
1594 (bool)(shift_lock_mask & aEvent->nativeModifiers());
1595 bool capslock_state = (bool)(caps_lock_mask & aEvent->nativeModifiers());
1597 // try to find a keysym that we can translate to a DOMKeyCode
1598 // this is needed because some of Qt's keycodes cannot be translated
1599 // TODO: use US keyboard keymap instead of localised keymap
1600 if (!domKeyCode &&
1601 aEvent->nativeScanCode() >= (quint32)x_min_keycode &&
1602 aEvent->nativeScanCode() <= (quint32)x_max_keycode) {
1603 int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode;
1604 for(int i = 0; (i < xkeysyms_per_keycode) && (domKeyCode == (quint32)NoSymbol); ++i) {
1605 domKeyCode = QtKeyCodeToDOMKeyCode(xkeymap[index + i]);
1609 // store character in domCharCode
1610 if (aEvent->text().length() && aEvent->text()[0].isPrint())
1611 domCharCode = (int32_t) aEvent->text()[0].unicode();
1613 KeyNameIndex keyNameIndex =
1614 domCharCode ? KEY_NAME_INDEX_PrintableKey :
1615 QtKeyCodeToDOMKeyNameIndex(aEvent->key());
1617 // If the key isn't autorepeat, we need to send the initial down event
1618 if (!aEvent->isAutoRepeat() && !IsKeyDown(domKeyCode)) {
1619 // send the key down event
1621 SetKeyDownFlag(domKeyCode);
1623 nsKeyEvent downEvent(true, NS_KEY_DOWN, this);
1624 InitKeyEvent(downEvent, aEvent);
1626 downEvent.keyCode = domKeyCode;
1627 downEvent.mKeyNameIndex = keyNameIndex;
1629 nsEventStatus status = DispatchEvent(&downEvent);
1631 // DispatchEvent can Destroy us (bug 378273)
1632 if (MOZ_UNLIKELY(mIsDestroyed)) {
1633 qWarning() << "Returning[" << __LINE__ << "]: " << "Window destroyed";
1634 return status;
1637 // If prevent default on keydown, do same for keypress
1638 if (status == nsEventStatus_eConsumeNoDefault)
1639 setNoDefault = true;
1642 // Don't pass modifiers as NS_KEY_PRESS events.
1643 // Instead of selectively excluding some keys from NS_KEY_PRESS events,
1644 // we instead selectively include (as per MSDN spec
1645 // ( http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keypress%28VS.71%29.aspx );
1646 // no official spec covers KeyPress events).
1647 if (aEvent->key() == Qt::Key_Shift ||
1648 aEvent->key() == Qt::Key_Control ||
1649 aEvent->key() == Qt::Key_Meta ||
1650 aEvent->key() == Qt::Key_Alt ||
1651 aEvent->key() == Qt::Key_AltGr) {
1653 return setNoDefault ?
1654 nsEventStatus_eConsumeNoDefault :
1655 nsEventStatus_eIgnore;
1658 // Look for specialized app-command keys
1659 switch (aEvent->key()) {
1660 case Qt::Key_Back:
1661 return DispatchCommandEvent(nsGkAtoms::Back);
1662 case Qt::Key_Forward:
1663 return DispatchCommandEvent(nsGkAtoms::Forward);
1664 case Qt::Key_Refresh:
1665 return DispatchCommandEvent(nsGkAtoms::Reload);
1666 case Qt::Key_Stop:
1667 return DispatchCommandEvent(nsGkAtoms::Stop);
1668 case Qt::Key_Search:
1669 return DispatchCommandEvent(nsGkAtoms::Search);
1670 case Qt::Key_Favorites:
1671 return DispatchCommandEvent(nsGkAtoms::Bookmarks);
1672 case Qt::Key_HomePage:
1673 return DispatchCommandEvent(nsGkAtoms::Home);
1674 case Qt::Key_Copy:
1675 case Qt::Key_F16: // F16, F20, F18, F14 are old keysyms for Copy Cut Paste Undo
1676 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_COPY);
1677 case Qt::Key_Cut:
1678 case Qt::Key_F20:
1679 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_CUT);
1680 case Qt::Key_Paste:
1681 case Qt::Key_F18:
1682 case Qt::Key_F9:
1683 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_PASTE);
1684 case Qt::Key_F14:
1685 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_UNDO);
1688 // Qt::Key_Redo and Qt::Key_Undo are not available yet.
1689 if (aEvent->nativeVirtualKey() == 0xff66) {
1690 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_REDO);
1692 if (aEvent->nativeVirtualKey() == 0xff65) {
1693 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_UNDO);
1696 nsKeyEvent event(true, NS_KEY_PRESS, this);
1697 InitKeyEvent(event, aEvent);
1699 // If prevent default on keydown, do same for keypress
1700 if (setNoDefault) {
1701 event.mFlags.mDefaultPrevented = true;
1704 // If there is no charcode attainable from the text, try to
1705 // generate it from the keycode. Check shift state for case
1706 // Also replace the charcode if ControlModifier is the only
1707 // pressed Modifier
1708 if ((!domCharCode) &&
1709 (QApplication::keyboardModifiers() &
1710 (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) {
1712 // get a character from X11 key map
1713 KeySym keysym = aEvent->nativeVirtualKey();
1714 if (keysym) {
1715 domCharCode = (uint32_t) keysym2ucs(keysym);
1716 if (domCharCode == -1 || !QChar((quint32)domCharCode).isPrint()) {
1717 domCharCode = 0;
1721 // if Ctrl is pressed and domCharCode is not a ASCII character
1722 if (domCharCode > 0xFF && (QApplication::keyboardModifiers() & Qt::ControlModifier)) {
1723 // replace Unicode character
1724 int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode;
1725 for (int i = 0; i < xkeysyms_per_keycode; ++i) {
1726 if (xkeymap[index + i] <= 0xFF && !shift_state) {
1727 domCharCode = (uint32_t) QChar::toLower((uint) xkeymap[index + i]);
1728 break;
1733 } else { // The key event should cause a character input.
1734 // At that time, we need to reset the modifiers
1735 // because nsEditor will not accept a key event
1736 // for text input if one or more modifiers are set.
1737 event.modifiers &= ~(widget::MODIFIER_CONTROL |
1738 widget::MODIFIER_ALT |
1739 widget::MODIFIER_META);
1742 KeySym keysym = NoSymbol;
1743 int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode;
1744 for (int i = 0; i < xkeysyms_per_keycode; ++i) {
1745 if (xkeymap[index + i] == aEvent->nativeVirtualKey()) {
1746 if ((i % 2) == 0) { // shifted char
1747 keysym = xkeymap[index + i + 1];
1748 break;
1749 } else { // unshifted char
1750 keysym = xkeymap[index + i - 1];
1751 break;
1754 if (xkeysyms_per_keycode - 1 == i) {
1755 qWarning() << "Symbol '" << aEvent->nativeVirtualKey() << "' not found";
1758 QChar unshiftedChar(domCharCode);
1759 long ucs = keysym2ucs(keysym);
1760 ucs = ucs == -1 ? 0 : ucs;
1761 QChar shiftedChar((uint)ucs);
1763 // append alternativeCharCodes if modifier is pressed
1764 // append an additional alternativeCharCodes if domCharCode is not a Latin character
1765 // and if one of these modifiers is pressed (i.e. Ctrl, Alt, Meta)
1766 if (domCharCode &&
1767 (QApplication::keyboardModifiers() &
1768 (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) {
1770 event.charCode = domCharCode;
1771 event.keyCode = 0;
1772 nsAlternativeCharCode altCharCode(0, 0);
1773 // if character has a lower and upper representation
1774 if ((unshiftedChar.isUpper() || unshiftedChar.isLower()) &&
1775 unshiftedChar.toLower() == shiftedChar.toLower()) {
1776 if (shift_state ^ capslock_state) {
1777 altCharCode.mUnshiftedCharCode = (uint32_t) QChar::toUpper((uint)domCharCode);
1778 altCharCode.mShiftedCharCode = (uint32_t) QChar::toLower((uint)domCharCode);
1779 } else {
1780 altCharCode.mUnshiftedCharCode = (uint32_t) QChar::toLower((uint)domCharCode);
1781 altCharCode.mShiftedCharCode = (uint32_t) QChar::toUpper((uint)domCharCode);
1783 } else {
1784 altCharCode.mUnshiftedCharCode = (uint32_t) unshiftedChar.unicode();
1785 altCharCode.mShiftedCharCode = (uint32_t) shiftedChar.unicode();
1788 // append alternative char code to event
1789 if ((altCharCode.mUnshiftedCharCode && altCharCode.mUnshiftedCharCode != domCharCode) ||
1790 (altCharCode.mShiftedCharCode && altCharCode.mShiftedCharCode != domCharCode)) {
1791 event.alternativeCharCodes.AppendElement(altCharCode);
1794 // check if the alternative char codes are latin-1
1795 if (altCharCode.mUnshiftedCharCode > 0xFF || altCharCode.mShiftedCharCode > 0xFF) {
1796 altCharCode.mUnshiftedCharCode = altCharCode.mShiftedCharCode = 0;
1798 // find latin char for keycode
1799 KeySym keysym = NoSymbol;
1800 int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode;
1801 // find first shifted and unshifted Latin-Char in XKeyMap
1802 for (int i = 0; i < xkeysyms_per_keycode; ++i) {
1803 keysym = xkeymap[index + i];
1804 if (keysym && keysym <= 0xFF) {
1805 if ((shift_state && (i % 2 == 1)) ||
1806 (!shift_state && (i % 2 == 0))) {
1807 altCharCode.mUnshiftedCharCode = altCharCode.mUnshiftedCharCode ?
1808 altCharCode.mUnshiftedCharCode :
1809 keysym;
1810 } else {
1811 altCharCode.mShiftedCharCode = altCharCode.mShiftedCharCode ?
1812 altCharCode.mShiftedCharCode :
1813 keysym;
1815 if (altCharCode.mUnshiftedCharCode && altCharCode.mShiftedCharCode) {
1816 break;
1821 if (altCharCode.mUnshiftedCharCode || altCharCode.mShiftedCharCode) {
1822 event.alternativeCharCodes.AppendElement(altCharCode);
1825 } else {
1826 event.charCode = domCharCode;
1829 if (xmodmap) {
1830 XFreeModifiermap(xmodmap);
1832 if (xkeymap) {
1833 XFree(xkeymap);
1836 event.keyCode = domCharCode ? 0 : domKeyCode;
1837 event.mKeyNameIndex = keyNameIndex;
1838 // send the key press event
1839 return DispatchEvent(&event);
1840 #else
1842 //:TODO: fix shortcuts hebrew for non X11,
1843 //see Bug 562195##51
1845 // before we dispatch a key, check if it's the context menu key.
1846 // If so, send a context menu key event instead.
1847 if (isContextMenuKeyEvent(aEvent)) {
1848 nsMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this,
1849 nsMouseEvent::eReal,
1850 nsMouseEvent::eContextMenuKey);
1851 //keyEventToContextMenuEvent(&event, &contextMenuEvent);
1852 return DispatchEvent(&contextMenuEvent);
1855 uint32_t domCharCode = 0;
1856 uint32_t domKeyCode = QtKeyCodeToDOMKeyCode(aEvent->key());
1858 if (aEvent->text().length() && aEvent->text()[0].isPrint())
1859 domCharCode = (int32_t) aEvent->text()[0].unicode();
1861 KeyNameIndex keyNameIndex =
1862 domCharCode ? KEY_NAME_INDEX_PrintableKey :
1863 QtKeyCodeToDOMKeyNameIndex(aEvent->key());
1865 // If the key isn't autorepeat, we need to send the initial down event
1866 if (!aEvent->isAutoRepeat() && !IsKeyDown(domKeyCode)) {
1867 // send the key down event
1869 SetKeyDownFlag(domKeyCode);
1871 nsKeyEvent downEvent(true, NS_KEY_DOWN, this);
1872 InitKeyEvent(downEvent, aEvent);
1874 downEvent.keyCode = domKeyCode;
1875 downEvent.mKeyNameIndex = keyNameIndex;
1877 nsEventStatus status = DispatchEvent(&downEvent);
1879 // If prevent default on keydown, do same for keypress
1880 if (status == nsEventStatus_eConsumeNoDefault)
1881 setNoDefault = true;
1884 nsKeyEvent event(true, NS_KEY_PRESS, this);
1885 InitKeyEvent(event, aEvent);
1887 event.charCode = domCharCode;
1889 event.keyCode = domCharCode ? 0 : domKeyCode;
1890 event.mKeyNameIndex = keyNameIndex;
1892 if (setNoDefault)
1893 event.mFlags.mDefaultPrevented = true;
1895 // send the key press event
1896 return DispatchEvent(&event);
1897 #endif
1900 nsEventStatus
1901 nsWindow::OnKeyReleaseEvent(QKeyEvent *aEvent)
1903 LOGFOCUS(("OnKeyReleaseEvent [%p]\n", (void *)this));
1905 // The user has done something.
1906 UserActivity();
1908 if (isContextMenuKeyEvent(aEvent)) {
1909 // er, what do we do here? DoDefault or NoDefault?
1910 return nsEventStatus_eConsumeDoDefault;
1913 uint32_t domKeyCode = QtKeyCodeToDOMKeyCode(aEvent->key());
1915 #ifdef MOZ_X11
1916 if (!domKeyCode) {
1917 // get keymap from the Xserver
1918 Display *display = mozilla::DefaultXDisplay();
1919 int x_min_keycode = 0, x_max_keycode = 0, xkeysyms_per_keycode;
1920 XDisplayKeycodes(display, &x_min_keycode, &x_max_keycode);
1921 KeySym *xkeymap = XGetKeyboardMapping(display, x_min_keycode, x_max_keycode - x_min_keycode,
1922 &xkeysyms_per_keycode);
1924 if (aEvent->nativeScanCode() >= (quint32)x_min_keycode &&
1925 aEvent->nativeScanCode() <= (quint32)x_max_keycode) {
1926 int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode;
1927 for(int i = 0; (i < xkeysyms_per_keycode) && (domKeyCode == (quint32)NoSymbol); ++i) {
1928 domKeyCode = QtKeyCodeToDOMKeyCode(xkeymap[index + i]);
1932 if (xkeymap) {
1933 XFree(xkeymap);
1936 #endif // MOZ_X11
1938 // send the key event as a key up event
1939 nsKeyEvent event(true, NS_KEY_UP, this);
1940 InitKeyEvent(event, aEvent);
1942 if (aEvent->key() == Qt::Key_AltGr) {
1943 sAltGrModifier = false;
1946 event.keyCode = domKeyCode;
1947 event.mKeyNameIndex =
1948 (aEvent->text().length() && aEvent->text()[0].isPrint()) ?
1949 KEY_NAME_INDEX_PrintableKey :
1950 QtKeyCodeToDOMKeyNameIndex(aEvent->key());
1952 // unset the key down flag
1953 ClearKeyDownFlag(event.keyCode);
1955 return DispatchEvent(&event);
1958 nsEventStatus
1959 nsWindow::OnScrollEvent(QGraphicsSceneWheelEvent *aEvent)
1961 // check to see if we should rollup
1962 WheelEvent wheelEvent(true, NS_WHEEL_WHEEL, this);
1963 wheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE;
1965 // negative values for aEvent->delta indicate downward scrolling;
1966 // this is opposite Gecko usage.
1967 // TODO: Store the unused delta values due to fraction round and add it
1968 // to next event. The stored values should be reset by other
1969 // direction scroll event.
1970 int32_t delta = (int)(aEvent->delta() / WHEEL_DELTA) * -3;
1972 switch (aEvent->orientation()) {
1973 case Qt::Vertical:
1974 wheelEvent.deltaY = wheelEvent.lineOrPageDeltaY = delta;
1975 break;
1976 case Qt::Horizontal:
1977 wheelEvent.deltaX = wheelEvent.lineOrPageDeltaX = delta;
1978 break;
1979 default:
1980 Q_ASSERT(0);
1981 break;
1984 wheelEvent.refPoint.x = nscoord(aEvent->scenePos().x());
1985 wheelEvent.refPoint.y = nscoord(aEvent->scenePos().y());
1987 wheelEvent.InitBasicModifiers(aEvent->modifiers() & Qt::ControlModifier,
1988 aEvent->modifiers() & Qt::AltModifier,
1989 aEvent->modifiers() & Qt::ShiftModifier,
1990 aEvent->modifiers() & Qt::MetaModifier);
1991 wheelEvent.time = 0;
1993 return DispatchEvent(&wheelEvent);
1997 nsEventStatus
1998 nsWindow::showEvent(QShowEvent *)
2000 LOG(("%s [%p]\n", __PRETTY_FUNCTION__,(void *)this));
2001 mIsVisible = true;
2002 return nsEventStatus_eConsumeDoDefault;
2005 nsEventStatus
2006 nsWindow::hideEvent(QHideEvent *)
2008 LOG(("%s [%p]\n", __PRETTY_FUNCTION__,(void *)this));
2009 mIsVisible = false;
2010 return nsEventStatus_eConsumeDoDefault;
2013 //Gestures are only supported in 4.6.0 >
2014 #if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0))
2015 nsEventStatus nsWindow::OnTouchEvent(QTouchEvent *event, bool &handled)
2017 handled = false;
2018 const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
2020 if (event->type() == QEvent::TouchBegin) {
2021 handled = true;
2022 for (int i = touchPoints.count() -1; i >= 0; i--) {
2023 QPointF fpos = touchPoints[i].pos();
2024 nsGestureNotifyEvent gestureNotifyEvent(true, NS_GESTURENOTIFY_EVENT_START, this);
2025 gestureNotifyEvent.refPoint = nsIntPoint(fpos.x(), fpos.y());
2026 DispatchEvent(&gestureNotifyEvent);
2029 else if (event->type() == QEvent::TouchEnd) {
2030 mGesturesCancelled = false;
2031 mPinchEvent.needDispatch = false;
2034 if (touchPoints.count() > 0) {
2035 // Remember start touch point in order to use it for
2036 // distance calculation in NS_SIMPLE_GESTURE_MAGNIFY_UPDATE
2037 mPinchEvent.touchPoint = touchPoints.at(0).pos();
2040 return nsEventStatus_eIgnore;
2043 nsEventStatus
2044 nsWindow::OnGestureEvent(QGestureEvent* event, bool &handled) {
2046 handled = false;
2047 if (mGesturesCancelled) {
2048 return nsEventStatus_eIgnore;
2051 nsEventStatus result = nsEventStatus_eIgnore;
2053 QGesture* gesture = event->gesture(Qt::PinchGesture);
2055 if (gesture) {
2056 QPinchGesture* pinch = static_cast<QPinchGesture*>(gesture);
2057 handled = true;
2059 mPinchEvent.centerPoint =
2060 mWidget->mapFromScene(event->mapToGraphicsScene(pinch->centerPoint()));
2061 nsIntPoint centerPoint(mPinchEvent.centerPoint.x(),
2062 mPinchEvent.centerPoint.y());
2064 if (pinch->state() == Qt::GestureStarted) {
2065 event->accept();
2066 mPinchEvent.startDistance = DistanceBetweenPoints(mPinchEvent.centerPoint, mPinchEvent.touchPoint) * 2;
2067 mPinchEvent.prevDistance = mPinchEvent.startDistance;
2068 result = DispatchGestureEvent(NS_SIMPLE_GESTURE_MAGNIFY_START,
2069 0, 0, centerPoint);
2071 else if (pinch->state() == Qt::GestureUpdated) {
2072 mPinchEvent.needDispatch = true;
2073 mPinchEvent.delta = 0;
2074 DispatchMotionToMainThread();
2076 else if (pinch->state() == Qt::GestureFinished) {
2077 double distance = DistanceBetweenPoints(mPinchEvent.centerPoint, mPinchEvent.touchPoint) * 2;
2078 double delta = distance - mPinchEvent.startDistance;
2079 result = DispatchGestureEvent(NS_SIMPLE_GESTURE_MAGNIFY,
2080 0, delta, centerPoint);
2081 mPinchEvent.needDispatch = false;
2083 else {
2084 handled = false;
2087 //Disable mouse events when gestures are used, because they cause problems with
2088 //Fennec
2089 mLastMultiTouchTime.start();
2092 gesture = event->gesture(gSwipeGestureId);
2093 if (gesture) {
2094 if (gesture->state() == Qt::GestureStarted) {
2095 event->accept();
2097 if (gesture->state() == Qt::GestureFinished) {
2098 event->accept();
2099 handled = true;
2101 MozSwipeGesture* swipe = static_cast<MozSwipeGesture*>(gesture);
2102 nsIntPoint hotspot;
2103 hotspot.x = swipe->hotSpot().x();
2104 hotspot.y = swipe->hotSpot().y();
2106 // Cancel pinch gesture
2107 mGesturesCancelled = true;
2108 mPinchEvent.needDispatch = false;
2110 double distance = DistanceBetweenPoints(swipe->hotSpot(), mPinchEvent.touchPoint) * 2;
2111 double delta = distance - mPinchEvent.startDistance;
2113 DispatchGestureEvent(NS_SIMPLE_GESTURE_MAGNIFY, 0, delta / 2, hotspot);
2115 result = DispatchGestureEvent(NS_SIMPLE_GESTURE_SWIPE,
2116 swipe->Direction(), 0, hotspot);
2118 mLastMultiTouchTime.start();
2121 return result;
2124 nsEventStatus
2125 nsWindow::DispatchGestureEvent(uint32_t aMsg, uint32_t aDirection,
2126 double aDelta, const nsIntPoint& aRefPoint)
2128 nsSimpleGestureEvent mozGesture(true, aMsg, this, 0, 0.0);
2129 mozGesture.direction = aDirection;
2130 mozGesture.delta = aDelta;
2131 mozGesture.refPoint = aRefPoint;
2133 Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers();
2135 mozGesture.InitBasicModifiers(modifiers & Qt::ControlModifier,
2136 modifiers & Qt::AltModifier,
2137 modifiers & Qt::ShiftModifier,
2138 false);
2139 mozGesture.button = 0;
2140 mozGesture.time = 0;
2142 return DispatchEvent(&mozGesture);
2146 double
2147 nsWindow::DistanceBetweenPoints(const QPointF &aFirstPoint, const QPointF &aSecondPoint)
2149 double result = 0;
2150 double deltaX = abs(aFirstPoint.x() - aSecondPoint.x());
2151 double deltaY = abs(aFirstPoint.y() - aSecondPoint.y());
2152 result = sqrt(deltaX*deltaX + deltaY*deltaY);
2153 return result;
2156 #endif //qt version check
2158 void
2159 nsWindow::ThemeChanged()
2161 NotifyThemeChanged();
2164 nsEventStatus
2165 nsWindow::OnDragMotionEvent(QGraphicsSceneDragDropEvent *aEvent)
2167 LOG(("nsWindow::OnDragMotionSignal\n"));
2169 nsMouseEvent event(true, NS_DRAGDROP_OVER, 0,
2170 nsMouseEvent::eReal);
2171 return nsEventStatus_eIgnore;
2174 nsEventStatus
2175 nsWindow::OnDragLeaveEvent(QGraphicsSceneDragDropEvent *aEvent)
2177 // XXX Do we want to pass this on only if the event's subwindow is null?
2178 LOG(("nsWindow::OnDragLeaveSignal(%p)\n", this));
2179 nsMouseEvent event(true, NS_DRAGDROP_EXIT, this, nsMouseEvent::eReal);
2181 return DispatchEvent(&event);
2184 nsEventStatus
2185 nsWindow::OnDragDropEvent(QGraphicsSceneDragDropEvent *aDropEvent)
2187 if (aDropEvent->proposedAction() == Qt::CopyAction)
2189 printf("text version of the data: %s\n", aDropEvent->mimeData()->text().toUtf8().data());
2190 aDropEvent->acceptProposedAction();
2193 LOG(("nsWindow::OnDragDropSignal\n"));
2194 nsMouseEvent event(true, NS_DRAGDROP_OVER, 0,
2195 nsMouseEvent::eReal);
2196 return nsEventStatus_eIgnore;
2199 nsEventStatus
2200 nsWindow::OnDragEnter(QGraphicsSceneDragDropEvent *aDragEvent)
2202 // Is it some format we think we can support?
2203 if ( aDragEvent->mimeData()->hasFormat(kURLMime)
2204 || aDragEvent->mimeData()->hasFormat(kURLDataMime)
2205 || aDragEvent->mimeData()->hasFormat(kURLDescriptionMime)
2206 || aDragEvent->mimeData()->hasFormat(kHTMLMime)
2207 || aDragEvent->mimeData()->hasFormat(kUnicodeMime)
2208 || aDragEvent->mimeData()->hasFormat(kTextMime)
2211 aDragEvent->acceptProposedAction();
2214 // XXX Do we want to pass this on only if the event's subwindow is null?
2216 LOG(("nsWindow::OnDragEnter(%p)\n", this));
2218 nsMouseEvent event(true, NS_DRAGDROP_ENTER, this, nsMouseEvent::eReal);
2219 return DispatchEvent(&event);
2222 static void
2223 GetBrandName(nsXPIDLString& brandName)
2225 nsCOMPtr<nsIStringBundleService> bundleService =
2226 mozilla::services::GetStringBundleService();
2228 nsCOMPtr<nsIStringBundle> bundle;
2229 if (bundleService)
2230 bundleService->CreateBundle(
2231 "chrome://branding/locale/brand.properties",
2232 getter_AddRefs(bundle));
2234 if (bundle)
2235 bundle->GetStringFromName(
2236 NS_LITERAL_STRING("brandShortName").get(),
2237 getter_Copies(brandName));
2239 if (brandName.IsEmpty())
2240 brandName.Assign(NS_LITERAL_STRING("Mozilla"));
2244 nsresult
2245 nsWindow::Create(nsIWidget *aParent,
2246 nsNativeWidget aNativeParent,
2247 const nsIntRect &aRect,
2248 nsDeviceContext *aContext,
2249 nsWidgetInitData *aInitData)
2251 // only set the base parent if we're not going to be a dialog or a
2252 // toplevel
2253 nsIWidget *baseParent = aParent;
2255 if (aInitData &&
2256 (aInitData->mWindowType == eWindowType_dialog ||
2257 aInitData->mWindowType == eWindowType_toplevel ||
2258 aInitData->mWindowType == eWindowType_invisible)) {
2260 baseParent = nullptr;
2261 // also drop native parent for toplevel windows
2262 aNativeParent = nullptr;
2265 // initialize all the common bits of this class
2266 BaseCreate(baseParent, aRect, aContext, aInitData);
2268 // and do our common creation
2269 mParent = aParent;
2271 // save our bounds
2272 mBounds = aRect;
2274 // find native parent
2275 MozQWidget *parent = nullptr;
2277 if (aParent != nullptr)
2278 parent = static_cast<MozQWidget*>(aParent->GetNativeData(NS_NATIVE_WIDGET));
2280 // ok, create our QGraphicsWidget
2281 mWidget = createQWidget(parent, aNativeParent, aInitData);
2283 if (!mWidget)
2284 return NS_ERROR_OUT_OF_MEMORY;
2286 LOG(("Create: nsWindow [%p] [%p]\n", (void *)this, (void *)mWidget));
2288 // resize so that everything is set to the right dimensions
2289 Resize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, false);
2291 // check if we should listen for resizes
2292 mListenForResizes = (aNativeParent ||
2293 (aInitData && aInitData->mListenForResizes));
2295 return NS_OK;
2298 already_AddRefed<nsIWidget>
2299 nsWindow::CreateChild(const nsIntRect& aRect,
2300 nsDeviceContext* aContext,
2301 nsWidgetInitData* aInitData,
2302 bool /*aForceUseIWidgetParent*/)
2304 //We need to force parent widget, otherwise GetTopLevelWindow doesn't work
2305 return nsBaseWidget::CreateChild(aRect,
2306 aContext,
2307 aInitData,
2308 true); // Force parent
2312 NS_IMETHODIMP
2313 nsWindow::SetWindowClass(const nsAString &xulWinType)
2315 if (!mWidget)
2316 return NS_ERROR_FAILURE;
2318 nsXPIDLString brandName;
2319 GetBrandName(brandName);
2321 #ifdef MOZ_X11
2322 XClassHint *class_hint = XAllocClassHint();
2323 if (!class_hint)
2324 return NS_ERROR_OUT_OF_MEMORY;
2325 const char *role = NULL;
2326 class_hint->res_name = ToNewCString(xulWinType);
2327 if (!class_hint->res_name) {
2328 XFree(class_hint);
2329 return NS_ERROR_OUT_OF_MEMORY;
2331 class_hint->res_class = ToNewCString(brandName);
2332 if (!class_hint->res_class) {
2333 nsMemory::Free(class_hint->res_name);
2334 XFree(class_hint);
2335 return NS_ERROR_OUT_OF_MEMORY;
2338 // Parse res_name into a name and role. Characters other than
2339 // [A-Za-z0-9_-] are converted to '_'. Anything after the first
2340 // colon is assigned to role; if there's no colon, assign the
2341 // whole thing to both role and res_name.
2342 for (char *c = class_hint->res_name; *c; c++) {
2343 if (':' == *c) {
2344 *c = 0;
2345 role = c + 1;
2347 else if (!isascii(*c) || (!isalnum(*c) && ('_' != *c) && ('-' != *c)))
2348 *c = '_';
2350 class_hint->res_name[0] = toupper(class_hint->res_name[0]);
2351 if (!role) role = class_hint->res_name;
2353 QWidget *widget = GetViewWidget();
2354 // If widget not show, handle might be null
2355 if (widget && widget->winId())
2356 XSetClassHint(gfxQtPlatform::GetXDisplay(widget),
2357 widget->winId(),
2358 class_hint);
2360 nsMemory::Free(class_hint->res_class);
2361 nsMemory::Free(class_hint->res_name);
2362 XFree(class_hint);
2363 #endif
2365 return NS_OK;
2368 void
2369 nsWindow::NativeResize(int32_t aWidth, int32_t aHeight, bool aRepaint)
2371 LOG(("nsWindow::NativeResize [%p] %d %d\n", (void *)this,
2372 aWidth, aHeight));
2374 mNeedsResize = false;
2376 if (mIsTopLevel) {
2377 QGraphicsView *widget = qobject_cast<QGraphicsView*>(GetViewWidget());
2378 NS_ENSURE_TRUE_VOID(widget);
2379 // map from in-scene widget to scene, from scene to view.
2380 QRect r = widget->mapFromScene(mWidget->mapToScene(QRect(0, 0, aWidth, aHeight))).boundingRect();
2381 // going from QPolygon to QRect includes the points, adding one to width and height
2382 r.adjust(0, 0, -1, -1);
2383 widget->resize(r.width(), r.height());
2385 else {
2386 mWidget->resize(aWidth, aHeight);
2389 if (aRepaint)
2390 mWidget->update();
2393 void
2394 nsWindow::NativeResize(int32_t aX, int32_t aY,
2395 int32_t aWidth, int32_t aHeight,
2396 bool aRepaint)
2398 LOG(("nsWindow::NativeResize [%p] %d %d %d %d\n", (void *)this,
2399 aX, aY, aWidth, aHeight));
2401 mNeedsResize = false;
2402 mNeedsMove = false;
2404 if (mIsTopLevel) {
2405 QGraphicsView *widget = qobject_cast<QGraphicsView*>(GetViewWidget());
2406 NS_ENSURE_TRUE_VOID(widget);
2407 // map from in-scene widget to scene, from scene to view.
2408 QRect r = widget->mapFromScene(mWidget->mapToScene(QRect(aX, aY, aWidth, aHeight))).boundingRect();
2409 // going from QPolygon to QRect includes the points, adding one to width and height
2410 r.adjust(0, 0, -1, -1);
2411 widget->setGeometry(r.x(), r.y(), r.width(), r.height());
2413 else {
2414 mWidget->setGeometry(aX, aY, aWidth, aHeight);
2417 if (aRepaint)
2418 mWidget->update();
2421 void
2422 nsWindow::NativeShow(bool aAction)
2424 if (aAction) {
2425 QWidget *widget = GetViewWidget();
2426 // On e10s, we never want the child process or plugin process
2427 // to go fullscreen because if we do the window because visible
2428 // do to disabled Qt-Xembed
2429 if (widget &&
2430 !widget->isVisible())
2431 MakeFullScreen(mSizeMode == nsSizeMode_Fullscreen);
2432 mWidget->show();
2434 // unset our flag now that our window has been shown
2435 mNeedsShow = false;
2437 else
2438 mWidget->hide();
2441 NS_IMETHODIMP
2442 nsWindow::SetHasTransparentBackground(bool aTransparent)
2444 return NS_ERROR_NOT_IMPLEMENTED;
2447 NS_IMETHODIMP
2448 nsWindow::GetHasTransparentBackground(bool& aTransparent)
2450 aTransparent = mIsTransparent;
2451 return NS_OK;
2454 void *
2455 nsWindow::SetupPluginPort(void)
2457 NS_WARNING("Not implemented");
2458 return nullptr;
2461 nsresult
2462 nsWindow::SetWindowIconList(const nsTArray<nsCString> &aIconList)
2464 QIcon icon;
2466 for (uint32_t i = 0; i < aIconList.Length(); ++i) {
2467 const char *path = aIconList[i].get();
2468 LOG(("window [%p] Loading icon from %s\n", (void *)this, path));
2469 icon.addFile(path);
2472 QWidget *widget = GetViewWidget();
2473 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
2474 widget->setWindowIcon(icon);
2476 return NS_OK;
2479 void
2480 nsWindow::SetDefaultIcon(void)
2482 SetIcon(NS_LITERAL_STRING("default"));
2485 void nsWindow::QWidgetDestroyed()
2487 mWidget = nullptr;
2490 NS_IMETHODIMP
2491 nsWindow::MakeFullScreen(bool aFullScreen)
2493 QWidget *widget = GetViewWidget();
2494 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
2495 if (aFullScreen) {
2496 if (mSizeMode != nsSizeMode_Fullscreen)
2497 mLastSizeMode = mSizeMode;
2499 mSizeMode = nsSizeMode_Fullscreen;
2500 widget->showFullScreen();
2502 else {
2503 mSizeMode = mLastSizeMode;
2505 switch (mSizeMode) {
2506 case nsSizeMode_Maximized:
2507 widget->showMaximized();
2508 break;
2509 case nsSizeMode_Minimized:
2510 widget->showMinimized();
2511 break;
2512 case nsSizeMode_Normal:
2513 widget->showNormal();
2514 break;
2515 default:
2516 widget->showNormal();
2517 break;
2521 NS_ASSERTION(mLastSizeMode != nsSizeMode_Fullscreen,
2522 "mLastSizeMode should never be fullscreen");
2523 return nsBaseWidget::MakeFullScreen(aFullScreen);
2526 NS_IMETHODIMP
2527 nsWindow::HideWindowChrome(bool aShouldHide)
2529 if (!mWidget) {
2530 // Nothing to hide
2531 return NS_ERROR_FAILURE;
2534 // Sawfish, metacity, and presumably other window managers get
2535 // confused if we change the window decorations while the window
2536 // is visible.
2537 bool wasVisible = false;
2538 if (mWidget->isVisible()) {
2539 NativeShow(false);
2540 wasVisible = true;
2543 if (wasVisible) {
2544 NativeShow(true);
2547 // For some window managers, adding or removing window decorations
2548 // requires unmapping and remapping our toplevel window. Go ahead
2549 // and flush the queue here so that we don't end up with a BadWindow
2550 // error later when this happens (when the persistence timer fires
2551 // and GetWindowPos is called)
2552 QWidget *widget = GetViewWidget();
2553 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
2554 #ifdef MOZ_X11
2555 XSync(gfxQtPlatform::GetXDisplay(widget), False);
2556 #endif
2558 return NS_OK;
2561 //////////////////////////////////////////////////////////////////////
2562 // These are all of our drag and drop operations
2564 void
2565 nsWindow::InitDragEvent(nsMouseEvent &aEvent)
2567 // set the keyboard modifiers
2570 // This will update the drag action based on the information in the
2571 // drag context.
2573 /* static */
2574 nsresult
2575 initialize_prefs(void)
2577 // check to see if we should set our raise pref
2578 return NS_OK;
2581 inline bool
2582 is_context_menu_key(const nsKeyEvent& aKeyEvent)
2584 return ((aKeyEvent.keyCode == NS_VK_F10 && aKeyEvent.IsShift() &&
2585 !aKeyEvent.IsControl() && !aKeyEvent.IsMeta() &&
2586 !aKeyEvent.IsAlt()) ||
2587 (aKeyEvent.keyCode == NS_VK_CONTEXT_MENU && !aKeyEvent.IsShift() &&
2588 !aKeyEvent.IsControl() && !aKeyEvent.IsMeta() &&
2589 !aKeyEvent.IsAlt()));
2592 void
2593 key_event_to_context_menu_event(nsMouseEvent &aEvent,
2594 QKeyEvent *aGdkEvent)
2596 aEvent.refPoint = nsIntPoint(0, 0);
2597 aEvent.modifiers = 0;
2598 aEvent.time = 0;
2599 aEvent.clickCount = 1;
2602 // nsChildWindow class
2604 nsChildWindow::nsChildWindow()
2608 nsChildWindow::~nsChildWindow()
2612 nsPopupWindow::nsPopupWindow()
2614 #ifdef DEBUG_WIDGETS
2615 qDebug("===================== popup!");
2616 #endif
2619 nsPopupWindow::~nsPopupWindow()
2623 NS_IMETHODIMP_(bool)
2624 nsWindow::HasGLContext()
2626 return MozQGLWidgetWrapper::hasGLContext(qobject_cast<QGraphicsView*>(GetViewWidget()));
2629 MozQWidget*
2630 nsWindow::createQWidget(MozQWidget *parent,
2631 nsNativeWidget nativeParent,
2632 nsWidgetInitData *aInitData)
2634 const char *windowName = NULL;
2635 Qt::WindowFlags flags = Qt::Widget;
2636 QWidget *parentWidget = (parent && parent->getReceiver()) ?
2637 parent->getReceiver()->GetViewWidget() : nullptr;
2639 #ifdef DEBUG_WIDGETS
2640 qDebug("NEW WIDGET\n\tparent is %p (%s)", (void*)parent,
2641 parent ? qPrintable(parent->objectName()) : "null");
2642 #endif
2644 // ok, create our windows
2645 switch (mWindowType) {
2646 case eWindowType_dialog:
2647 windowName = "topLevelDialog";
2648 mIsTopLevel = true;
2649 flags |= Qt::Dialog;
2650 break;
2651 case eWindowType_popup:
2652 windowName = "topLevelPopup";
2653 break;
2654 case eWindowType_toplevel:
2655 windowName = "topLevelWindow";
2656 mIsTopLevel = true;
2657 break;
2658 case eWindowType_invisible:
2659 windowName = "topLevelInvisible";
2660 break;
2661 case eWindowType_child:
2662 case eWindowType_plugin:
2663 default: // sheet
2664 windowName = "paintArea";
2665 break;
2668 MozQWidget* parentQWidget = nullptr;
2669 if (parent) {
2670 parentQWidget = parent;
2671 } else if (nativeParent && nativeParent != PARENTLESS_WIDGET) {
2672 parentQWidget = static_cast<MozQWidget*>(nativeParent);
2674 MozQWidget * widget = new MozQWidget(this, parentQWidget);
2675 if (!widget)
2676 return nullptr;
2677 widget->setObjectName(QString(windowName));
2679 // make only child and plugin windows focusable
2680 if (eWindowType_child == mWindowType || eWindowType_plugin == mWindowType) {
2681 widget->setFlag(QGraphicsItem::ItemIsFocusable);
2682 widget->setFocusPolicy(Qt::WheelFocus);
2685 // create a QGraphicsView if this is a new toplevel window
2687 if (mIsTopLevel) {
2688 QGraphicsView* newView =
2689 nsFastStartup::GetStartupGraphicsView(parentWidget, widget);
2691 if (mWindowType == eWindowType_dialog) {
2692 newView->setWindowModality(Qt::WindowModal);
2695 #if defined(MOZ_PLATFORM_MAEMO) || defined(MOZ_GL_PROVIDER)
2696 if (ComputeShouldAccelerate(mUseLayersAcceleration)) {
2697 // Only create new OGL widget if it is not yet installed
2698 if (!HasGLContext()) {
2699 MozQGraphicsView *qview = qobject_cast<MozQGraphicsView*>(newView);
2700 if (qview) {
2701 qview->setGLWidgetEnabled(true);
2705 #endif
2707 if (gfxQtPlatform::GetPlatform()->GetRenderMode() == gfxQtPlatform::RENDER_DIRECT) {
2708 // Disable double buffer and system background rendering
2709 #if defined(MOZ_X11) && (QT_VERSION < QT_VERSION_CHECK(5,0,0))
2710 newView->viewport()->setAttribute(Qt::WA_PaintOnScreen, true);
2711 #endif
2712 newView->viewport()->setAttribute(Qt::WA_NoSystemBackground, true);
2714 // Enable gestures:
2715 #if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0))
2716 #if defined MOZ_ENABLE_MEEGOTOUCH
2717 // Disable default Gesture filters (speedup filtering)
2718 newView->viewport()->ungrabGesture(Qt::PanGesture);
2719 newView->viewport()->ungrabGesture(Qt::TapGesture);
2720 newView->viewport()->ungrabGesture(Qt::TapAndHoldGesture);
2721 newView->viewport()->ungrabGesture(Qt::SwipeGesture);
2722 #endif
2724 // Enable required filters
2725 newView->viewport()->grabGesture(Qt::PinchGesture);
2726 newView->viewport()->grabGesture(gSwipeGestureId);
2727 #endif
2728 newView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
2729 newView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
2731 #if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0))
2732 // Top level widget is just container, and should not be painted
2733 widget->setFlag(QGraphicsItem::ItemHasNoContents);
2734 #endif
2736 #ifdef MOZ_X11
2737 if (newView->effectiveWinId()) {
2738 XSetWindowBackgroundPixmap(mozilla::DefaultXDisplay(),
2739 newView->effectiveWinId(), None);
2741 #endif
2744 if (mWindowType == eWindowType_popup) {
2745 widget->setZValue(100);
2747 // XXX is this needed for Qt?
2748 // gdk does not automatically set the cursor for "temporary"
2749 // windows, which are what gtk uses for popups.
2750 SetCursor(eCursor_standard);
2751 } else if (mIsTopLevel) {
2752 SetDefaultIcon();
2754 #if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0))
2755 #if defined MOZ_ENABLE_MEEGOTOUCH
2756 // Disable default Gesture filters (speedup filtering)
2757 widget->ungrabGesture(Qt::PanGesture);
2758 widget->ungrabGesture(Qt::TapGesture);
2759 widget->ungrabGesture(Qt::TapAndHoldGesture);
2760 widget->ungrabGesture(Qt::SwipeGesture);
2761 #endif
2762 widget->grabGesture(Qt::PinchGesture);
2763 widget->grabGesture(gSwipeGestureId);
2764 #endif
2766 return widget;
2769 // return the gfxASurface for rendering to this widget
2770 gfxASurface*
2771 nsWindow::GetThebesSurface()
2773 /* This is really a dummy surface; this is only used when doing reflow, because
2774 * we need a RenderingContext to measure text against.
2776 if (mThebesSurface)
2777 return mThebesSurface;
2779 #ifdef CAIRO_HAS_QT_SURFACE
2780 gfxQtPlatform::RenderMode renderMode = gfxQtPlatform::GetPlatform()->GetRenderMode();
2781 if (renderMode == gfxQtPlatform::RENDER_QPAINTER) {
2782 mThebesSurface = new gfxQPainterSurface(gfxIntSize(1, 1), gfxASurface::CONTENT_COLOR);
2784 #endif
2785 if (!mThebesSurface) {
2786 gfxASurface::gfxImageFormat imageFormat = gfxASurface::ImageFormatRGB24;
2787 mThebesSurface = new gfxImageSurface(gfxIntSize(1, 1), imageFormat);
2790 return mThebesSurface;
2793 NS_IMETHODIMP
2794 nsWindow::BeginResizeDrag(nsGUIEvent* aEvent, int32_t aHorizontal, int32_t aVertical)
2796 NS_ENSURE_ARG_POINTER(aEvent);
2798 if (aEvent->eventStructType != NS_MOUSE_EVENT) {
2799 // you can only begin a resize drag with a mouse event
2800 return NS_ERROR_INVALID_ARG;
2803 nsMouseEvent* mouse_event = static_cast<nsMouseEvent*>(aEvent);
2805 if (mouse_event->button != nsMouseEvent::eLeftButton) {
2806 // you can only begin a resize drag with the left mouse button
2807 return NS_ERROR_INVALID_ARG;
2810 return NS_OK;
2813 nsEventStatus
2814 nsWindow::contextMenuEvent(QGraphicsSceneContextMenuEvent *)
2816 return nsEventStatus_eIgnore;
2819 nsEventStatus
2820 nsWindow::imComposeEvent(QInputMethodEvent *event, bool &handled)
2822 // XXX Needs to check whether this widget has been destroyed or not after
2823 // each DispatchEvent().
2825 nsCompositionEvent start(true, NS_COMPOSITION_START, this);
2826 DispatchEvent(&start);
2828 nsAutoString compositionStr(event->commitString().utf16());
2830 if (!compositionStr.IsEmpty()) {
2831 nsCompositionEvent update(true, NS_COMPOSITION_UPDATE, this);
2832 update.data = compositionStr;
2833 DispatchEvent(&update);
2836 nsTextEvent text(true, NS_TEXT_TEXT, this);
2837 text.theText = compositionStr;
2838 DispatchEvent(&text);
2840 nsCompositionEvent end(true, NS_COMPOSITION_END, this);
2841 end.data = compositionStr;
2842 DispatchEvent(&end);
2844 return nsEventStatus_eIgnore;
2847 nsIWidget *
2848 nsWindow::GetParent(void)
2850 return mParent;
2853 float
2854 nsWindow::GetDPI()
2856 QDesktopWidget* rootWindow = QApplication::desktop();
2857 double heightInches = rootWindow->heightMM()/25.4;
2858 if (heightInches < 0.25) {
2859 // Something's broken, but we'd better not crash.
2860 return 96.0f;
2863 return float(rootWindow->height()/heightInches);
2866 void
2867 nsWindow::DispatchActivateEvent(void)
2869 if (mWidgetListener)
2870 mWidgetListener->WindowActivated();
2873 void
2874 nsWindow::DispatchDeactivateEvent(void)
2876 if (mWidgetListener)
2877 mWidgetListener->WindowDeactivated();
2880 void
2881 nsWindow::DispatchActivateEventOnTopLevelWindow(void)
2883 nsWindow * topLevelWindow = static_cast<nsWindow*>(GetTopLevelWidget());
2884 if (topLevelWindow != nullptr)
2885 topLevelWindow->DispatchActivateEvent();
2888 void
2889 nsWindow::DispatchDeactivateEventOnTopLevelWindow(void)
2891 nsWindow * topLevelWindow = static_cast<nsWindow*>(GetTopLevelWidget());
2892 if (topLevelWindow != nullptr)
2893 topLevelWindow->DispatchDeactivateEvent();
2896 void
2897 nsWindow::DispatchResizeEvent(nsIntRect &aRect, nsEventStatus &aStatus)
2899 aStatus = nsEventStatus_eIgnore;
2900 if (mWidgetListener &&
2901 mWidgetListener->WindowResized(this, aRect.width, aRect.height))
2902 aStatus = nsEventStatus_eConsumeNoDefault;
2905 NS_IMETHODIMP
2906 nsWindow::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus &aStatus)
2908 #ifdef DEBUG
2909 debug_DumpEvent(stdout, aEvent->widget, aEvent,
2910 nsAutoCString("something"), 0);
2911 #endif
2913 aStatus = nsEventStatus_eIgnore;
2915 // send it to the standard callback
2916 if (mWidgetListener)
2917 aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
2919 return NS_OK;
2922 NS_IMETHODIMP
2923 nsWindow::Show(bool aState)
2925 LOG(("nsWindow::Show [%p] state %d\n", (void *)this, aState));
2926 if (aState == mIsShown)
2927 return NS_OK;
2929 // Clear our cached resources when the window is hidden.
2930 if (mIsShown && !aState) {
2931 ClearCachedResources();
2934 mIsShown = aState;
2936 #ifdef MOZ_ENABLE_QTMOBILITY
2937 if (mWidget &&
2938 (mWindowType == eWindowType_toplevel ||
2939 mWindowType == eWindowType_dialog ||
2940 mWindowType == eWindowType_popup))
2942 if (!gOrientation) {
2943 gOrientation = new QOrientationSensor();
2944 gOrientation->addFilter(&gOrientationFilter);
2945 gOrientation->start();
2946 if (!gOrientation->isActive()) {
2947 qWarning("Orientationsensor didn't start!");
2949 gOrientationFilter.filter(gOrientation->reading());
2951 QObject::connect((QObject*) &gOrientationFilter, SIGNAL(orientationChanged()),
2952 mWidget, SLOT(orientationChanged()));
2955 #endif
2957 if ((aState && !AreBoundsSane()) || !mWidget) {
2958 LOG(("\tbounds are insane or window hasn't been created yet\n"));
2959 mNeedsShow = true;
2960 return NS_OK;
2963 if (aState) {
2964 if (mNeedsMove) {
2965 NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height,
2966 false);
2967 } else if (mNeedsResize) {
2968 NativeResize(mBounds.width, mBounds.height, false);
2971 else
2972 // If someone is hiding this widget, clear any needing show flag.
2973 mNeedsShow = false;
2975 NativeShow(aState);
2977 return NS_OK;
2980 NS_IMETHODIMP
2981 nsWindow::Resize(double aWidth, double aHeight, bool aRepaint)
2983 mBounds.width = NSToIntRound(aWidth);
2984 mBounds.height = NSToIntRound(aHeight);
2986 if (!mWidget)
2987 return NS_OK;
2989 if (mIsShown) {
2990 if (AreBoundsSane()) {
2991 if (mIsTopLevel || mNeedsShow)
2992 NativeResize(mBounds.x, mBounds.y,
2993 mBounds.width, mBounds.height, aRepaint);
2994 else
2995 NativeResize(mBounds.width, mBounds.height, aRepaint);
2997 // Does it need to be shown because it was previously insane?
2998 if (mNeedsShow)
2999 NativeShow(true);
3001 else {
3002 // If someone has set this so that the needs show flag is false
3003 // and it needs to be hidden, update the flag and hide the
3004 // window. This flag will be cleared the next time someone
3005 // hides the window or shows it. It also prevents us from
3006 // calling NativeShow(false) excessively on the window which
3007 // causes unneeded X traffic.
3008 if (!mNeedsShow) {
3009 mNeedsShow = true;
3010 NativeShow(false);
3014 else if (AreBoundsSane() && mListenForResizes) {
3015 // For widgets that we listen for resizes for (widgets created
3016 // with native parents) we apparently _always_ have to resize. I
3017 // dunno why, but apparently we're lame like that.
3018 NativeResize(mBounds.width, mBounds.height, aRepaint);
3020 else {
3021 mNeedsResize = true;
3024 // synthesize a resize event if this isn't a toplevel
3025 if (mIsTopLevel || mListenForResizes) {
3026 nsEventStatus status;
3027 DispatchResizeEvent(mBounds, status);
3030 NotifyRollupGeometryChange();
3031 return NS_OK;
3034 NS_IMETHODIMP
3035 nsWindow::Resize(double aX, double aY, double aWidth, double aHeight,
3036 bool aRepaint)
3038 mBounds.x = NSToIntRound(aX);
3039 mBounds.y = NSToIntRound(aY);
3040 mBounds.width = NSToIntRound(aWidth);
3041 mBounds.height = NSToIntRound(aHeight);
3043 mPlaced = true;
3045 if (!mWidget)
3046 return NS_OK;
3048 // Has this widget been set to visible?
3049 if (mIsShown) {
3050 // Are the bounds sane?
3051 if (AreBoundsSane()) {
3052 // Yep? Resize the window
3053 NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height,
3054 aRepaint);
3055 // Does it need to be shown because it was previously insane?
3056 if (mNeedsShow)
3057 NativeShow(true);
3059 else {
3060 // If someone has set this so that the needs show flag is false
3061 // and it needs to be hidden, update the flag and hide the
3062 // window. This flag will be cleared the next time someone
3063 // hides the window or shows it. It also prevents us from
3064 // calling NativeShow(false) excessively on the window which
3065 // causes unneeded X traffic.
3066 if (!mNeedsShow) {
3067 mNeedsShow = true;
3068 NativeShow(false);
3072 // If the widget hasn't been shown, mark the widget as needing to be
3073 // resized before it is shown
3074 else if (AreBoundsSane() && mListenForResizes) {
3075 // For widgets that we listen for resizes for (widgets created
3076 // with native parents) we apparently _always_ have to resize. I
3077 // dunno why, but apparently we're lame like that.
3078 NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height,
3079 aRepaint);
3081 else {
3082 mNeedsResize = true;
3083 mNeedsMove = true;
3086 if (mIsTopLevel || mListenForResizes) {
3087 // synthesize a resize event
3088 nsEventStatus status;
3089 DispatchResizeEvent(mBounds, status);
3092 if (aRepaint)
3093 mWidget->update();
3095 NotifyRollupGeometryChange();
3096 return NS_OK;
3099 NS_IMETHODIMP
3100 nsWindow::Enable(bool aState)
3102 mEnabled = aState;
3104 return NS_OK;
3107 bool
3108 nsWindow::IsEnabled() const
3110 return mEnabled;
3113 void
3114 nsWindow::OnDestroy(void)
3116 if (mOnDestroyCalled)
3117 return;
3119 mOnDestroyCalled = true;
3121 // release references to children and device context
3122 nsBaseWidget::OnDestroy();
3124 // let go of our parent
3125 mParent = nullptr;
3127 nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
3128 NotifyWindowDestroyed();
3131 bool
3132 nsWindow::AreBoundsSane(void)
3134 if (mBounds.width > 0 && mBounds.height > 0)
3135 return true;
3137 return false;
3140 #if defined(MOZ_X11) && (MOZ_PLATFORM_MAEMO == 6)
3141 typedef enum {
3142 VKBUndefined,
3143 VKBOpen,
3144 VKBClose
3145 } PluginVKBState;
3147 static QCoreApplication::EventFilter previousEventFilter = NULL;
3149 static PluginVKBState
3150 GetPluginVKBState(Window aWinId)
3152 // Set default value as unexpected error
3153 PluginVKBState imeState = VKBUndefined;
3154 Display *display = mozilla::DefaultXDisplay();
3156 Atom actualType;
3157 int actualFormat;
3158 unsigned long nitems;
3159 unsigned long bytes;
3160 union {
3161 unsigned char* asUChar;
3162 unsigned long* asLong;
3163 } data = {0};
3164 int status = XGetWindowProperty(display, aWinId, sPluginIMEAtom,
3165 0, 1, False, AnyPropertyType,
3166 &actualType, &actualFormat, &nitems,
3167 &bytes, &data.asUChar);
3169 if (status == Success && actualType == XA_CARDINAL && actualFormat == 32 && nitems == 1) {
3170 // Assume that plugin set value false - close VKB, true - open VKB
3171 imeState = data.asLong[0] ? VKBOpen : VKBClose;
3174 if (status == Success) {
3175 XFree(data.asUChar);
3178 return imeState;
3181 static void
3182 SetVKBState(Window aWinId, PluginVKBState aState)
3184 Display *display = mozilla::DefaultXDisplay();
3185 if (aState != VKBUndefined) {
3186 unsigned long isOpen = aState == VKBOpen ? 1 : 0;
3187 XChangeProperty(display, aWinId, sPluginIMEAtom, XA_CARDINAL, 32,
3188 PropModeReplace, (unsigned char *) &isOpen, 1);
3189 } else {
3190 XDeleteProperty(display, aWinId, sPluginIMEAtom);
3192 XSync(display, False);
3195 static bool
3196 x11EventFilter(void* message, long* result)
3198 XEvent* event = static_cast<XEvent*>(message);
3199 if (event->type == PropertyNotify) {
3200 if (event->xproperty.atom == sPluginIMEAtom) {
3201 PluginVKBState state = GetPluginVKBState(event->xproperty.window);
3202 if (state == VKBOpen) {
3203 MozQWidget::requestVKB();
3204 } else if (state == VKBClose) {
3205 MozQWidget::hideVKB();
3207 return true;
3210 if (previousEventFilter) {
3211 return previousEventFilter(message, result);
3214 return false;
3216 #endif
3218 NS_IMETHODIMP_(void)
3219 nsWindow::SetInputContext(const InputContext& aContext,
3220 const InputContextAction& aAction)
3222 NS_ENSURE_TRUE_VOID(mWidget);
3224 // SetSoftwareKeyboardState uses mInputContext,
3225 // so, before calling that, record aContext in mInputContext.
3226 mInputContext = aContext;
3228 #if defined(MOZ_X11) && (MOZ_PLATFORM_MAEMO == 6)
3229 if (sPluginIMEAtom) {
3230 static QCoreApplication::EventFilter currentEventFilter = NULL;
3231 if (mInputContext.mIMEState.mEnabled == IMEState::PLUGIN &&
3232 currentEventFilter != x11EventFilter) {
3233 // Install event filter for listening Plugin IME state changes
3234 previousEventFilter = QCoreApplication::instance()->setEventFilter(x11EventFilter);
3235 currentEventFilter = x11EventFilter;
3236 } else if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN &&
3237 currentEventFilter == x11EventFilter) {
3238 // Remove event filter
3239 QCoreApplication::instance()->setEventFilter(previousEventFilter);
3240 currentEventFilter = previousEventFilter;
3241 previousEventFilter = NULL;
3242 QWidget* view = GetViewWidget();
3243 if (view) {
3244 SetVKBState(view->winId(), VKBUndefined);
3248 #endif
3250 switch (mInputContext.mIMEState.mEnabled) {
3251 case IMEState::ENABLED:
3252 case IMEState::PASSWORD:
3253 case IMEState::PLUGIN:
3254 SetSoftwareKeyboardState(true, aAction);
3255 break;
3256 default:
3257 SetSoftwareKeyboardState(false, aAction);
3258 break;
3262 NS_IMETHODIMP_(InputContext)
3263 nsWindow::GetInputContext()
3265 mInputContext.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
3266 // Our qt widget looks like using only one context per process.
3267 // However, it's better to set the context's pointer.
3268 #if (QT_VERSION <= QT_VERSION_CHECK(5, 0, 0))
3269 mInputContext.mNativeIMEContext = qApp->inputContext();
3270 #else
3271 mInputContext.mNativeIMEContext = nullptr;
3272 #endif
3273 return mInputContext;
3276 void
3277 nsWindow::SetSoftwareKeyboardState(bool aOpen,
3278 const InputContextAction& aAction)
3280 if (aOpen) {
3281 NS_ENSURE_TRUE_VOID(mInputContext.mIMEState.mEnabled !=
3282 IMEState::DISABLED);
3284 // Ensure that opening the virtual keyboard is allowed for this specific
3285 // InputContext depending on the content.ime.strict.policy pref
3286 if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN &&
3287 Preferences::GetBool("content.ime.strict_policy", false) &&
3288 !aAction.ContentGotFocusByTrustedCause() &&
3289 !aAction.UserMightRequestOpenVKB()) {
3290 return;
3292 #if defined(MOZ_X11) && (MOZ_PLATFORM_MAEMO == 6)
3293 // doen't open VKB if plugin did set closed state
3294 else if (sPluginIMEAtom) {
3295 QWidget* view = GetViewWidget();
3296 if (view && GetPluginVKBState(view->winId()) == VKBClose) {
3297 return;
3300 #endif
3303 if (aOpen) {
3304 // VKB open need to be delayed in order to give
3305 // to plugins chance prevent VKB from opening
3306 int32_t openDelay =
3307 Preferences::GetInt("ui.vkb.open.delay", 200);
3308 MozQWidget::requestVKB(openDelay, mWidget);
3309 } else {
3310 MozQWidget::hideVKB();
3312 return;
3315 void
3316 nsWindow::UserActivity()
3318 if (!mIdleService) {
3319 mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
3322 if (mIdleService) {
3323 mIdleService->ResetIdleTimeOut(0);
3327 uint32_t
3328 nsWindow::GetGLFrameBufferFormat()
3330 if (mLayerManager &&
3331 mLayerManager->GetBackendType() == mozilla::layers::LAYERS_OPENGL) {
3332 return MozQGLWidgetWrapper::isRGBAContext() ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
3334 return LOCAL_GL_NONE;