1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/qt/nsWindow.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2256 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim:expandtab:shiftwidth=4:tabstop=4: 1.6 + */ 1.7 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.10 + 1.11 +#include "mozilla/ArrayUtils.h" 1.12 +#include "mozilla/MiscEvents.h" 1.13 +#include "mozilla/MouseEvents.h" 1.14 +#include "mozilla/TextEvents.h" 1.15 +#include "mozilla/TouchEvents.h" 1.16 + 1.17 +#include <QGuiApplication> 1.18 +#include <QtGui/QCursor> 1.19 +#include <QIcon> 1.20 +#include <QMouseEvent> 1.21 +#include <QWheelEvent> 1.22 +#include <QResizeEvent> 1.23 +#include <QPaintEngine> 1.24 +#include <QMimeData> 1.25 +#include <QScreen> 1.26 + 1.27 +#include <QtCore/QDebug> 1.28 +#include <QtCore/QEvent> 1.29 +#include <QtCore/QVariant> 1.30 +#include <algorithm> 1.31 + 1.32 +#ifdef MOZ_X11 1.33 +#include <X11/Xlib.h> 1.34 +#include <X11/Xutil.h> 1.35 +#endif //MOZ_X11 1.36 + 1.37 +#include "nsXULAppAPI.h" 1.38 + 1.39 +#include "prlink.h" 1.40 + 1.41 +#include "nsWindow.h" 1.42 +#include "mozqwidget.h" 1.43 + 1.44 +#include "nsIdleService.h" 1.45 +#include "nsRenderingContext.h" 1.46 +#include "nsIRollupListener.h" 1.47 +#include "nsWidgetsCID.h" 1.48 +#include "nsQtKeyUtils.h" 1.49 +#include "mozilla/Services.h" 1.50 +#include "mozilla/Preferences.h" 1.51 +#include "mozilla/Likely.h" 1.52 +#include "mozilla/layers/LayersTypes.h" 1.53 +#include "nsIWidgetListener.h" 1.54 +#include "ClientLayerManager.h" 1.55 +#include "BasicLayers.h" 1.56 + 1.57 +#include "nsIStringBundle.h" 1.58 +#include "nsGfxCIID.h" 1.59 + 1.60 +#include "imgIContainer.h" 1.61 +#include "nsGfxCIID.h" 1.62 +#include "nsIInterfaceRequestorUtils.h" 1.63 +#include "nsAutoPtr.h" 1.64 + 1.65 +#include "gfxQtPlatform.h" 1.66 + 1.67 +#include "nsIDOMWheelEvent.h" 1.68 + 1.69 +#include "GLContext.h" 1.70 + 1.71 +#ifdef MOZ_X11 1.72 +#include "keysym2ucs.h" 1.73 +#endif 1.74 + 1.75 +#include "Layers.h" 1.76 +#include "GLContextProvider.h" 1.77 + 1.78 +using namespace mozilla; 1.79 +using namespace mozilla::gl; 1.80 +using namespace mozilla::widget; 1.81 +using namespace mozilla::gfx; 1.82 +using namespace mozilla::layers; 1.83 +using mozilla::gl::GLContext; 1.84 + 1.85 +#define kWindowPositionSlop 20 1.86 + 1.87 +// Qt 1.88 +static const int WHEEL_DELTA = 120; 1.89 +static bool gGlobalsInitialized = false; 1.90 +static bool sAltGrModifier = false; 1.91 + 1.92 +static void find_first_visible_parent(QWindow* aItem, QWindow*& aVisibleItem); 1.93 +static bool is_mouse_in_window (MozQWidget* aWindow, double aMouseX, double aMouseY); 1.94 +static bool isContextMenuKeyEvent(const QKeyEvent *qe); 1.95 +static void InitKeyEvent(WidgetKeyboardEvent &aEvent, QKeyEvent *aQEvent); 1.96 + 1.97 +nsWindow::nsWindow() 1.98 +{ 1.99 + LOG(("%s [%p]\n", __PRETTY_FUNCTION__, (void *)this)); 1.100 + 1.101 + mIsTopLevel = false; 1.102 + mIsDestroyed = false; 1.103 + mIsShown = false; 1.104 + mEnabled = true; 1.105 + mWidget = nullptr; 1.106 + mVisible = false; 1.107 + mActivatePending = false; 1.108 + mWindowType = eWindowType_child; 1.109 + mSizeState = nsSizeMode_Normal; 1.110 + mLastSizeMode = nsSizeMode_Normal; 1.111 + mQCursor = Qt::ArrowCursor; 1.112 + mNeedsResize = false; 1.113 + mNeedsMove = false; 1.114 + mListenForResizes = false; 1.115 + mNeedsShow = false; 1.116 + mTimerStarted = false; 1.117 + mMoveEvent.needDispatch = false; 1.118 + 1.119 + if (!gGlobalsInitialized) { 1.120 + gfxPlatform::GetPlatform(); 1.121 + gGlobalsInitialized = true; 1.122 + } 1.123 + 1.124 + memset(mKeyDownFlags, 0, sizeof(mKeyDownFlags)); 1.125 + 1.126 + mIsTransparent = false; 1.127 + 1.128 + mCursor = eCursor_standard; 1.129 +} 1.130 + 1.131 +nsWindow::~nsWindow() 1.132 +{ 1.133 + LOG(("%s [%p]\n", __PRETTY_FUNCTION__, (void *)this)); 1.134 + 1.135 + Destroy(); 1.136 +} 1.137 + 1.138 +nsresult 1.139 +nsWindow::Create(nsIWidget *aParent, 1.140 + nsNativeWidget aNativeParent, 1.141 + const nsIntRect &aRect, 1.142 + nsDeviceContext *aContext, 1.143 + nsWidgetInitData *aInitData) 1.144 +{ 1.145 + // only set the base parent if we're not going to be a dialog or a 1.146 + // toplevel 1.147 + nsIWidget *baseParent = aParent; 1.148 + 1.149 + // initialize all the common bits of this class 1.150 + BaseCreate(baseParent, aRect, aContext, aInitData); 1.151 + 1.152 + mVisible = true; 1.153 + 1.154 + // and do our common creation 1.155 + mParent = (nsWindow *)aParent; 1.156 + 1.157 + // save our bounds 1.158 + mBounds = aRect; 1.159 + 1.160 + // find native parent 1.161 + MozQWidget *parent = nullptr; 1.162 + 1.163 + if (aParent != nullptr) { 1.164 + parent = static_cast<MozQWidget*>(aParent->GetNativeData(NS_NATIVE_WIDGET)); 1.165 + } else if (aNativeParent != nullptr) { 1.166 + parent = static_cast<MozQWidget*>(aNativeParent); 1.167 + if (parent && mParent == nullptr) { 1.168 + mParent = parent->getReceiver(); 1.169 + } 1.170 + } 1.171 + 1.172 + LOG(("Create: nsWindow [%p] mWidget:[%p] parent:[%p], natPar:[%p] mParent:%p\n", (void *)this, (void*)mWidget, parent, aNativeParent, mParent)); 1.173 + 1.174 + // ok, create our QGraphicsWidget 1.175 + mWidget = createQWidget(parent, aInitData); 1.176 + 1.177 + if (!mWidget) { 1.178 + return NS_ERROR_OUT_OF_MEMORY; 1.179 + } 1.180 + 1.181 + 1.182 + // resize so that everything is set to the right dimensions 1.183 + Resize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, false); 1.184 + 1.185 + // check if we should listen for resizes 1.186 + mListenForResizes = (aNativeParent || 1.187 + (aInitData && aInitData->mListenForResizes)); 1.188 + 1.189 + return NS_OK; 1.190 +} 1.191 + 1.192 +MozQWidget* 1.193 +nsWindow::createQWidget(MozQWidget* parent, 1.194 + nsWidgetInitData* aInitData) 1.195 +{ 1.196 + const char *windowName = nullptr; 1.197 + Qt::WindowFlags flags = Qt::Widget; 1.198 + 1.199 + // ok, create our windows 1.200 + switch (mWindowType) { 1.201 + case eWindowType_dialog: 1.202 + windowName = "topLevelDialog"; 1.203 + flags = Qt::Dialog; 1.204 + break; 1.205 + case eWindowType_popup: 1.206 + windowName = "topLevelPopup"; 1.207 + flags = Qt::Popup; 1.208 + break; 1.209 + case eWindowType_toplevel: 1.210 + windowName = "topLevelWindow"; 1.211 + flags = Qt::Window; 1.212 + break; 1.213 + case eWindowType_invisible: 1.214 + windowName = "topLevelInvisible"; 1.215 + break; 1.216 + case eWindowType_child: 1.217 + case eWindowType_plugin: 1.218 + default: // sheet 1.219 + windowName = "paintArea"; 1.220 + break; 1.221 + } 1.222 + 1.223 + MozQWidget* widget = new MozQWidget(this, parent); 1.224 + if (!widget) { 1.225 + return nullptr; 1.226 + } 1.227 + 1.228 + widget->setObjectName(QString(windowName)); 1.229 + if (mWindowType == eWindowType_invisible) { 1.230 + widget->setVisibility(QWindow::Hidden); 1.231 + } 1.232 + if (mWindowType == eWindowType_dialog) { 1.233 + widget->setModality(Qt::WindowModal); 1.234 + } 1.235 + 1.236 + widget->create(); 1.237 + 1.238 + // create a QGraphicsView if this is a new toplevel window 1.239 + LOG(("nsWindow::%s [%p] Created Window: %s, widget:%p, par:%p\n", __FUNCTION__, (void *)this, windowName, widget, parent)); 1.240 + 1.241 + return widget; 1.242 +} 1.243 + 1.244 +NS_IMETHODIMP 1.245 +nsWindow::Destroy(void) 1.246 +{ 1.247 + if (mIsDestroyed || !mWidget) { 1.248 + return NS_OK; 1.249 + } 1.250 + 1.251 + LOG(("nsWindow::Destroy [%p]\n", (void *)this)); 1.252 + mIsDestroyed = true; 1.253 + 1.254 + /** Need to clean our LayerManager up while still alive */ 1.255 + if (mLayerManager) { 1.256 + mLayerManager->Destroy(); 1.257 + } 1.258 + mLayerManager = nullptr; 1.259 + 1.260 + // It is safe to call DestroyeCompositor several times (here and 1.261 + // in the parent class) since it will take effect only once. 1.262 + // The reason we call it here is because on gtk platforms we need 1.263 + // to destroy the compositor before we destroy the gdk window (which 1.264 + // destroys the the gl context attached to it). 1.265 + DestroyCompositor(); 1.266 + 1.267 + ClearCachedResources(); 1.268 + 1.269 + nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener(); 1.270 + if (rollupListener) { 1.271 + nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget(); 1.272 + if (static_cast<nsIWidget *>(this) == rollupWidget) { 1.273 + rollupListener->Rollup(0, nullptr, nullptr); 1.274 + } 1.275 + } 1.276 + 1.277 + Show(false); 1.278 + 1.279 + // walk the list of children and call destroy on them. Have to be 1.280 + // careful, though -- calling destroy on a kid may actually remove 1.281 + // it from our child list, losing its sibling links. 1.282 + for (nsIWidget* kid = mFirstChild; kid; ) { 1.283 + nsIWidget* next = kid->GetNextSibling(); 1.284 + kid->Destroy(); 1.285 + kid = next; 1.286 + } 1.287 + 1.288 + // Destroy thebes surface now. Badness can happen if we destroy 1.289 + // the surface after its X Window. 1.290 + if (mWidget) { 1.291 + mWidget->dropReceiver(); 1.292 + 1.293 + // Call deleteLater instead of delete; Qt still needs the object 1.294 + // to be valid even after sending it a Close event. We could 1.295 + // also set WA_DeleteOnClose, but this gives us more control. 1.296 + mWidget->deleteLater(); 1.297 + } 1.298 + mWidget = nullptr; 1.299 + 1.300 + OnDestroy(); 1.301 + 1.302 + return NS_OK; 1.303 +} 1.304 + 1.305 +NS_IMETHODIMP 1.306 +nsWindow::Show(bool aState) 1.307 +{ 1.308 + LOG(("nsWindow::Show [%p] state %d\n", (void *)this, aState)); 1.309 + if (aState == mIsShown) { 1.310 + return NS_OK; 1.311 + } 1.312 + 1.313 + // Clear our cached resources when the window is hidden. 1.314 + if (mIsShown && !aState) { 1.315 + ClearCachedResources(); 1.316 + } 1.317 + 1.318 + mIsShown = aState; 1.319 + 1.320 + if ((aState && !AreBoundsSane()) || !mWidget) { 1.321 + LOG(("\tbounds are insane or window hasn't been created yet\n")); 1.322 + mNeedsShow = true; 1.323 + return NS_OK; 1.324 + } 1.325 + 1.326 + if (aState) { 1.327 + if (mNeedsMove) { 1.328 + NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, 1.329 + false); 1.330 + } else if (mNeedsResize) { 1.331 + NativeResize(mBounds.width, mBounds.height, false); 1.332 + } 1.333 + } 1.334 + else { 1.335 + // If someone is hiding this widget, clear any needing show flag. 1.336 + mNeedsShow = false; 1.337 + } 1.338 + 1.339 + NativeShow(aState); 1.340 + 1.341 + return NS_OK; 1.342 +} 1.343 + 1.344 +bool 1.345 +nsWindow::IsVisible() const 1.346 +{ 1.347 + return mIsShown; 1.348 +} 1.349 + 1.350 +NS_IMETHODIMP 1.351 +nsWindow::ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY) 1.352 +{ 1.353 + if (!mWidget) { 1.354 + return NS_ERROR_FAILURE; 1.355 + } 1.356 + 1.357 + int32_t screenWidth = qApp->primaryScreen()->size().width(); 1.358 + int32_t screenHeight = qApp->primaryScreen()->size().height(); 1.359 + 1.360 + if (aAllowSlop) { 1.361 + if (*aX < (kWindowPositionSlop - mBounds.width)) 1.362 + *aX = kWindowPositionSlop - mBounds.width; 1.363 + if (*aX > (screenWidth - kWindowPositionSlop)) 1.364 + *aX = screenWidth - kWindowPositionSlop; 1.365 + if (*aY < (kWindowPositionSlop - mBounds.height)) 1.366 + *aY = kWindowPositionSlop - mBounds.height; 1.367 + if (*aY > (screenHeight - kWindowPositionSlop)) 1.368 + *aY = screenHeight - kWindowPositionSlop; 1.369 + } else { 1.370 + if (*aX < 0) 1.371 + *aX = 0; 1.372 + if (*aX > (screenWidth - mBounds.width)) 1.373 + *aX = screenWidth - mBounds.width; 1.374 + if (*aY < 0) 1.375 + *aY = 0; 1.376 + if (*aY > (screenHeight - mBounds.height)) 1.377 + *aY = screenHeight - mBounds.height; 1.378 + } 1.379 + 1.380 + return NS_OK; 1.381 +} 1.382 + 1.383 +NS_IMETHODIMP 1.384 +nsWindow::Move(double aX, double aY) 1.385 +{ 1.386 + LOG(("nsWindow::Move [%p] %f %f\n", (void *)this, 1.387 + aX, aY)); 1.388 + 1.389 + int32_t x = NSToIntRound(aX); 1.390 + int32_t y = NSToIntRound(aY); 1.391 + 1.392 + if (mIsTopLevel) { 1.393 + SetSizeMode(nsSizeMode_Normal); 1.394 + } 1.395 + 1.396 + if (x == mBounds.x && y == mBounds.y) { 1.397 + return NS_OK; 1.398 + } 1.399 + 1.400 + mNeedsMove = false; 1.401 + 1.402 + // update the bounds 1.403 + QPoint pos(x, y); 1.404 + if (mIsTopLevel) { 1.405 + mWidget->setPosition(x, y); 1.406 + } 1.407 + else if (mWidget) { 1.408 + // the position of the widget is set relative to the parent 1.409 + // so we map the coordinates accordingly 1.410 + pos = mWidget->mapToGlobal(pos); 1.411 + mWidget->setPosition(pos); 1.412 + } 1.413 + 1.414 + mBounds.x = pos.x(); 1.415 + mBounds.y = pos.y(); 1.416 + 1.417 + NotifyRollupGeometryChange(); 1.418 + return NS_OK; 1.419 +} 1.420 + 1.421 +NS_IMETHODIMP 1.422 +nsWindow::Resize(double aWidth, double aHeight, bool aRepaint) 1.423 +{ 1.424 + mBounds.width = NSToIntRound(aWidth); 1.425 + mBounds.height = NSToIntRound(aHeight); 1.426 + 1.427 + if (!mWidget) 1.428 + return NS_OK; 1.429 + 1.430 + if (mIsShown) { 1.431 + if (AreBoundsSane()) { 1.432 + if (mIsTopLevel || mNeedsShow) 1.433 + NativeResize(mBounds.x, mBounds.y, 1.434 + mBounds.width, mBounds.height, aRepaint); 1.435 + else 1.436 + NativeResize(mBounds.width, mBounds.height, aRepaint); 1.437 + 1.438 + // Does it need to be shown because it was previously insane? 1.439 + if (mNeedsShow) { 1.440 + NativeShow(true); 1.441 + } 1.442 + } 1.443 + else { 1.444 + // If someone has set this so that the needs show flag is false 1.445 + // and it needs to be hidden, update the flag and hide the 1.446 + // window. This flag will be cleared the next time someone 1.447 + // hides the window or shows it. It also prevents us from 1.448 + // calling NativeShow(false) excessively on the window which 1.449 + // causes unneeded X traffic. 1.450 + if (!mNeedsShow) { 1.451 + mNeedsShow = true; 1.452 + NativeShow(false); 1.453 + } 1.454 + } 1.455 + } 1.456 + else if (AreBoundsSane() && mListenForResizes) { 1.457 + // For widgets that we listen for resizes for (widgets created 1.458 + // with native parents) we apparently _always_ have to resize. I 1.459 + // dunno why, but apparently we're lame like that. 1.460 + NativeResize(mBounds.width, mBounds.height, aRepaint); 1.461 + } 1.462 + else { 1.463 + mNeedsResize = true; 1.464 + } 1.465 + 1.466 + // synthesize a resize event if this isn't a toplevel 1.467 + if (mIsTopLevel || mListenForResizes) { 1.468 + nsEventStatus status; 1.469 + DispatchResizeEvent(mBounds, status); 1.470 + } 1.471 + 1.472 + NotifyRollupGeometryChange(); 1.473 + return NS_OK; 1.474 +} 1.475 + 1.476 +NS_IMETHODIMP 1.477 +nsWindow::Resize(double aX, double aY, double aWidth, double aHeight, 1.478 + bool aRepaint) 1.479 +{ 1.480 + mBounds.x = NSToIntRound(aX); 1.481 + mBounds.y = NSToIntRound(aY); 1.482 + mBounds.width = NSToIntRound(aWidth); 1.483 + mBounds.height = NSToIntRound(aHeight); 1.484 + 1.485 + mPlaced = true; 1.486 + 1.487 + if (!mWidget) { 1.488 + return NS_OK; 1.489 + } 1.490 + 1.491 + // Has this widget been set to visible? 1.492 + if (mIsShown) { 1.493 + // Are the bounds sane? 1.494 + if (AreBoundsSane()) { 1.495 + // Yep? Resize the window 1.496 + NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, 1.497 + aRepaint); 1.498 + // Does it need to be shown because it was previously insane? 1.499 + if (mNeedsShow) 1.500 + NativeShow(true); 1.501 + } 1.502 + else { 1.503 + // If someone has set this so that the needs show flag is false 1.504 + // and it needs to be hidden, update the flag and hide the 1.505 + // window. This flag will be cleared the next time someone 1.506 + // hides the window or shows it. It also prevents us from 1.507 + // calling NativeShow(false) excessively on the window which 1.508 + // causes unneeded X traffic. 1.509 + if (!mNeedsShow) { 1.510 + mNeedsShow = true; 1.511 + NativeShow(false); 1.512 + } 1.513 + } 1.514 + } 1.515 + // If the widget hasn't been shown, mark the widget as needing to be 1.516 + // resized before it is shown 1.517 + else if (AreBoundsSane() && mListenForResizes) { 1.518 + // For widgets that we listen for resizes for (widgets created 1.519 + // with native parents) we apparently _always_ have to resize. I 1.520 + // dunno why, but apparently we're lame like that. 1.521 + NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, 1.522 + aRepaint); 1.523 + } 1.524 + else { 1.525 + mNeedsResize = true; 1.526 + mNeedsMove = true; 1.527 + } 1.528 + 1.529 + if (mIsTopLevel || mListenForResizes) { 1.530 + // synthesize a resize event 1.531 + nsEventStatus status; 1.532 + DispatchResizeEvent(mBounds, status); 1.533 + } 1.534 + 1.535 + if (aRepaint) { 1.536 + mWidget->renderLater(); 1.537 + } 1.538 + 1.539 + NotifyRollupGeometryChange(); 1.540 + return NS_OK; 1.541 +} 1.542 + 1.543 +NS_IMETHODIMP 1.544 +nsWindow::Enable(bool aState) 1.545 +{ 1.546 + mEnabled = aState; 1.547 + 1.548 + return NS_OK; 1.549 +} 1.550 + 1.551 +bool 1.552 +nsWindow::IsEnabled() const 1.553 +{ 1.554 + return mEnabled; 1.555 +} 1.556 + 1.557 +NS_IMETHODIMP 1.558 +nsWindow::SetFocus(bool aRaise) 1.559 +{ 1.560 + // Make sure that our owning widget has focus. If it doesn't try to 1.561 + // grab it. Note that we don't set our focus flag in this case. 1.562 + LOGFOCUS((" SetFocus [%p]\n", (void *)this)); 1.563 + 1.564 + if (!mWidget) { 1.565 + return NS_ERROR_FAILURE; 1.566 + } 1.567 + 1.568 + if (mWidget->focusObject()) { 1.569 + return NS_OK; 1.570 + } 1.571 + 1.572 + // Because QGraphicsItem cannot get the focus if they are 1.573 + // invisible, we look up the chain, for the lowest visible 1.574 + // parent and focus that one 1.575 + QWindow* realFocusItem = nullptr; 1.576 + find_first_visible_parent(mWidget, realFocusItem); 1.577 + 1.578 + if (!realFocusItem || realFocusItem->focusObject()) { 1.579 + return NS_OK; 1.580 + } 1.581 + 1.582 + if (aRaise && mWidget) { 1.583 + // the raising has to happen on the view widget 1.584 + mWidget->raise(); 1.585 + } 1.586 + 1.587 + // XXXndeakin why is this here? It should dispatch only when the OS 1.588 + // notifies us. 1.589 + DispatchActivateEvent(); 1.590 + 1.591 + return NS_OK; 1.592 +} 1.593 + 1.594 +NS_IMETHODIMP 1.595 +nsWindow::ConfigureChildren(const nsTArray<nsIWidget::Configuration>& aConfigurations) 1.596 +{ 1.597 + for (uint32_t i = 0; i < aConfigurations.Length(); ++i) { 1.598 + const Configuration& configuration = aConfigurations[i]; 1.599 + 1.600 + nsWindow* w = static_cast<nsWindow*>(configuration.mChild); 1.601 + NS_ASSERTION(w->GetParent() == this, 1.602 + "Configured widget is not a child"); 1.603 + 1.604 + if (w->mBounds.Size() != configuration.mBounds.Size()) { 1.605 + w->Resize(configuration.mBounds.x, configuration.mBounds.y, 1.606 + configuration.mBounds.width, configuration.mBounds.height, 1.607 + true); 1.608 + } else if (w->mBounds.TopLeft() != configuration.mBounds.TopLeft()) { 1.609 + w->Move(configuration.mBounds.x, configuration.mBounds.y); 1.610 + } 1.611 + } 1.612 + return NS_OK; 1.613 +} 1.614 + 1.615 +NS_IMETHODIMP 1.616 +nsWindow::Invalidate(const nsIntRect &aRect) 1.617 +{ 1.618 + LOGDRAW(("Invalidate (rect) [%p,%p]: %d %d %d %d\n", (void *)this, 1.619 + (void*)mWidget,aRect.x, aRect.y, aRect.width, aRect.height)); 1.620 + 1.621 + if (!mWidget) { 1.622 + return NS_OK; 1.623 + } 1.624 + 1.625 + mWidget->renderLater(); 1.626 + 1.627 + return NS_OK; 1.628 +} 1.629 + 1.630 +nsIntPoint 1.631 +nsWindow::WidgetToScreenOffset() 1.632 +{ 1.633 + NS_ENSURE_TRUE(mWidget, nsIntPoint(0,0)); 1.634 + 1.635 + QPoint origin(0, 0); 1.636 + origin = mWidget->mapToGlobal(origin); 1.637 + 1.638 + return nsIntPoint(origin.x(), origin.y()); 1.639 +} 1.640 + 1.641 +void* 1.642 +nsWindow::GetNativeData(uint32_t aDataType) 1.643 +{ 1.644 + switch (aDataType) { 1.645 + case NS_NATIVE_WINDOW: 1.646 + case NS_NATIVE_WIDGET: { 1.647 + return mWidget; 1.648 + } 1.649 + case NS_NATIVE_SHAREABLE_WINDOW: { 1.650 + return mWidget ? (void*)mWidget->winId() : nullptr; 1.651 + } 1.652 + case NS_NATIVE_DISPLAY: { 1.653 +#ifdef MOZ_X11 1.654 + return gfxQtPlatform::GetXDisplay(mWidget); 1.655 +#endif 1.656 + break; 1.657 + } 1.658 + case NS_NATIVE_PLUGIN_PORT: 1.659 + case NS_NATIVE_GRAPHIC: 1.660 + case NS_NATIVE_SHELLWIDGET: { 1.661 + break; 1.662 + } 1.663 + default: 1.664 + NS_WARNING("nsWindow::GetNativeData called with bad value"); 1.665 + return nullptr; 1.666 + } 1.667 + LOG(("nsWindow::%s [%p] aDataType:%i\n", __FUNCTION__, (void *)this, aDataType)); 1.668 + return nullptr; 1.669 +} 1.670 + 1.671 +NS_IMETHODIMP 1.672 +nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus) 1.673 +{ 1.674 +#ifdef DEBUG 1.675 + debug_DumpEvent(stdout, aEvent->widget, aEvent, 1.676 + nsAutoCString("something"), 0); 1.677 +#endif 1.678 + 1.679 + aStatus = nsEventStatus_eIgnore; 1.680 + 1.681 + // send it to the standard callback 1.682 + if (mWidgetListener) { 1.683 + aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents); 1.684 + } 1.685 + 1.686 + return NS_OK; 1.687 +} 1.688 + 1.689 +NS_IMETHODIMP_(void) 1.690 +nsWindow::SetInputContext(const InputContext& aContext, 1.691 + const InputContextAction& aAction) 1.692 +{ 1.693 + NS_ENSURE_TRUE_VOID(mWidget); 1.694 + 1.695 + // SetSoftwareKeyboardState uses mInputContext, 1.696 + // so, before calling that, record aContext in mInputContext. 1.697 + mInputContext = aContext; 1.698 + 1.699 + switch (mInputContext.mIMEState.mEnabled) { 1.700 + case IMEState::ENABLED: 1.701 + case IMEState::PASSWORD: 1.702 + case IMEState::PLUGIN: 1.703 + SetSoftwareKeyboardState(true, aAction); 1.704 + break; 1.705 + default: 1.706 + SetSoftwareKeyboardState(false, aAction); 1.707 + break; 1.708 + } 1.709 +} 1.710 + 1.711 +NS_IMETHODIMP_(InputContext) 1.712 +nsWindow::GetInputContext() 1.713 +{ 1.714 + mInputContext.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED; 1.715 + // Our qt widget looks like using only one context per process. 1.716 + // However, it's better to set the context's pointer. 1.717 + mInputContext.mNativeIMEContext = qApp->inputMethod(); 1.718 + 1.719 + return mInputContext; 1.720 +} 1.721 + 1.722 +NS_IMETHODIMP 1.723 +nsWindow::ReparentNativeWidget(nsIWidget *aNewParent) 1.724 +{ 1.725 + NS_PRECONDITION(aNewParent, ""); 1.726 + 1.727 + MozQWidget* newParent = static_cast<MozQWidget*>(aNewParent->GetNativeData(NS_NATIVE_WINDOW)); 1.728 + NS_ASSERTION(newParent, "Parent widget has a null native window handle"); 1.729 + if (mWidget) { 1.730 + mWidget->setParent(newParent); 1.731 + } 1.732 + return NS_OK; 1.733 +} 1.734 + 1.735 +NS_IMETHODIMP 1.736 +nsWindow::MakeFullScreen(bool aFullScreen) 1.737 +{ 1.738 + NS_ENSURE_TRUE(mWidget, NS_ERROR_FAILURE); 1.739 + 1.740 + if (aFullScreen) { 1.741 + if (mSizeMode != nsSizeMode_Fullscreen) { 1.742 + mLastSizeMode = mSizeMode; 1.743 + } 1.744 + 1.745 + mSizeMode = nsSizeMode_Fullscreen; 1.746 + mWidget->showFullScreen(); 1.747 + } 1.748 + else { 1.749 + mSizeMode = mLastSizeMode; 1.750 + 1.751 + switch (mSizeMode) { 1.752 + case nsSizeMode_Maximized: 1.753 + mWidget->showMaximized(); 1.754 + break; 1.755 + case nsSizeMode_Minimized: 1.756 + mWidget->showMinimized(); 1.757 + break; 1.758 + case nsSizeMode_Normal: 1.759 + mWidget->showNormal(); 1.760 + break; 1.761 + default: 1.762 + mWidget->showNormal(); 1.763 + break; 1.764 + } 1.765 + } 1.766 + 1.767 + NS_ASSERTION(mLastSizeMode != nsSizeMode_Fullscreen, 1.768 + "mLastSizeMode should never be fullscreen"); 1.769 + return nsBaseWidget::MakeFullScreen(aFullScreen); 1.770 +} 1.771 + 1.772 +LayerManager* 1.773 +nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager, 1.774 + LayersBackend aBackendHint, 1.775 + LayerManagerPersistence aPersistence, 1.776 + bool* aAllowRetaining) 1.777 +{ 1.778 + if (!mLayerManager && eTransparencyTransparent == GetTransparencyMode()) { 1.779 + mLayerManager = CreateBasicLayerManager(); 1.780 + } 1.781 + 1.782 + return nsBaseWidget::GetLayerManager(aShadowManager, aBackendHint, 1.783 + aPersistence, aAllowRetaining); 1.784 +} 1.785 + 1.786 +void 1.787 +nsWindow::UserActivity() 1.788 +{ 1.789 + if (!mIdleService) { 1.790 + mIdleService = do_GetService("@mozilla.org/widget/idleservice;1"); 1.791 + } 1.792 + 1.793 + if (mIdleService) { 1.794 + mIdleService->ResetIdleTimeOut(0); 1.795 + } 1.796 +} 1.797 + 1.798 +uint32_t 1.799 +nsWindow::GetGLFrameBufferFormat() 1.800 +{ 1.801 + if (mLayerManager && 1.802 + mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_OPENGL) { 1.803 + return LOCAL_GL_RGB; 1.804 + } 1.805 + return LOCAL_GL_NONE; 1.806 +} 1.807 + 1.808 +NS_IMETHODIMP 1.809 +nsWindow::SetCursor(nsCursor aCursor) 1.810 +{ 1.811 + if (mCursor == aCursor) { 1.812 + return NS_OK; 1.813 + } 1.814 + 1.815 + mCursor = aCursor; 1.816 + if (mWidget) { 1.817 + mWidget->SetCursor(mCursor); 1.818 + } 1.819 + return NS_OK; 1.820 +} 1.821 + 1.822 +NS_IMETHODIMP 1.823 +nsWindow::SetTitle(const nsAString& aTitle) 1.824 +{ 1.825 + QString qStr(QString::fromUtf16((const ushort*)aTitle.BeginReading(), aTitle.Length())); 1.826 + 1.827 + mWidget->setTitle(qStr); 1.828 + 1.829 + return NS_OK; 1.830 +} 1.831 + 1.832 +// EVENTS 1.833 + 1.834 +void 1.835 +nsWindow::OnPaint() 1.836 +{ 1.837 + LOGDRAW(("nsWindow::%s [%p]\n", __FUNCTION__, (void *)this)); 1.838 + nsIWidgetListener* listener = 1.839 + mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener; 1.840 + if (!listener) { 1.841 + return; 1.842 + } 1.843 + 1.844 + listener->WillPaintWindow(this); 1.845 + 1.846 + switch (GetLayerManager()->GetBackendType()) { 1.847 + case mozilla::layers::LayersBackend::LAYERS_CLIENT: { 1.848 + nsIntRegion region(nsIntRect(0, 0, mWidget->width(), mWidget->height())); 1.849 + listener->PaintWindow(this, region); 1.850 + break; 1.851 + } 1.852 + default: 1.853 + NS_ERROR("Invalid layer manager"); 1.854 + } 1.855 + 1.856 + listener->DidPaintWindow(); 1.857 +} 1.858 + 1.859 +nsEventStatus 1.860 +nsWindow::moveEvent(QMoveEvent* aEvent) 1.861 +{ 1.862 + LOG(("configure event [%p] %d %d\n", (void *)this, 1.863 + aEvent->pos().x(), aEvent->pos().y())); 1.864 + 1.865 + // can we shortcut? 1.866 + if (!mWidget || !mWidgetListener) 1.867 + return nsEventStatus_eIgnore; 1.868 + 1.869 + if ((mBounds.x == aEvent->pos().x() && 1.870 + mBounds.y == aEvent->pos().y())) 1.871 + { 1.872 + return nsEventStatus_eIgnore; 1.873 + } 1.874 + 1.875 + NotifyWindowMoved(aEvent->pos().x(), aEvent->pos().y()); 1.876 + return nsEventStatus_eConsumeNoDefault; 1.877 +} 1.878 + 1.879 +nsEventStatus 1.880 +nsWindow::resizeEvent(QResizeEvent* aEvent) 1.881 +{ 1.882 + nsIntRect rect; 1.883 + 1.884 + // Generate XPFE resize event 1.885 + GetBounds(rect); 1.886 + 1.887 + rect.width = aEvent->size().width(); 1.888 + rect.height = aEvent->size().height(); 1.889 + 1.890 + mBounds.width = rect.width; 1.891 + mBounds.height = rect.height; 1.892 + 1.893 + nsEventStatus status; 1.894 + DispatchResizeEvent(rect, status); 1.895 + return status; 1.896 +} 1.897 + 1.898 +nsEventStatus 1.899 +nsWindow::mouseMoveEvent(QMouseEvent* aEvent) 1.900 +{ 1.901 + UserActivity(); 1.902 + 1.903 + mMoveEvent.pos = aEvent->pos(); 1.904 + mMoveEvent.modifiers = aEvent->modifiers(); 1.905 + mMoveEvent.needDispatch = true; 1.906 + DispatchMotionToMainThread(); 1.907 + 1.908 + return nsEventStatus_eIgnore; 1.909 +} 1.910 + 1.911 +nsEventStatus 1.912 +nsWindow::mousePressEvent(QMouseEvent* aEvent) 1.913 +{ 1.914 + // The user has done something. 1.915 + UserActivity(); 1.916 + 1.917 + QPoint pos = aEvent->pos(); 1.918 + 1.919 + // we check against the widgets geometry, so use parent coordinates 1.920 + // for the check 1.921 + if (mWidget) 1.922 + pos = mWidget->mapToGlobal(pos); 1.923 + 1.924 + if (CheckForRollup( pos.x(), pos.y(), false)) 1.925 + return nsEventStatus_eIgnore; 1.926 + 1.927 + uint16_t domButton; 1.928 + switch (aEvent->button()) { 1.929 + case Qt::MidButton: 1.930 + domButton = WidgetMouseEvent::eMiddleButton; 1.931 + break; 1.932 + case Qt::RightButton: 1.933 + domButton = WidgetMouseEvent::eRightButton; 1.934 + break; 1.935 + default: 1.936 + domButton = WidgetMouseEvent::eLeftButton; 1.937 + break; 1.938 + } 1.939 + 1.940 + WidgetMouseEvent event(true, NS_MOUSE_BUTTON_DOWN, this, 1.941 + WidgetMouseEvent::eReal); 1.942 + event.button = domButton; 1.943 + InitButtonEvent(event, aEvent, 1); 1.944 + 1.945 + LOG(("%s [%p] button: %d\n", __PRETTY_FUNCTION__, (void*)this, domButton)); 1.946 + 1.947 + nsEventStatus status = DispatchEvent(&event); 1.948 + 1.949 + // right menu click on linux should also pop up a context menu 1.950 + if (domButton == WidgetMouseEvent::eRightButton && 1.951 + MOZ_LIKELY(!mIsDestroyed)) { 1.952 + WidgetMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this, 1.953 + WidgetMouseEvent::eReal); 1.954 + InitButtonEvent(contextMenuEvent, aEvent, 1); 1.955 + DispatchEvent(&contextMenuEvent, status); 1.956 + } 1.957 + 1.958 + return status; 1.959 +} 1.960 + 1.961 +nsEventStatus 1.962 +nsWindow::mouseReleaseEvent(QMouseEvent* aEvent) 1.963 +{ 1.964 + // The user has done something. 1.965 + UserActivity(); 1.966 + 1.967 + uint16_t domButton; 1.968 + 1.969 + switch (aEvent->button()) { 1.970 + case Qt::MidButton: 1.971 + domButton = WidgetMouseEvent::eMiddleButton; 1.972 + break; 1.973 + case Qt::RightButton: 1.974 + domButton = WidgetMouseEvent::eRightButton; 1.975 + break; 1.976 + default: 1.977 + domButton = WidgetMouseEvent::eLeftButton; 1.978 + break; 1.979 + } 1.980 + 1.981 + LOG(("%s [%p] button: %d\n", __PRETTY_FUNCTION__, (void*)this, domButton)); 1.982 + 1.983 + WidgetMouseEvent event(true, NS_MOUSE_BUTTON_UP, this, 1.984 + WidgetMouseEvent::eReal); 1.985 + event.button = domButton; 1.986 + InitButtonEvent(event, aEvent, 1); 1.987 + 1.988 + nsEventStatus status = DispatchEvent(&event); 1.989 + 1.990 + return status; 1.991 +} 1.992 + 1.993 +nsEventStatus 1.994 +nsWindow::mouseDoubleClickEvent(QMouseEvent* aEvent) 1.995 +{ 1.996 + uint32_t eventType; 1.997 + 1.998 + switch (aEvent->button()) { 1.999 + case Qt::MidButton: 1.1000 + eventType = WidgetMouseEvent::eMiddleButton; 1.1001 + break; 1.1002 + case Qt::RightButton: 1.1003 + eventType = WidgetMouseEvent::eRightButton; 1.1004 + break; 1.1005 + default: 1.1006 + eventType = WidgetMouseEvent::eLeftButton; 1.1007 + break; 1.1008 + } 1.1009 + 1.1010 + WidgetMouseEvent event(true, NS_MOUSE_DOUBLECLICK, this, 1.1011 + WidgetMouseEvent::eReal); 1.1012 + event.button = eventType; 1.1013 + 1.1014 + InitButtonEvent(event, aEvent, 2); 1.1015 + //pressed 1.1016 + return DispatchEvent(&event); 1.1017 +} 1.1018 + 1.1019 +nsEventStatus 1.1020 +nsWindow::focusInEvent(QFocusEvent* aEvent) 1.1021 +{ 1.1022 + LOGFOCUS(("OnFocusInEvent [%p]\n", (void *)this)); 1.1023 + 1.1024 + if (!mWidget) { 1.1025 + return nsEventStatus_eIgnore; 1.1026 + } 1.1027 + 1.1028 + DispatchActivateEventOnTopLevelWindow(); 1.1029 + 1.1030 + LOGFOCUS(("Events sent from focus in event [%p]\n", (void *)this)); 1.1031 + return nsEventStatus_eIgnore; 1.1032 +} 1.1033 + 1.1034 +nsEventStatus 1.1035 +nsWindow::focusOutEvent(QFocusEvent* aEvent) 1.1036 +{ 1.1037 + LOGFOCUS(("OnFocusOutEvent [%p]\n", (void *)this)); 1.1038 + 1.1039 + if (!mWidget) { 1.1040 + return nsEventStatus_eIgnore; 1.1041 + } 1.1042 + 1.1043 + DispatchDeactivateEventOnTopLevelWindow(); 1.1044 + 1.1045 + LOGFOCUS(("Done with container focus out [%p]\n", (void *)this)); 1.1046 + return nsEventStatus_eIgnore; 1.1047 +} 1.1048 + 1.1049 +nsEventStatus 1.1050 +nsWindow::keyPressEvent(QKeyEvent* aEvent) 1.1051 +{ 1.1052 + LOGFOCUS(("OnKeyPressEvent [%p]\n", (void *)this)); 1.1053 + 1.1054 + // The user has done something. 1.1055 + UserActivity(); 1.1056 + 1.1057 + if (aEvent->key() == Qt::Key_AltGr) { 1.1058 + sAltGrModifier = true; 1.1059 + } 1.1060 + 1.1061 +#ifdef MOZ_X11 1.1062 + // before we dispatch a key, check if it's the context menu key. 1.1063 + // If so, send a context menu key event instead. 1.1064 + if (isContextMenuKeyEvent(aEvent)) { 1.1065 + WidgetMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this, 1.1066 + WidgetMouseEvent::eReal, 1.1067 + WidgetMouseEvent::eContextMenuKey); 1.1068 + //keyEventToContextMenuEvent(&event, &contextMenuEvent); 1.1069 + return DispatchEvent(&contextMenuEvent); 1.1070 + } 1.1071 + 1.1072 + uint32_t domCharCode = 0; 1.1073 + uint32_t domKeyCode = QtKeyCodeToDOMKeyCode(aEvent->key()); 1.1074 + 1.1075 + // get keymap and modifier map from the Xserver 1.1076 + Display *display = gfxQtPlatform::GetXDisplay(mWidget); 1.1077 + int x_min_keycode = 0, x_max_keycode = 0, xkeysyms_per_keycode; 1.1078 + XDisplayKeycodes(display, &x_min_keycode, &x_max_keycode); 1.1079 + XModifierKeymap *xmodmap = XGetModifierMapping(display); 1.1080 + if (!xmodmap) 1.1081 + return nsEventStatus_eIgnore; 1.1082 + 1.1083 + KeySym *xkeymap = XGetKeyboardMapping(display, x_min_keycode, x_max_keycode - x_min_keycode, 1.1084 + &xkeysyms_per_keycode); 1.1085 + if (!xkeymap) { 1.1086 + XFreeModifiermap(xmodmap); 1.1087 + return nsEventStatus_eIgnore; 1.1088 + } 1.1089 + 1.1090 + // create modifier masks 1.1091 + qint32 shift_mask = 0, shift_lock_mask = 0, caps_lock_mask = 0, num_lock_mask = 0; 1.1092 + 1.1093 + for (int i = 0; i < 8 * xmodmap->max_keypermod; ++i) { 1.1094 + qint32 maskbit = 1 << (i / xmodmap->max_keypermod); 1.1095 + KeyCode modkeycode = xmodmap->modifiermap[i]; 1.1096 + if (modkeycode == NoSymbol) { 1.1097 + continue; 1.1098 + } 1.1099 + 1.1100 + quint32 mapindex = (modkeycode - x_min_keycode) * xkeysyms_per_keycode; 1.1101 + for (int j = 0; j < xkeysyms_per_keycode; ++j) { 1.1102 + KeySym modkeysym = xkeymap[mapindex + j]; 1.1103 + switch (modkeysym) { 1.1104 + case XK_Num_Lock: 1.1105 + num_lock_mask |= maskbit; 1.1106 + break; 1.1107 + case XK_Caps_Lock: 1.1108 + caps_lock_mask |= maskbit; 1.1109 + break; 1.1110 + case XK_Shift_Lock: 1.1111 + shift_lock_mask |= maskbit; 1.1112 + break; 1.1113 + case XK_Shift_L: 1.1114 + case XK_Shift_R: 1.1115 + shift_mask |= maskbit; 1.1116 + break; 1.1117 + } 1.1118 + } 1.1119 + } 1.1120 + // indicate whether is down or not 1.1121 + bool shift_state = ((shift_mask & aEvent->nativeModifiers()) != 0) ^ 1.1122 + (bool)(shift_lock_mask & aEvent->nativeModifiers()); 1.1123 + bool capslock_state = (bool)(caps_lock_mask & aEvent->nativeModifiers()); 1.1124 + 1.1125 + // try to find a keysym that we can translate to a DOMKeyCode 1.1126 + // this is needed because some of Qt's keycodes cannot be translated 1.1127 + // TODO: use US keyboard keymap instead of localised keymap 1.1128 + if (!domKeyCode && 1.1129 + aEvent->nativeScanCode() >= (quint32)x_min_keycode && 1.1130 + aEvent->nativeScanCode() <= (quint32)x_max_keycode) { 1.1131 + int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode; 1.1132 + for(int i = 0; (i < xkeysyms_per_keycode) && (domKeyCode == (quint32)NoSymbol); ++i) { 1.1133 + domKeyCode = QtKeyCodeToDOMKeyCode(xkeymap[index + i]); 1.1134 + } 1.1135 + } 1.1136 + 1.1137 + // store character in domCharCode 1.1138 + if (aEvent->text().length() && aEvent->text()[0].isPrint()) 1.1139 + domCharCode = (int32_t) aEvent->text()[0].unicode(); 1.1140 + 1.1141 + KeyNameIndex keyNameIndex = 1.1142 + domCharCode ? KEY_NAME_INDEX_PrintableKey : 1.1143 + QtKeyCodeToDOMKeyNameIndex(aEvent->key()); 1.1144 + 1.1145 + // If the key isn't autorepeat, we need to send the initial down event 1.1146 + if (!aEvent->isAutoRepeat() && !IsKeyDown(domKeyCode)) { 1.1147 + // send the key down event 1.1148 + 1.1149 + SetKeyDownFlag(domKeyCode); 1.1150 + 1.1151 + WidgetKeyboardEvent downEvent(true, NS_KEY_DOWN, this); 1.1152 + InitKeyEvent(downEvent, aEvent); 1.1153 + 1.1154 + downEvent.keyCode = domKeyCode; 1.1155 + downEvent.mKeyNameIndex = keyNameIndex; 1.1156 + 1.1157 + nsEventStatus status = DispatchEvent(&downEvent); 1.1158 + 1.1159 + // DispatchEvent can Destroy us (bug 378273) 1.1160 + if (MOZ_UNLIKELY(mIsDestroyed)) { 1.1161 + qWarning() << "Returning[" << __LINE__ << "]: " << "Window destroyed"; 1.1162 + return status; 1.1163 + } 1.1164 + 1.1165 + // If prevent default on keydown, don't dispatch keypress event 1.1166 + if (status == nsEventStatus_eConsumeNoDefault) { 1.1167 + return nsEventStatus_eConsumeNoDefault; 1.1168 + } 1.1169 + } 1.1170 + 1.1171 + // Don't pass modifiers as NS_KEY_PRESS events. 1.1172 + // Instead of selectively excluding some keys from NS_KEY_PRESS events, 1.1173 + // we instead selectively include (as per MSDN spec 1.1174 + // ( http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keypress%28VS.71%29.aspx ); 1.1175 + // no official spec covers KeyPress events). 1.1176 + if (aEvent->key() == Qt::Key_Shift || 1.1177 + aEvent->key() == Qt::Key_Control || 1.1178 + aEvent->key() == Qt::Key_Meta || 1.1179 + aEvent->key() == Qt::Key_Alt || 1.1180 + aEvent->key() == Qt::Key_AltGr) { 1.1181 + 1.1182 + return nsEventStatus_eIgnore; 1.1183 + } 1.1184 + 1.1185 + // Look for specialized app-command keys 1.1186 + switch (aEvent->key()) { 1.1187 + case Qt::Key_Back: 1.1188 + return DispatchCommandEvent(nsGkAtoms::Back); 1.1189 + case Qt::Key_Forward: 1.1190 + return DispatchCommandEvent(nsGkAtoms::Forward); 1.1191 + case Qt::Key_Refresh: 1.1192 + return DispatchCommandEvent(nsGkAtoms::Reload); 1.1193 + case Qt::Key_Stop: 1.1194 + return DispatchCommandEvent(nsGkAtoms::Stop); 1.1195 + case Qt::Key_Search: 1.1196 + return DispatchCommandEvent(nsGkAtoms::Search); 1.1197 + case Qt::Key_Favorites: 1.1198 + return DispatchCommandEvent(nsGkAtoms::Bookmarks); 1.1199 + case Qt::Key_HomePage: 1.1200 + return DispatchCommandEvent(nsGkAtoms::Home); 1.1201 + case Qt::Key_Copy: 1.1202 + case Qt::Key_F16: // F16, F20, F18, F14 are old keysyms for Copy Cut Paste Undo 1.1203 + return DispatchContentCommandEvent(NS_CONTENT_COMMAND_COPY); 1.1204 + case Qt::Key_Cut: 1.1205 + case Qt::Key_F20: 1.1206 + return DispatchContentCommandEvent(NS_CONTENT_COMMAND_CUT); 1.1207 + case Qt::Key_Paste: 1.1208 + case Qt::Key_F18: 1.1209 + case Qt::Key_F9: 1.1210 + return DispatchContentCommandEvent(NS_CONTENT_COMMAND_PASTE); 1.1211 + case Qt::Key_F14: 1.1212 + return DispatchContentCommandEvent(NS_CONTENT_COMMAND_UNDO); 1.1213 + } 1.1214 + 1.1215 + // Qt::Key_Redo and Qt::Key_Undo are not available yet. 1.1216 + if (aEvent->nativeVirtualKey() == 0xff66) { 1.1217 + return DispatchContentCommandEvent(NS_CONTENT_COMMAND_REDO); 1.1218 + } 1.1219 + if (aEvent->nativeVirtualKey() == 0xff65) { 1.1220 + return DispatchContentCommandEvent(NS_CONTENT_COMMAND_UNDO); 1.1221 + } 1.1222 + 1.1223 + WidgetKeyboardEvent event(true, NS_KEY_PRESS, this); 1.1224 + InitKeyEvent(event, aEvent); 1.1225 + 1.1226 + // If there is no charcode attainable from the text, try to 1.1227 + // generate it from the keycode. Check shift state for case 1.1228 + // Also replace the charcode if ControlModifier is the only 1.1229 + // pressed Modifier 1.1230 + if ((!domCharCode) && 1.1231 + (QGuiApplication::keyboardModifiers() & 1.1232 + (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) { 1.1233 + 1.1234 + // get a character from X11 key map 1.1235 + KeySym keysym = aEvent->nativeVirtualKey(); 1.1236 + if (keysym) { 1.1237 + domCharCode = (uint32_t) keysym2ucs(keysym); 1.1238 + if (domCharCode == -1 || !QChar((quint32)domCharCode).isPrint()) { 1.1239 + domCharCode = 0; 1.1240 + } 1.1241 + } 1.1242 + 1.1243 + // if Ctrl is pressed and domCharCode is not a ASCII character 1.1244 + if (domCharCode > 0xFF && (QGuiApplication::keyboardModifiers() & Qt::ControlModifier)) { 1.1245 + // replace Unicode character 1.1246 + int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode; 1.1247 + for (int i = 0; i < xkeysyms_per_keycode; ++i) { 1.1248 + if (xkeymap[index + i] <= 0xFF && !shift_state) { 1.1249 + domCharCode = (uint32_t) QChar::toLower((uint) xkeymap[index + i]); 1.1250 + break; 1.1251 + } 1.1252 + } 1.1253 + } 1.1254 + 1.1255 + } else { // The key event should cause a character input. 1.1256 + // At that time, we need to reset the modifiers 1.1257 + // because nsEditor will not accept a key event 1.1258 + // for text input if one or more modifiers are set. 1.1259 + event.modifiers &= ~(MODIFIER_CONTROL | 1.1260 + MODIFIER_ALT | 1.1261 + MODIFIER_META); 1.1262 + } 1.1263 + 1.1264 + KeySym keysym = NoSymbol; 1.1265 + int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode; 1.1266 + for (int i = 0; i < xkeysyms_per_keycode; ++i) { 1.1267 + if (xkeymap[index + i] == aEvent->nativeVirtualKey()) { 1.1268 + if ((i % 2) == 0) { // shifted char 1.1269 + keysym = xkeymap[index + i + 1]; 1.1270 + break; 1.1271 + } else { // unshifted char 1.1272 + keysym = xkeymap[index + i - 1]; 1.1273 + break; 1.1274 + } 1.1275 + } 1.1276 + if (xkeysyms_per_keycode - 1 == i) { 1.1277 + qWarning() << "Symbol '" << aEvent->nativeVirtualKey() << "' not found"; 1.1278 + } 1.1279 + } 1.1280 + QChar unshiftedChar(domCharCode); 1.1281 + long ucs = keysym2ucs(keysym); 1.1282 + ucs = ucs == -1 ? 0 : ucs; 1.1283 + QChar shiftedChar((uint)ucs); 1.1284 + 1.1285 + // append alternativeCharCodes if modifier is pressed 1.1286 + // append an additional alternativeCharCodes if domCharCode is not a Latin character 1.1287 + // and if one of these modifiers is pressed (i.e. Ctrl, Alt, Meta) 1.1288 + if (domCharCode && 1.1289 + (QGuiApplication::keyboardModifiers() & 1.1290 + (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) { 1.1291 + 1.1292 + event.charCode = domCharCode; 1.1293 + event.keyCode = 0; 1.1294 + AlternativeCharCode altCharCode(0, 0); 1.1295 + // if character has a lower and upper representation 1.1296 + if ((unshiftedChar.isUpper() || unshiftedChar.isLower()) && 1.1297 + unshiftedChar.toLower() == shiftedChar.toLower()) { 1.1298 + if (shift_state ^ capslock_state) { 1.1299 + altCharCode.mUnshiftedCharCode = (uint32_t) QChar::toUpper((uint)domCharCode); 1.1300 + altCharCode.mShiftedCharCode = (uint32_t) QChar::toLower((uint)domCharCode); 1.1301 + } else { 1.1302 + altCharCode.mUnshiftedCharCode = (uint32_t) QChar::toLower((uint)domCharCode); 1.1303 + altCharCode.mShiftedCharCode = (uint32_t) QChar::toUpper((uint)domCharCode); 1.1304 + } 1.1305 + } else { 1.1306 + altCharCode.mUnshiftedCharCode = (uint32_t) unshiftedChar.unicode(); 1.1307 + altCharCode.mShiftedCharCode = (uint32_t) shiftedChar.unicode(); 1.1308 + } 1.1309 + 1.1310 + // append alternative char code to event 1.1311 + if ((altCharCode.mUnshiftedCharCode && altCharCode.mUnshiftedCharCode != domCharCode) || 1.1312 + (altCharCode.mShiftedCharCode && altCharCode.mShiftedCharCode != domCharCode)) { 1.1313 + event.alternativeCharCodes.AppendElement(altCharCode); 1.1314 + } 1.1315 + 1.1316 + // check if the alternative char codes are latin-1 1.1317 + if (altCharCode.mUnshiftedCharCode > 0xFF || altCharCode.mShiftedCharCode > 0xFF) { 1.1318 + altCharCode.mUnshiftedCharCode = altCharCode.mShiftedCharCode = 0; 1.1319 + 1.1320 + // find latin char for keycode 1.1321 + KeySym keysym = NoSymbol; 1.1322 + int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode; 1.1323 + // find first shifted and unshifted Latin-Char in XKeyMap 1.1324 + for (int i = 0; i < xkeysyms_per_keycode; ++i) { 1.1325 + keysym = xkeymap[index + i]; 1.1326 + if (keysym && keysym <= 0xFF) { 1.1327 + if ((shift_state && (i % 2 == 1)) || 1.1328 + (!shift_state && (i % 2 == 0))) { 1.1329 + altCharCode.mUnshiftedCharCode = altCharCode.mUnshiftedCharCode ? 1.1330 + altCharCode.mUnshiftedCharCode : 1.1331 + keysym; 1.1332 + } else { 1.1333 + altCharCode.mShiftedCharCode = altCharCode.mShiftedCharCode ? 1.1334 + altCharCode.mShiftedCharCode : 1.1335 + keysym; 1.1336 + } 1.1337 + if (altCharCode.mUnshiftedCharCode && altCharCode.mShiftedCharCode) { 1.1338 + break; 1.1339 + } 1.1340 + } 1.1341 + } 1.1342 + 1.1343 + if (altCharCode.mUnshiftedCharCode || altCharCode.mShiftedCharCode) { 1.1344 + event.alternativeCharCodes.AppendElement(altCharCode); 1.1345 + } 1.1346 + } 1.1347 + } else { 1.1348 + event.charCode = domCharCode; 1.1349 + } 1.1350 + 1.1351 + if (xmodmap) { 1.1352 + XFreeModifiermap(xmodmap); 1.1353 + } 1.1354 + if (xkeymap) { 1.1355 + XFree(xkeymap); 1.1356 + } 1.1357 + 1.1358 + event.keyCode = domCharCode ? 0 : domKeyCode; 1.1359 + event.mKeyNameIndex = keyNameIndex; 1.1360 + // send the key press event 1.1361 + return DispatchEvent(&event); 1.1362 +#else 1.1363 + 1.1364 + //:TODO: fix shortcuts hebrew for non X11, 1.1365 + //see Bug 562195##51 1.1366 + 1.1367 + // before we dispatch a key, check if it's the context menu key. 1.1368 + // If so, send a context menu key event instead. 1.1369 + if (isContextMenuKeyEvent(aEvent)) { 1.1370 + WidgetMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this, 1.1371 + WidgetMouseEvent::eReal, 1.1372 + WidgetMouseEvent::eContextMenuKey); 1.1373 + //keyEventToContextMenuEvent(&event, &contextMenuEvent); 1.1374 + return DispatchEvent(&contextMenuEvent); 1.1375 + } 1.1376 + 1.1377 + uint32_t domCharCode = 0; 1.1378 + uint32_t domKeyCode = QtKeyCodeToDOMKeyCode(aEvent->key()); 1.1379 + 1.1380 + if (aEvent->text().length() && aEvent->text()[0].isPrint()) { 1.1381 + domCharCode = (int32_t) aEvent->text()[0].unicode(); 1.1382 + } 1.1383 + 1.1384 + KeyNameIndex keyNameIndex = 1.1385 + domCharCode ? KEY_NAME_INDEX_PrintableKey : 1.1386 + QtKeyCodeToDOMKeyNameIndex(aEvent->key()); 1.1387 + 1.1388 + // If the key isn't autorepeat, we need to send the initial down event 1.1389 + if (!aEvent->isAutoRepeat() && !IsKeyDown(domKeyCode)) { 1.1390 + // send the key down event 1.1391 + 1.1392 + SetKeyDownFlag(domKeyCode); 1.1393 + 1.1394 + WidgetKeyboardEvent downEvent(true, NS_KEY_DOWN, this); 1.1395 + InitKeyEvent(downEvent, aEvent); 1.1396 + 1.1397 + downEvent.keyCode = domKeyCode; 1.1398 + downEvent.mKeyNameIndex = keyNameIndex; 1.1399 + 1.1400 + nsEventStatus status = DispatchEvent(&downEvent); 1.1401 + 1.1402 + // If prevent default on keydown, don't dispatch keypress event 1.1403 + if (status == nsEventStatus_eConsumeNoDefault) { 1.1404 + return nsEventStatus_eConsumeNoDefault; 1.1405 + } 1.1406 + } 1.1407 + 1.1408 + WidgetKeyboardEvent event(true, NS_KEY_PRESS, this); 1.1409 + InitKeyEvent(event, aEvent); 1.1410 + 1.1411 + event.charCode = domCharCode; 1.1412 + 1.1413 + event.keyCode = domCharCode ? 0 : domKeyCode; 1.1414 + event.mKeyNameIndex = keyNameIndex; 1.1415 + 1.1416 + // send the key press event 1.1417 + return DispatchEvent(&event); 1.1418 +#endif 1.1419 +} 1.1420 + 1.1421 +nsEventStatus 1.1422 +nsWindow::keyReleaseEvent(QKeyEvent* aEvent) 1.1423 +{ 1.1424 + LOGFOCUS(("OnKeyReleaseEvent [%p]\n", (void *)this)); 1.1425 + 1.1426 + // The user has done something. 1.1427 + UserActivity(); 1.1428 + 1.1429 + if (isContextMenuKeyEvent(aEvent)) { 1.1430 + // er, what do we do here? DoDefault or NoDefault? 1.1431 + return nsEventStatus_eConsumeDoDefault; 1.1432 + } 1.1433 + 1.1434 + uint32_t domKeyCode = QtKeyCodeToDOMKeyCode(aEvent->key()); 1.1435 + 1.1436 +#ifdef MOZ_X11 1.1437 + if (!domKeyCode) { 1.1438 + // get keymap from the Xserver 1.1439 + Display *display = gfxQtPlatform::GetXDisplay(mWidget); 1.1440 + int x_min_keycode = 0, x_max_keycode = 0, xkeysyms_per_keycode; 1.1441 + XDisplayKeycodes(display, &x_min_keycode, &x_max_keycode); 1.1442 + KeySym *xkeymap = XGetKeyboardMapping(display, x_min_keycode, x_max_keycode - x_min_keycode, 1.1443 + &xkeysyms_per_keycode); 1.1444 + 1.1445 + if (aEvent->nativeScanCode() >= (quint32)x_min_keycode && 1.1446 + aEvent->nativeScanCode() <= (quint32)x_max_keycode) { 1.1447 + int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode; 1.1448 + for(int i = 0; (i < xkeysyms_per_keycode) && (domKeyCode == (quint32)NoSymbol); ++i) { 1.1449 + domKeyCode = QtKeyCodeToDOMKeyCode(xkeymap[index + i]); 1.1450 + } 1.1451 + } 1.1452 + 1.1453 + if (xkeymap) { 1.1454 + XFree(xkeymap); 1.1455 + } 1.1456 + } 1.1457 +#endif // MOZ_X11 1.1458 + 1.1459 + // send the key event as a key up event 1.1460 + WidgetKeyboardEvent event(true, NS_KEY_UP, this); 1.1461 + InitKeyEvent(event, aEvent); 1.1462 + 1.1463 + if (aEvent->key() == Qt::Key_AltGr) { 1.1464 + sAltGrModifier = false; 1.1465 + } 1.1466 + 1.1467 + event.keyCode = domKeyCode; 1.1468 + event.mKeyNameIndex = 1.1469 + (aEvent->text().length() && aEvent->text()[0].isPrint()) ? 1.1470 + KEY_NAME_INDEX_PrintableKey : 1.1471 + QtKeyCodeToDOMKeyNameIndex(aEvent->key()); 1.1472 + 1.1473 + // unset the key down flag 1.1474 + ClearKeyDownFlag(event.keyCode); 1.1475 + 1.1476 + return DispatchEvent(&event); 1.1477 +} 1.1478 + 1.1479 +nsEventStatus 1.1480 +nsWindow::wheelEvent(QWheelEvent* aEvent) 1.1481 +{ 1.1482 + // check to see if we should rollup 1.1483 + WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, this); 1.1484 + wheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE; 1.1485 + 1.1486 + // negative values for aEvent->delta indicate downward scrolling; 1.1487 + // this is opposite Gecko usage. 1.1488 + // TODO: Store the unused delta values due to fraction round and add it 1.1489 + // to next event. The stored values should be reset by other 1.1490 + // direction scroll event. 1.1491 + int32_t delta = (int)(aEvent->delta() / WHEEL_DELTA) * -3; 1.1492 + 1.1493 + switch (aEvent->orientation()) { 1.1494 + case Qt::Vertical: 1.1495 + wheelEvent.deltaY = wheelEvent.lineOrPageDeltaY = delta; 1.1496 + break; 1.1497 + case Qt::Horizontal: 1.1498 + wheelEvent.deltaX = wheelEvent.lineOrPageDeltaX = delta; 1.1499 + break; 1.1500 + default: 1.1501 + Q_ASSERT(0); 1.1502 + break; 1.1503 + } 1.1504 + 1.1505 + wheelEvent.refPoint.x = nscoord(aEvent->pos().x()); 1.1506 + wheelEvent.refPoint.y = nscoord(aEvent->pos().y()); 1.1507 + 1.1508 + wheelEvent.InitBasicModifiers(aEvent->modifiers() & Qt::ControlModifier, 1.1509 + aEvent->modifiers() & Qt::AltModifier, 1.1510 + aEvent->modifiers() & Qt::ShiftModifier, 1.1511 + aEvent->modifiers() & Qt::MetaModifier); 1.1512 + wheelEvent.time = 0; 1.1513 + 1.1514 + return DispatchEvent(&wheelEvent); 1.1515 +} 1.1516 + 1.1517 +nsEventStatus 1.1518 +nsWindow::showEvent(QShowEvent *) 1.1519 +{ 1.1520 + LOG(("%s [%p]\n", __PRETTY_FUNCTION__,(void *)this)); 1.1521 + mVisible = true; 1.1522 + return nsEventStatus_eConsumeDoDefault; 1.1523 +} 1.1524 + 1.1525 +nsEventStatus 1.1526 +nsWindow::hideEvent(QHideEvent *) 1.1527 +{ 1.1528 + LOG(("%s [%p]\n", __PRETTY_FUNCTION__,(void *)this)); 1.1529 + mVisible = false; 1.1530 + return nsEventStatus_eConsumeDoDefault; 1.1531 +} 1.1532 + 1.1533 +nsEventStatus nsWindow::touchEvent(QTouchEvent* aEvent) 1.1534 +{ 1.1535 + return nsEventStatus_eIgnore; 1.1536 +} 1.1537 + 1.1538 +nsEventStatus 1.1539 +nsWindow::tabletEvent(QTabletEvent* aEvent) 1.1540 +{ 1.1541 + LOGFOCUS(("nsWindow::%s [%p]\n", __FUNCTION__, (void *)this)); 1.1542 + return nsEventStatus_eIgnore; 1.1543 +} 1.1544 + 1.1545 +// Helpers 1.1546 + 1.1547 +void 1.1548 +nsWindow::InitButtonEvent(WidgetMouseEvent& aMoveEvent, 1.1549 + QMouseEvent* aEvent, 1.1550 + int aClickCount) 1.1551 +{ 1.1552 + aMoveEvent.refPoint.x = nscoord(aEvent->pos().x()); 1.1553 + aMoveEvent.refPoint.y = nscoord(aEvent->pos().y()); 1.1554 + 1.1555 + aMoveEvent.InitBasicModifiers(aEvent->modifiers() & Qt::ControlModifier, 1.1556 + aEvent->modifiers() & Qt::AltModifier, 1.1557 + aEvent->modifiers() & Qt::ShiftModifier, 1.1558 + aEvent->modifiers() & Qt::MetaModifier); 1.1559 + aMoveEvent.clickCount = aClickCount; 1.1560 +} 1.1561 + 1.1562 +nsEventStatus 1.1563 +nsWindow::DispatchEvent(WidgetGUIEvent* aEvent) 1.1564 +{ 1.1565 + nsEventStatus status; 1.1566 + DispatchEvent(aEvent, status); 1.1567 + return status; 1.1568 +} 1.1569 + 1.1570 +void 1.1571 +nsWindow::DispatchActivateEvent(void) 1.1572 +{ 1.1573 + if (mWidgetListener) { 1.1574 + mWidgetListener->WindowActivated(); 1.1575 + } 1.1576 +} 1.1577 + 1.1578 +void 1.1579 +nsWindow::DispatchDeactivateEvent(void) 1.1580 +{ 1.1581 + if (mWidgetListener) { 1.1582 + mWidgetListener->WindowDeactivated(); 1.1583 + } 1.1584 +} 1.1585 + 1.1586 +void 1.1587 +nsWindow::DispatchActivateEventOnTopLevelWindow(void) 1.1588 +{ 1.1589 + nsWindow* topLevelWindow = static_cast<nsWindow*>(GetTopLevelWidget()); 1.1590 + if (topLevelWindow != nullptr) { 1.1591 + topLevelWindow->DispatchActivateEvent(); 1.1592 + } 1.1593 +} 1.1594 + 1.1595 +void 1.1596 +nsWindow::DispatchDeactivateEventOnTopLevelWindow(void) 1.1597 +{ 1.1598 + nsWindow* topLevelWindow = static_cast<nsWindow*>(GetTopLevelWidget()); 1.1599 + if (topLevelWindow != nullptr) { 1.1600 + topLevelWindow->DispatchDeactivateEvent(); 1.1601 + } 1.1602 +} 1.1603 + 1.1604 +void 1.1605 +nsWindow::DispatchResizeEvent(nsIntRect &aRect, nsEventStatus &aStatus) 1.1606 +{ 1.1607 + aStatus = nsEventStatus_eIgnore; 1.1608 + if (mWidgetListener && 1.1609 + mWidgetListener->WindowResized(this, aRect.width, aRect.height)) { 1.1610 + aStatus = nsEventStatus_eConsumeNoDefault; 1.1611 + } 1.1612 +} 1.1613 + 1.1614 +///////////////////////////////////// OLD GECKO ECENTS need to Sort /////////////////// 1.1615 + 1.1616 +/* static */ bool 1.1617 +isContextMenuKeyEvent(const QKeyEvent *qe) 1.1618 +{ 1.1619 + uint32_t kc = QtKeyCodeToDOMKeyCode(qe->key()); 1.1620 + if (qe->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)) { 1.1621 + return false; 1.1622 + } 1.1623 + 1.1624 + bool isShift = qe->modifiers() & Qt::ShiftModifier; 1.1625 + return (kc == NS_VK_F10 && isShift) || 1.1626 + (kc == NS_VK_CONTEXT_MENU && !isShift); 1.1627 +} 1.1628 + 1.1629 +/* static */void 1.1630 +InitKeyEvent(WidgetKeyboardEvent &aEvent, QKeyEvent *aQEvent) 1.1631 +{ 1.1632 + aEvent.InitBasicModifiers(aQEvent->modifiers() & Qt::ControlModifier, 1.1633 + aQEvent->modifiers() & Qt::AltModifier, 1.1634 + aQEvent->modifiers() & Qt::ShiftModifier, 1.1635 + aQEvent->modifiers() & Qt::MetaModifier); 1.1636 + aEvent.mIsRepeat = 1.1637 + (aEvent.message == NS_KEY_DOWN || aEvent.message == NS_KEY_PRESS) && 1.1638 + aQEvent->isAutoRepeat(); 1.1639 + aEvent.time = 0; 1.1640 + 1.1641 + if (sAltGrModifier) { 1.1642 + aEvent.modifiers |= (MODIFIER_CONTROL | MODIFIER_ALT); 1.1643 + } 1.1644 + 1.1645 + // The transformations above and in qt for the keyval are not invertible 1.1646 + // so link to the QKeyEvent (which will vanish soon after return from the 1.1647 + // event callback) to give plugins access to hardware_keycode and state. 1.1648 + // (An XEvent would be nice but the QKeyEvent is good enough.) 1.1649 + aEvent.pluginEvent = (void *)aQEvent; 1.1650 +} 1.1651 + 1.1652 +NS_IMPL_ISUPPORTS_INHERITED(nsWindow, nsBaseWidget, nsISupportsWeakReference) 1.1653 + 1.1654 + 1.1655 + 1.1656 +void 1.1657 +nsWindow::ClearCachedResources() 1.1658 +{ 1.1659 + if (mLayerManager && 1.1660 + mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_BASIC) { 1.1661 + mLayerManager->ClearCachedResources(); 1.1662 + } 1.1663 + for (nsIWidget* kid = mFirstChild; kid; ) { 1.1664 + nsIWidget* next = kid->GetNextSibling(); 1.1665 + static_cast<nsWindow*>(kid)->ClearCachedResources(); 1.1666 + kid = next; 1.1667 + } 1.1668 +} 1.1669 + 1.1670 +NS_IMETHODIMP 1.1671 +nsWindow::SetParent(nsIWidget *aNewParent) 1.1672 +{ 1.1673 + NS_ENSURE_ARG_POINTER(aNewParent); 1.1674 + 1.1675 + nsCOMPtr<nsIWidget> kungFuDeathGrip(this); 1.1676 + nsIWidget* parent = GetParent(); 1.1677 + if (parent) { 1.1678 + parent->RemoveChild(this); 1.1679 + } 1.1680 + ReparentNativeWidget(aNewParent); 1.1681 + aNewParent->AddChild(this); 1.1682 + return NS_OK; 1.1683 +} 1.1684 + 1.1685 +NS_IMETHODIMP 1.1686 +nsWindow::SetModal(bool aModal) 1.1687 +{ 1.1688 + LOG(("nsWindow::SetModal [%p] %d, widget[%p]\n", (void *)this, aModal, mWidget)); 1.1689 + if (mWidget) { 1.1690 + mWidget->setModality(aModal ? Qt::WindowModal : Qt::NonModal); 1.1691 + } 1.1692 + 1.1693 + return NS_OK; 1.1694 +} 1.1695 + 1.1696 + 1.1697 +NS_IMETHODIMP 1.1698 +nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement, 1.1699 + nsIWidget *aWidget, 1.1700 + bool aActivate) 1.1701 +{ 1.1702 + return NS_ERROR_NOT_IMPLEMENTED; 1.1703 +} 1.1704 + 1.1705 +NS_IMETHODIMP 1.1706 +nsWindow::SetSizeMode(int32_t aMode) 1.1707 +{ 1.1708 + nsresult rv; 1.1709 + 1.1710 + LOG(("nsWindow::SetSizeMode [%p] %d\n", (void *)this, aMode)); 1.1711 + if (aMode != nsSizeMode_Minimized) { 1.1712 + mWidget->requestActivate(); 1.1713 + } 1.1714 + 1.1715 + // Save the requested state. 1.1716 + rv = nsBaseWidget::SetSizeMode(aMode); 1.1717 + 1.1718 + // return if there's no shell or our current state is the same as 1.1719 + // the mode we were just set to. 1.1720 + if (!mWidget || mSizeState == mSizeMode) { 1.1721 + return rv; 1.1722 + } 1.1723 + 1.1724 + switch (aMode) { 1.1725 + case nsSizeMode_Maximized: 1.1726 + mWidget->showMaximized(); 1.1727 + break; 1.1728 + case nsSizeMode_Minimized: 1.1729 + mWidget->showMinimized(); 1.1730 + break; 1.1731 + case nsSizeMode_Fullscreen: 1.1732 + mWidget->showFullScreen(); 1.1733 + break; 1.1734 + 1.1735 + default: 1.1736 + // nsSizeMode_Normal, really. 1.1737 + mWidget->show(); 1.1738 + break; 1.1739 + } 1.1740 + 1.1741 + mSizeState = mSizeMode; 1.1742 + 1.1743 + return rv; 1.1744 +} 1.1745 + 1.1746 +// Helper function to recursively find the first parent item that 1.1747 +// is still visible (QGraphicsItem can be hidden even if they are 1.1748 +// set to visible if one of their ancestors is invisible) 1.1749 +/* static */ 1.1750 +void find_first_visible_parent(QWindow* aItem, QWindow*& aVisibleItem) 1.1751 +{ 1.1752 + NS_ENSURE_TRUE_VOID(aItem); 1.1753 + 1.1754 + aVisibleItem = nullptr; 1.1755 + QWindow* parItem = nullptr; 1.1756 + while (!aVisibleItem) { 1.1757 + if (aItem->isVisible()) { 1.1758 + aVisibleItem = aItem; 1.1759 + } 1.1760 + else { 1.1761 + parItem = aItem->parent(); 1.1762 + if (parItem) { 1.1763 + aItem = parItem; 1.1764 + } 1.1765 + else { 1.1766 + aItem->setVisible(true); 1.1767 + aVisibleItem = aItem; 1.1768 + } 1.1769 + } 1.1770 + } 1.1771 +} 1.1772 + 1.1773 +NS_IMETHODIMP 1.1774 +nsWindow::GetScreenBounds(nsIntRect &aRect) 1.1775 +{ 1.1776 + aRect = nsIntRect(nsIntPoint(0, 0), mBounds.Size()); 1.1777 + if (mIsTopLevel) { 1.1778 + QPoint pos = mWidget->position(); 1.1779 + aRect.MoveTo(pos.x(), pos.y()); 1.1780 + } 1.1781 + else { 1.1782 + aRect.MoveTo(WidgetToScreenOffset()); 1.1783 + } 1.1784 + LOG(("GetScreenBounds %d %d | %d %d | %d %d\n", 1.1785 + aRect.x, aRect.y, 1.1786 + mBounds.width, mBounds.height, 1.1787 + aRect.width, aRect.height)); 1.1788 + return NS_OK; 1.1789 +} 1.1790 + 1.1791 +NS_IMETHODIMP 1.1792 +nsWindow::SetIcon(const nsAString& aIconSpec) 1.1793 +{ 1.1794 + if (!mWidget) 1.1795 + return NS_OK; 1.1796 + 1.1797 + nsCOMPtr<nsIFile> iconFile; 1.1798 + nsAutoCString path; 1.1799 + nsTArray<nsCString> iconList; 1.1800 + 1.1801 + // Look for icons with the following suffixes appended to the base name. 1.1802 + // The last two entries (for the old XPM format) will be ignored unless 1.1803 + // no icons are found using the other suffixes. XPM icons are depricated. 1.1804 + 1.1805 + const char extensions[6][7] = { ".png", "16.png", "32.png", "48.png", 1.1806 + ".xpm", "16.xpm" }; 1.1807 + 1.1808 + for (uint32_t i = 0; i < ArrayLength(extensions); i++) { 1.1809 + // Don't bother looking for XPM versions if we found a PNG. 1.1810 + if (i == ArrayLength(extensions) - 2 && iconList.Length()) 1.1811 + break; 1.1812 + 1.1813 + nsAutoString extension; 1.1814 + extension.AppendASCII(extensions[i]); 1.1815 + 1.1816 + ResolveIconName(aIconSpec, extension, getter_AddRefs(iconFile)); 1.1817 + if (iconFile) { 1.1818 + iconFile->GetNativePath(path); 1.1819 + iconList.AppendElement(path); 1.1820 + } 1.1821 + } 1.1822 + 1.1823 + // leave the default icon intact if no matching icons were found 1.1824 + if (iconList.Length() == 0) 1.1825 + return NS_OK; 1.1826 + 1.1827 + return SetWindowIconList(iconList); 1.1828 +} 1.1829 + 1.1830 +NS_IMETHODIMP 1.1831 +nsWindow::CaptureMouse(bool aCapture) 1.1832 +{ 1.1833 + LOG(("CaptureMouse %p\n", (void *)this)); 1.1834 + 1.1835 + if (!mWidget) 1.1836 + return NS_OK; 1.1837 + 1.1838 + mWidget->setMouseGrabEnabled(aCapture); 1.1839 + 1.1840 + return NS_OK; 1.1841 +} 1.1842 + 1.1843 +bool 1.1844 +nsWindow::CheckForRollup(double aMouseX, double aMouseY, 1.1845 + bool aIsWheel) 1.1846 +{ 1.1847 + nsIRollupListener* rollupListener = GetActiveRollupListener(); 1.1848 + nsCOMPtr<nsIWidget> rollupWidget; 1.1849 + if (rollupListener) { 1.1850 + rollupWidget = rollupListener->GetRollupWidget(); 1.1851 + } 1.1852 + if (!rollupWidget) { 1.1853 + nsBaseWidget::gRollupListener = nullptr; 1.1854 + return false; 1.1855 + } 1.1856 + 1.1857 + bool retVal = false; 1.1858 + MozQWidget *currentPopup = 1.1859 + (MozQWidget *)rollupWidget->GetNativeData(NS_NATIVE_WINDOW); 1.1860 + if (!is_mouse_in_window(currentPopup, aMouseX, aMouseY)) { 1.1861 + bool rollup = true; 1.1862 + if (aIsWheel) { 1.1863 + rollup = rollupListener->ShouldRollupOnMouseWheelEvent(); 1.1864 + retVal = true; 1.1865 + } 1.1866 + // if we're dealing with menus, we probably have submenus and 1.1867 + // we don't want to rollup if the clickis in a parent menu of 1.1868 + // the current submenu 1.1869 + uint32_t popupsToRollup = UINT32_MAX; 1.1870 + if (rollupListener) { 1.1871 + nsAutoTArray<nsIWidget*, 5> widgetChain; 1.1872 + uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain); 1.1873 + for (uint32_t i=0; i<widgetChain.Length(); ++i) { 1.1874 + nsIWidget* widget = widgetChain[i]; 1.1875 + MozQWidget* currWindow = 1.1876 + (MozQWidget*) widget->GetNativeData(NS_NATIVE_WINDOW); 1.1877 + if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) { 1.1878 + if (i < sameTypeCount) { 1.1879 + rollup = false; 1.1880 + } 1.1881 + else { 1.1882 + popupsToRollup = sameTypeCount; 1.1883 + } 1.1884 + break; 1.1885 + } 1.1886 + } // foreach parent menu widget 1.1887 + } // if rollup listener knows about menus 1.1888 + 1.1889 + // if we've determined that we should still rollup, do it. 1.1890 + if (rollup) { 1.1891 + nsIntPoint pos(aMouseX, aMouseY); 1.1892 + retVal = rollupListener->Rollup(popupsToRollup, &pos, nullptr); 1.1893 + } 1.1894 + } 1.1895 + 1.1896 + return retVal; 1.1897 +} 1.1898 + 1.1899 +/* static */ 1.1900 +bool 1.1901 +is_mouse_in_window (MozQWidget* aWindow, double aMouseX, double aMouseY) 1.1902 +{ 1.1903 + return aWindow->geometry().contains(aMouseX, aMouseY); 1.1904 +} 1.1905 + 1.1906 +NS_IMETHODIMP 1.1907 +nsWindow::GetAttention(int32_t aCycleCount) 1.1908 +{ 1.1909 + LOG(("nsWindow::GetAttention [%p]\n", (void *)this)); 1.1910 + return NS_ERROR_NOT_IMPLEMENTED; 1.1911 +} 1.1912 + 1.1913 + 1.1914 + 1.1915 +nsEventStatus 1.1916 +nsWindow::OnCloseEvent(QCloseEvent *aEvent) 1.1917 +{ 1.1918 + if (!mWidgetListener) 1.1919 + return nsEventStatus_eIgnore; 1.1920 + mWidgetListener->RequestWindowClose(this); 1.1921 + return nsEventStatus_eConsumeNoDefault; 1.1922 +} 1.1923 + 1.1924 + 1.1925 +inline bool 1.1926 +is_latin_shortcut_key(quint32 aKeyval) 1.1927 +{ 1.1928 + return ((Qt::Key_0 <= aKeyval && aKeyval <= Qt::Key_9) || 1.1929 + (Qt::Key_A <= aKeyval && aKeyval <= Qt::Key_Z)); 1.1930 +} 1.1931 + 1.1932 +nsEventStatus 1.1933 +nsWindow::DispatchCommandEvent(nsIAtom* aCommand) 1.1934 +{ 1.1935 + WidgetCommandEvent event(true, nsGkAtoms::onAppCommand, aCommand, this); 1.1936 + 1.1937 + nsEventStatus status; 1.1938 + DispatchEvent(&event, status); 1.1939 + 1.1940 + return status; 1.1941 +} 1.1942 + 1.1943 +nsEventStatus 1.1944 +nsWindow::DispatchContentCommandEvent(int32_t aMsg) 1.1945 +{ 1.1946 + WidgetContentCommandEvent event(true, aMsg, this); 1.1947 + 1.1948 + nsEventStatus status; 1.1949 + DispatchEvent(&event, status); 1.1950 + 1.1951 + return status; 1.1952 +} 1.1953 + 1.1954 + 1.1955 +static void 1.1956 +GetBrandName(nsXPIDLString& brandName) 1.1957 +{ 1.1958 + nsCOMPtr<nsIStringBundleService> bundleService = 1.1959 + mozilla::services::GetStringBundleService(); 1.1960 + 1.1961 + nsCOMPtr<nsIStringBundle> bundle; 1.1962 + if (bundleService) { 1.1963 + bundleService->CreateBundle( 1.1964 + "chrome://branding/locale/brand.properties", 1.1965 + getter_AddRefs(bundle)); 1.1966 + } 1.1967 + 1.1968 + if (bundle) { 1.1969 + bundle->GetStringFromName( 1.1970 + MOZ_UTF16("brandShortName"), 1.1971 + getter_Copies(brandName)); 1.1972 + } 1.1973 + 1.1974 + if (brandName.IsEmpty()) { 1.1975 + brandName.Assign(NS_LITERAL_STRING("Mozilla")); 1.1976 + } 1.1977 +} 1.1978 + 1.1979 +NS_IMETHODIMP 1.1980 +nsWindow::SetWindowClass(const nsAString &xulWinType) 1.1981 +{ 1.1982 + if (!mWidget) { 1.1983 + return NS_ERROR_FAILURE; 1.1984 + } 1.1985 + 1.1986 + nsXPIDLString brandName; 1.1987 + GetBrandName(brandName); 1.1988 + 1.1989 +#ifdef MOZ_X11 1.1990 + XClassHint *class_hint = XAllocClassHint(); 1.1991 + if (!class_hint) { 1.1992 + return NS_ERROR_OUT_OF_MEMORY; 1.1993 + } 1.1994 + const char *role = nullptr; 1.1995 + class_hint->res_name = ToNewCString(xulWinType); 1.1996 + if (!class_hint->res_name) { 1.1997 + XFree(class_hint); 1.1998 + return NS_ERROR_OUT_OF_MEMORY; 1.1999 + } 1.2000 + class_hint->res_class = ToNewCString(brandName); 1.2001 + if (!class_hint->res_class) { 1.2002 + nsMemory::Free(class_hint->res_name); 1.2003 + XFree(class_hint); 1.2004 + return NS_ERROR_OUT_OF_MEMORY; 1.2005 + } 1.2006 + 1.2007 + // Parse res_name into a name and role. Characters other than 1.2008 + // [A-Za-z0-9_-] are converted to '_'. Anything after the first 1.2009 + // colon is assigned to role; if there's no colon, assign the 1.2010 + // whole thing to both role and res_name. 1.2011 + for (char *c = class_hint->res_name; *c; c++) { 1.2012 + if (':' == *c) { 1.2013 + *c = 0; 1.2014 + role = c + 1; 1.2015 + } 1.2016 + else if (!isascii(*c) || (!isalnum(*c) && ('_' != *c) && ('-' != *c))) 1.2017 + *c = '_'; 1.2018 + } 1.2019 + class_hint->res_name[0] = toupper(class_hint->res_name[0]); 1.2020 + if (!role) role = class_hint->res_name; 1.2021 + 1.2022 + QWindow *widget = mWidget; 1.2023 + // If widget not show, handle might be null 1.2024 + if (widget && widget->winId()) { 1.2025 + XSetClassHint(gfxQtPlatform::GetXDisplay(widget), 1.2026 + widget->winId(), 1.2027 + class_hint); 1.2028 + } 1.2029 + 1.2030 + nsMemory::Free(class_hint->res_class); 1.2031 + nsMemory::Free(class_hint->res_name); 1.2032 + XFree(class_hint); 1.2033 +#endif 1.2034 + 1.2035 + return NS_OK; 1.2036 +} 1.2037 + 1.2038 +void 1.2039 +nsWindow::NativeResize(int32_t aWidth, int32_t aHeight, bool aRepaint) 1.2040 +{ 1.2041 + LOG(("nsWindow::NativeResize [%p] %d %d\n", (void *)this, 1.2042 + aWidth, aHeight)); 1.2043 + 1.2044 + mNeedsResize = false; 1.2045 + 1.2046 + mWidget->resize(aWidth, aHeight); 1.2047 + 1.2048 + if (aRepaint) { 1.2049 + mWidget->renderLater(); 1.2050 + } 1.2051 +} 1.2052 + 1.2053 +void 1.2054 +nsWindow::NativeResize(int32_t aX, int32_t aY, 1.2055 + int32_t aWidth, int32_t aHeight, 1.2056 + bool aRepaint) 1.2057 +{ 1.2058 + LOG(("nsWindow::NativeResize [%p] %d %d %d %d\n", (void *)this, 1.2059 + aX, aY, aWidth, aHeight)); 1.2060 + 1.2061 + mNeedsResize = false; 1.2062 + mNeedsMove = false; 1.2063 + 1.2064 + mWidget->setGeometry(aX, aY, aWidth, aHeight); 1.2065 + 1.2066 + if (aRepaint) { 1.2067 + mWidget->renderLater(); 1.2068 + } 1.2069 +} 1.2070 + 1.2071 +void 1.2072 +nsWindow::NativeShow(bool aAction) 1.2073 +{ 1.2074 + if (aAction) { 1.2075 + // On e10s, we never want the child process or plugin process 1.2076 + // to go fullscreen because if we do the window because visible 1.2077 + // do to disabled Qt-Xembed 1.2078 + mWidget->show(); 1.2079 + // unset our flag now that our window has been shown 1.2080 + mNeedsShow = false; 1.2081 + } 1.2082 + else { 1.2083 + mWidget->hide(); 1.2084 + } 1.2085 +} 1.2086 + 1.2087 +NS_IMETHODIMP 1.2088 +nsWindow::SetHasTransparentBackground(bool aTransparent) 1.2089 +{ 1.2090 + return NS_ERROR_NOT_IMPLEMENTED; 1.2091 +} 1.2092 + 1.2093 +NS_IMETHODIMP 1.2094 +nsWindow::GetHasTransparentBackground(bool& aTransparent) 1.2095 +{ 1.2096 + aTransparent = mIsTransparent; 1.2097 + return NS_OK; 1.2098 +} 1.2099 + 1.2100 +void * 1.2101 +nsWindow::SetupPluginPort(void) 1.2102 +{ 1.2103 + NS_WARNING("Not implemented"); 1.2104 + return nullptr; 1.2105 +} 1.2106 + 1.2107 +nsresult 1.2108 +nsWindow::SetWindowIconList(const nsTArray<nsCString> &aIconList) 1.2109 +{ 1.2110 + QIcon icon; 1.2111 + 1.2112 + for (uint32_t i = 0; i < aIconList.Length(); ++i) { 1.2113 + const char *path = aIconList[i].get(); 1.2114 + LOG(("window [%p] Loading icon from %s\n", (void *)this, path)); 1.2115 + icon.addFile(path); 1.2116 + } 1.2117 + 1.2118 + mWidget->setIcon(icon); 1.2119 + 1.2120 + return NS_OK; 1.2121 +} 1.2122 + 1.2123 +void 1.2124 +nsWindow::SetDefaultIcon(void) 1.2125 +{ 1.2126 + SetIcon(NS_LITERAL_STRING("default")); 1.2127 +} 1.2128 + 1.2129 +void nsWindow::QWidgetDestroyed() 1.2130 +{ 1.2131 + mWidget = nullptr; 1.2132 +} 1.2133 + 1.2134 + 1.2135 +NS_IMETHODIMP 1.2136 +nsWindow::HideWindowChrome(bool aShouldHide) 1.2137 +{ 1.2138 + if (!mWidget) { 1.2139 + // Nothing to hide 1.2140 + return NS_ERROR_FAILURE; 1.2141 + } 1.2142 + 1.2143 + // Sawfish, metacity, and presumably other window managers get 1.2144 + // confused if we change the window decorations while the window 1.2145 + // is visible. 1.2146 + bool wasVisible = false; 1.2147 + if (mWidget->isVisible()) { 1.2148 + NativeShow(false); 1.2149 + wasVisible = true; 1.2150 + } 1.2151 + 1.2152 + if (wasVisible) { 1.2153 + NativeShow(true); 1.2154 + } 1.2155 + 1.2156 + return NS_OK; 1.2157 +} 1.2158 + 1.2159 +////////////////////////////////////////////////////////////////////// 1.2160 + 1.2161 +NS_IMETHODIMP_(bool) 1.2162 +nsWindow::HasGLContext() 1.2163 +{ 1.2164 + return false; 1.2165 +} 1.2166 + 1.2167 + 1.2168 +nsIWidget* 1.2169 +nsWindow::GetParent(void) 1.2170 +{ 1.2171 + return mParent; 1.2172 +} 1.2173 + 1.2174 +float 1.2175 +nsWindow::GetDPI() 1.2176 +{ 1.2177 + return qApp->primaryScreen()->logicalDotsPerInch(); 1.2178 +} 1.2179 + 1.2180 +void 1.2181 +nsWindow::OnDestroy(void) 1.2182 +{ 1.2183 + if (mOnDestroyCalled) { 1.2184 + return; 1.2185 + } 1.2186 + 1.2187 + mOnDestroyCalled = true; 1.2188 + 1.2189 + // release references to children and device context 1.2190 + nsBaseWidget::OnDestroy(); 1.2191 + 1.2192 + // let go of our parent 1.2193 + mParent = nullptr; 1.2194 + 1.2195 + nsCOMPtr<nsIWidget> kungFuDeathGrip = this; 1.2196 + NotifyWindowDestroyed(); 1.2197 +} 1.2198 + 1.2199 +bool 1.2200 +nsWindow::AreBoundsSane(void) 1.2201 +{ 1.2202 + if (mBounds.width > 0 && mBounds.height > 0) { 1.2203 + return true; 1.2204 + } 1.2205 + 1.2206 + return false; 1.2207 +} 1.2208 + 1.2209 +void 1.2210 +nsWindow::SetSoftwareKeyboardState(bool aOpen, 1.2211 + const InputContextAction& aAction) 1.2212 +{ 1.2213 + if (aOpen) { 1.2214 + NS_ENSURE_TRUE_VOID(mInputContext.mIMEState.mEnabled != 1.2215 + IMEState::DISABLED); 1.2216 + 1.2217 + // Ensure that opening the virtual keyboard is allowed for this specific 1.2218 + // InputContext depending on the content.ime.strict.policy pref 1.2219 + if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN && 1.2220 + Preferences::GetBool("content.ime.strict_policy", false) && 1.2221 + !aAction.ContentGotFocusByTrustedCause() && 1.2222 + !aAction.UserMightRequestOpenVKB()) { 1.2223 + return; 1.2224 + } 1.2225 + } 1.2226 + 1.2227 + if (aOpen) { 1.2228 + qApp->inputMethod()->show(); 1.2229 + } else { 1.2230 + qApp->inputMethod()->hide(); 1.2231 + } 1.2232 + 1.2233 + return; 1.2234 +} 1.2235 + 1.2236 + 1.2237 +void 1.2238 +nsWindow::ProcessMotionEvent() 1.2239 +{ 1.2240 + if (mMoveEvent.needDispatch) { 1.2241 + WidgetMouseEvent event(true, NS_MOUSE_MOVE, this, 1.2242 + WidgetMouseEvent::eReal); 1.2243 + 1.2244 + event.refPoint.x = nscoord(mMoveEvent.pos.x()); 1.2245 + event.refPoint.y = nscoord(mMoveEvent.pos.y()); 1.2246 + 1.2247 + event.InitBasicModifiers(mMoveEvent.modifiers & Qt::ControlModifier, 1.2248 + mMoveEvent.modifiers & Qt::AltModifier, 1.2249 + mMoveEvent.modifiers & Qt::ShiftModifier, 1.2250 + mMoveEvent.modifiers & Qt::MetaModifier); 1.2251 + event.clickCount = 0; 1.2252 + 1.2253 + DispatchEvent(&event); 1.2254 + mMoveEvent.needDispatch = false; 1.2255 + } 1.2256 + 1.2257 + mTimerStarted = false; 1.2258 +} 1.2259 +