diff options
Diffstat (limited to 'src/gui/kernel/qguiapplication.cpp')
-rw-r--r-- | src/gui/kernel/qguiapplication.cpp | 164 |
1 files changed, 103 insertions, 61 deletions
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index a3ac0ff189..9f73f019a3 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtGui module of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ @@ -75,6 +75,7 @@ #include "private/qwindow_p.h" #include "private/qcursor_p.h" #include "private/qopenglcontext_p.h" +#include "private/qinputdevicemanager_p.h" #include "private/qdnd_p.h" #include <qpa/qplatformthemefactory_p.h> @@ -104,6 +105,14 @@ QT_BEGIN_NAMESPACE +// Helper macro for static functions to check on the existence of the application class. +#define CHECK_QAPP_INSTANCE(...) \ + if (Q_LIKELY(QCoreApplication::instance())) { \ + } else { \ + qWarning("Must construct a QGuiApplication first."); \ + return __VA_ARGS__; \ + } + Q_GUI_EXPORT bool qt_is_gui_used = true; Qt::MouseButtons QGuiApplicationPrivate::mouse_buttons = Qt::NoButton; @@ -138,12 +147,15 @@ QString *QGuiApplicationPrivate::displayName = 0; QPalette *QGuiApplicationPrivate::app_pal = 0; // default application palette Qt::MouseButtons QGuiApplicationPrivate::buttons = Qt::NoButton; + ulong QGuiApplicationPrivate::mousePressTime = 0; Qt::MouseButton QGuiApplicationPrivate::mousePressButton = Qt::NoButton; int QGuiApplicationPrivate::mousePressX = 0; int QGuiApplicationPrivate::mousePressY = 0; int QGuiApplicationPrivate::mouse_double_click_distance = -1; +QWindow *QGuiApplicationPrivate::currentMousePressWindow = 0; + static Qt::LayoutDirection layout_direction = Qt::LeftToRight; static bool force_reverse = false; @@ -162,8 +174,11 @@ QWindow *QGuiApplicationPrivate::focus_window = 0; static QBasicMutex applicationFontMutex; QFont *QGuiApplicationPrivate::app_font = 0; +QStyleHints *QGuiApplicationPrivate::styleHints = Q_NULLPTR; bool QGuiApplicationPrivate::obey_desktop_settings = true; +QInputDeviceManager *QGuiApplicationPrivate::m_inputDeviceManager = 0; + static qreal fontSmoothingGamma = 1.7; extern void qRegisterGuiVariant(); @@ -176,7 +191,7 @@ extern void qInitImageConversions(); static bool qt_detectRTLLanguage() { return force_reverse ^ - (QCoreApplication::tr("QT_LAYOUT_DIRECTION", + (QGuiApplication::tr("QT_LAYOUT_DIRECTION", "Translate this string to the string 'LTR' in left-to-right" " languages or to 'RTL' in right-to-left languages (such as Hebrew" " and Arabic) to get proper widget layout.") == QLatin1String("RTL")); @@ -215,11 +230,6 @@ static inline void clearFontUnlocked() QGuiApplicationPrivate::app_font = 0; } -static inline bool isPopupWindow(const QWindow *w) -{ - return (w->flags() & Qt::WindowType_Mask) == Qt::Popup; -} - // Geometry specification for top level windows following the convention of the // -geometry command line arguments in X11 (see XParseGeometry). struct QWindowGeometrySpecification @@ -597,7 +607,6 @@ QGuiApplication::~QGuiApplication() QGuiApplicationPrivate::QGuiApplicationPrivate(int &argc, char **argv, int flags) : QCoreApplicationPrivate(argc, argv, flags), - styleHints(0), inputMethod(0), lastTouchType(QEvent::TouchEnd), ownGlobalShareContext(false) @@ -650,6 +659,7 @@ QString QGuiApplication::applicationDisplayName() */ QWindow *QGuiApplication::modalWindow() { + CHECK_QAPP_INSTANCE(Q_NULLPTR) if (QGuiApplicationPrivate::self->modalWindowList.isEmpty()) return 0; return QGuiApplicationPrivate::self->modalWindowList.first(); @@ -671,7 +681,7 @@ static void updateBlockedStatusRecursion(QWindow *window, bool shouldBeBlocked) void QGuiApplicationPrivate::updateBlockedStatus(QWindow *window) { bool shouldBeBlocked = false; - if (!isPopupWindow(window) && !self->modalWindowList.isEmpty()) + if (!QWindowPrivate::get(window)->isPopup() && !self->modalWindowList.isEmpty()) shouldBeBlocked = self->isWindowBlocked(window); updateBlockedStatusRecursion(window, shouldBeBlocked); } @@ -681,7 +691,7 @@ void QGuiApplicationPrivate::showModalWindow(QWindow *modal) self->modalWindowList.prepend(modal); // Send leave for currently entered window if it should be blocked - if (currentMouseWindow && !isPopupWindow(currentMouseWindow)) { + if (currentMouseWindow && !QWindowPrivate::get(currentMouseWindow)->isPopup()) { bool shouldBeBlocked = self->isWindowBlocked(currentMouseWindow); if (shouldBeBlocked) { // Remove the new window from modalWindowList temporarily so leave can go through @@ -790,12 +800,6 @@ bool QGuiApplicationPrivate::isWindowBlocked(QWindow *window, QWindow **blocking return false; } -bool QGuiApplicationPrivate::synthesizeMouseFromTouchEventsEnabled() -{ - return QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents) - && QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::SynthesizeMouseFromTouchEvents).toBool(); -} - /*! Returns the QWindow that receives events tied to focus, such as key events. @@ -872,9 +876,14 @@ QWindowList QGuiApplication::topLevelWindows() } /*! - Returns the primary (or default) screen of the application. + Returns the primary (or default) screen of the application, or null if there is none This will be the screen where QWindows are initially shown, unless otherwise specified. + + On some platforms, it may be null when there are actually no screens connected. + It is not possible to start a new QGuiApplication while there are no screens. + Applications which were running at the time the primary screen was removed + will stop rendering graphics until one or more screens are restored. */ QScreen *QGuiApplication::primaryScreen() { @@ -1094,6 +1103,8 @@ static void init_plugins(const QList<QByteArray> &pluginList) QLatin1String(pluginSpec.mid(colonPos+1))); if (plugin) QGuiApplicationPrivate::generic_plugin_list.append(plugin); + else + qWarning() << "No such plugin for spec " << pluginSpec; } } @@ -1259,8 +1270,11 @@ void QGuiApplicationPrivate::init() } // Load environment exported generic plugins - foreach (const QByteArray &plugin, qgetenv("QT_QPA_GENERIC_PLUGINS").split(',')) - pluginList << plugin; + QByteArray envPlugins = qgetenv("QT_QPA_GENERIC_PLUGINS"); + if (!envPlugins.isEmpty()) { + foreach (const QByteArray &plugin, envPlugins.split(',')) + pluginList << plugin; + } if (platform_integration == 0) createPlatformIntegration(); @@ -1352,7 +1366,8 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate() cleanupThreadData(); - delete styleHints; + delete QGuiApplicationPrivate::styleHints; + QGuiApplicationPrivate::styleHints = Q_NULLPTR; delete inputMethod; qt_cleanupFontDatabase(); @@ -1366,6 +1381,8 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate() } #endif + platform_integration->destroy(); + delete platform_theme; platform_theme = 0; delete platform_integration; @@ -1430,6 +1447,7 @@ Qt::KeyboardModifiers QGuiApplication::keyboardModifiers() */ Qt::KeyboardModifiers QGuiApplication::queryKeyboardModifiers() { + CHECK_QAPP_INSTANCE(Qt::KeyboardModifiers(0)) QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration(); return pi->queryKeyboardModifiers(); } @@ -1511,18 +1529,6 @@ int QGuiApplication::exec() */ bool QGuiApplication::notify(QObject *object, QEvent *event) { -#ifndef QT_NO_SHORTCUT - if (event->type() == QEvent::KeyPress) { - // Try looking for a Shortcut before sending key events - QWindow *w = qobject_cast<QWindow *>(object); - QObject *focus = w ? w->focusObject() : 0; - if (!focus) - focus = object; - if (QGuiApplicationPrivate::instance()->shortcutMap.tryShortcutEvent(focus, static_cast<QKeyEvent *>(event))) - return true; - } -#endif - if (object->isWindowType()) QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(static_cast<QWindow *>(object), event); return QCoreApplication::notify(object, event); @@ -1685,7 +1691,8 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo // with the current event, we split it in two. QWindowSystemInterfacePrivate::MouseEvent *mouseButtonEvent = new QWindowSystemInterfacePrivate::MouseEvent( e->window.data(), e->timestamp, e->type, e->localPos, e->globalPos, e->buttons, e->modifiers); - mouseButtonEvent->synthetic = e->synthetic; + if (e->flags & QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic) + mouseButtonEvent->flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; QWindowSystemInterfacePrivate::windowSystemEventQueue.prepend(mouseButtonEvent); stateChange = Qt::NoButton; } @@ -1696,9 +1703,20 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo QPointF localPoint = e->localPos; QPointF globalPoint = e->globalPos; - if (e->nullWindow) { + if (e->nullWindow()) { window = QGuiApplication::topLevelAt(globalPoint.toPoint()); if (window) { + // Moves and the release following a press must go to the same + // window, even if the cursor has moved on over another window. + if (e->buttons != Qt::NoButton) { + if (!currentMousePressWindow) + currentMousePressWindow = window; + else + window = currentMousePressWindow; + } else if (currentMousePressWindow) { + window = currentMousePressWindow; + currentMousePressWindow = 0; + } QPointF delta = globalPoint - globalPoint.toPoint(); localPoint = window->mapFromGlobal(globalPoint.toPoint()) + delta; } @@ -1729,7 +1747,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo } mouse_buttons = buttons = e->buttons; if (button & e->buttons) { - ulong doubleClickInterval = static_cast<ulong>(qApp->styleHints()->mouseDoubleClickInterval()); + ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval()); doubleClick = e->timestamp - mousePressTime < doubleClickInterval && button == mousePressButton; type = frameStrut ? QEvent::NonClientAreaMouseButtonPress : QEvent::MouseButtonPress; mousePressTime = e->timestamp; @@ -1749,7 +1767,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo ev.setTimestamp(e->timestamp); setMouseEventSource(&ev, e->source); #ifndef QT_NO_CURSOR - if (!e->synthetic) { + if (!e->synthetic()) { if (const QScreen *screen = window->screen()) if (QPlatformCursor *cursor = screen->handle()->cursor()) cursor->pointerEvent(ev); @@ -1767,7 +1785,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo } QGuiApplication::sendSpontaneousEvent(window, &ev); - if (!e->synthetic && !ev.isAccepted() + if (!e->synthetic() && !ev.isAccepted() && !frameStrut && qApp->testAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents)) { if (!m_fakeTouchDevice) { @@ -1798,12 +1816,12 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::convertTouchPoints(points, &type); QWindowSystemInterfacePrivate::TouchEvent fake(window, e->timestamp, type, m_fakeTouchDevice, touchPoints, e->modifiers); - fake.synthetic = true; + fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; processTouchEvent(&fake); } if (doubleClick) { mousePressButton = Qt::NoButton; - if (!e->window.isNull() || e->nullWindow) { // QTBUG-36364, check if window closed in response to press + if (!e->window.isNull() || e->nullWindow()) { // QTBUG-36364, check if window closed in response to press const QEvent::Type doubleClickType = frameStrut ? QEvent::NonClientAreaMouseButtonDblClick : QEvent::MouseButtonDblClick; QMouseEvent dblClickEvent(doubleClickType, localPoint, localPoint, globalPoint, button, buttons, e->modifiers); @@ -1821,7 +1839,7 @@ void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::Wh QPointF globalPoint = e->globalPos; QPointF localPoint = e->localPos; - if (e->nullWindow) { + if (e->nullWindow()) { window = QGuiApplication::topLevelAt(globalPoint.toPoint()); if (window) { QPointF delta = globalPoint - globalPoint.toPoint(); @@ -1840,7 +1858,7 @@ void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::Wh return; } - QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta, e->qt4Delta, e->qt4Orientation, buttons, e->modifiers, e->phase); + QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta, e->qt4Delta, e->qt4Orientation, buttons, e->modifiers, e->phase, e->source); ev.setTimestamp(e->timestamp); QGuiApplication::sendSpontaneousEvent(window, &ev); #endif /* ifndef QT_NO_WHEELEVENT */ @@ -1852,7 +1870,7 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE { QWindow *window = e->window.data(); modifier_buttons = e->modifiers; - if (e->nullWindow + if (e->nullWindow() #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_NO_SDK) || e->key == Qt::Key_Back || e->key == Qt::Key_Menu #endif @@ -1860,6 +1878,13 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE window = QGuiApplication::focusWindow(); } +#if !defined(Q_OS_OSX) + // On OS X the shortcut override is checked earlier, see: QWindowSystemInterface::handleKeyEvent() + const bool checkShortcut = e->keyType == QEvent::KeyPress && window != 0; + if (checkShortcut && QWindowSystemInterface::tryHandleShortcutEvent(window, e->timestamp, e->key, e->modifiers, e->unicode)) + return; +#endif // Q_OS_OSX + QKeyEvent ev(e->keyType, e->key, e->modifiers, e->nativeScanCode, e->nativeVirtualKey, e->nativeModifiers, e->unicode, e->repeat, e->repeatCount); @@ -2093,7 +2118,7 @@ void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::T // subsequent events up to the release are delivered to that same window. // If window is given, just send to that. if (type == QEvent::TabletPress) { - if (e->nullWindow) { + if (e->nullWindow()) { window = QGuiApplication::topLevelAt(e->global.toPoint()); localValid = false; } @@ -2101,7 +2126,7 @@ void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::T return; tabletPressTarget = window; } else { - if (e->nullWindow) { + if (e->nullWindow()) { window = tabletPressTarget; localValid = false; } @@ -2238,7 +2263,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To touchEvent.setWindow(*winIt); QGuiApplication::sendSpontaneousEvent(*winIt, &touchEvent); } - if (!self->synthesizedMousePoints.isEmpty() && !e->synthetic) { + if (!self->synthesizedMousePoints.isEmpty() && !e->synthetic()) { for (QHash<QWindow *, SynthesizedMouseData>::const_iterator synthIt = self->synthesizedMousePoints.constBegin(), synthItEnd = self->synthesizedMousePoints.constEnd(); synthIt != synthItEnd; ++synthIt) { if (!synthIt->window) @@ -2250,7 +2275,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To buttons & ~Qt::LeftButton, e->modifiers, Qt::MouseEventSynthesizedByQt); - fake.synthetic = true; + fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; processMouseEvent(&fake); } self->synthesizedMousePoints.clear(); @@ -2429,9 +2454,9 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To } QGuiApplication::sendSpontaneousEvent(w, &touchEvent); - if (!e->synthetic && !touchEvent.isAccepted() && synthesizeMouseFromTouchEventsEnabled()) { - // exclude touchpads as those generate their own mouse events - if (touchEvent.device()->type() != QTouchDevice::TouchPad) { + if (!e->synthetic() && !touchEvent.isAccepted() && qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) { + // exclude devices which generate their own mouse events + if (!(touchEvent.device()->capabilities() & QTouchDevice::MouseEmulation)) { Qt::MouseButtons b = eventType == QEvent::TouchEnd ? Qt::NoButton : Qt::LeftButton; if (b == Qt::NoButton) self->synthesizedMousePoints.clear(); @@ -2452,7 +2477,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To b | (buttons & ~Qt::LeftButton), e->modifiers, Qt::MouseEventSynthesizedByQt); - fake.synthetic = true; + fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; processMouseEvent(&fake); break; } @@ -2543,7 +2568,7 @@ void QGuiApplicationPrivate::reportGeometryChange(QWindowSystemInterfacePrivate: } if (availableGeometryChanged) - emit s->availableGeometryChanged(s->geometry()); + emit s->availableGeometryChanged(s->availableGeometry()); if (geometryChanged || availableGeometryChanged) { foreach (QScreen* sibling, s->virtualSiblings()) @@ -2592,6 +2617,8 @@ void QGuiApplicationPrivate::processExposeEvent(QWindowSystemInterfacePrivate::E return; QWindow *window = e->exposed.data(); + if (!window) + return; QWindowPrivate *p = qt_window_private(window); if (!p->receivedExpose) { @@ -2607,7 +2634,7 @@ void QGuiApplicationPrivate::processExposeEvent(QWindowSystemInterfacePrivate::E p->receivedExpose = true; } - p->exposed = e->isExposed; + p->exposed = e->isExposed && window->screen(); QExposeEvent exposeEvent(e->region); QCoreApplication::sendSpontaneousEvent(window, &exposeEvent); @@ -3176,6 +3203,7 @@ Qt::LayoutDirection QGuiApplication::layoutDirection() #ifndef QT_NO_CURSOR QCursor *QGuiApplication::overrideCursor() { + CHECK_QAPP_INSTANCE(Q_NULLPTR) return qGuiApp->d_func()->cursor_list.isEmpty() ? 0 : &qGuiApp->d_func()->cursor_list.first(); } @@ -3189,6 +3217,7 @@ QCursor *QGuiApplication::overrideCursor() */ void QGuiApplication::changeOverrideCursor(const QCursor &cursor) { + CHECK_QAPP_INSTANCE() if (qGuiApp->d_func()->cursor_list.isEmpty()) return; qGuiApp->d_func()->cursor_list.removeFirst(); @@ -3263,6 +3292,7 @@ static inline void applyWindowCursor(const QList<QWindow *> &l) */ void QGuiApplication::setOverrideCursor(const QCursor &cursor) { + CHECK_QAPP_INSTANCE() qGuiApp->d_func()->cursor_list.prepend(cursor); applyCursor(QGuiApplicationPrivate::window_list, cursor); } @@ -3280,6 +3310,7 @@ void QGuiApplication::setOverrideCursor(const QCursor &cursor) */ void QGuiApplication::restoreOverrideCursor() { + CHECK_QAPP_INSTANCE() if (qGuiApp->d_func()->cursor_list.isEmpty()) return; qGuiApp->d_func()->cursor_list.removeFirst(); @@ -3304,9 +3335,9 @@ void QGuiApplication::restoreOverrideCursor() */ QStyleHints *QGuiApplication::styleHints() { - if (!qGuiApp->d_func()->styleHints) - qGuiApp->d_func()->styleHints = new QStyleHints(); - return qGuiApp->d_func()->styleHints; + if (!QGuiApplicationPrivate::styleHints) + QGuiApplicationPrivate::styleHints = new QStyleHints(); + return QGuiApplicationPrivate::styleHints; } /*! @@ -3347,6 +3378,7 @@ bool QGuiApplication::desktopSettingsAware() */ QInputMethod *QGuiApplication::inputMethod() { + CHECK_QAPP_INSTANCE(Q_NULLPTR) if (!qGuiApp->d_func()->inputMethod) qGuiApp->d_func()->inputMethod = new QInputMethod(); return qGuiApp->d_func()->inputMethod; @@ -3482,6 +3514,16 @@ void QGuiApplicationPrivate::setMouseEventFlags(QMouseEvent *event, Qt::MouseEve event->caps |= (value & Qt::MouseEventFlagMask) << MouseFlagsShift; } +QInputDeviceManager *QGuiApplicationPrivate::inputDeviceManager() +{ + Q_ASSERT(QGuiApplication::instance()); + + if (!m_inputDeviceManager) + m_inputDeviceManager = new QInputDeviceManager(QGuiApplication::instance()); + + return m_inputDeviceManager; +} + #include "moc_qguiapplication.cpp" QT_END_NAMESPACE |