diff options
author | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2018-08-21 02:32:49 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2018-08-21 02:32:50 +0200 |
commit | 5a03b75c50b2e34552c7ec3e1e15e7b2a0128bf7 (patch) | |
tree | 88e05cd6150e0b3cda4e8716668082c655007fb8 /src/plugins/platforms | |
parent | 0e7724079f1eae283714ae12769d1372b8f85659 (diff) | |
parent | 6553921dd537e416da2f4d1441ab6d63059cda60 (diff) |
Merge dev into 5.12
Change-Id: I63f632b595f66d2fc93e9aa713500e3799e3df2a
Diffstat (limited to 'src/plugins/platforms')
29 files changed, 558 insertions, 704 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h index 3f7966b247..0e5934bc23 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.h +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h @@ -41,9 +41,6 @@ #define QCOCOAGLCONTEXT_H #include <QtCore/QPointer> -#include <QtCore/qvector.h> -#include <QtCore/private/qcore_mac_p.h> - #include <qpa/qplatformopenglcontext.h> #include <QtGui/QOpenGLContext> #include <QtGui/QWindow> @@ -68,6 +65,8 @@ public: bool isSharing() const override; bool isValid() const override; + void windowWasHidden(); + NSOpenGLContext *nativeContext() const; QFunctionPointer getProcAddress(const char *procName) override; @@ -75,14 +74,14 @@ public: private: static NSOpenGLPixelFormat *pixelFormatForSurfaceFormat(const QSurfaceFormat &format); - bool setDrawable(QPlatformSurface *surface); + bool setActiveWindow(QWindow *window); void updateSurfaceFormat(); NSOpenGLContext *m_context = nil; NSOpenGLContext *m_shareContext = nil; QSurfaceFormat m_format; + QPointer<QWindow> m_currentWindow; bool m_didCheckForSoftwareContext = false; - QVarLengthArray<QMacScopedObserver, 3> m_observers; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index cba9e90a78..4d0fa2e28e 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -41,8 +41,6 @@ #include "qcocoawindow.h" #include "qcocoahelpers.h" #include <qdebug.h> -#include <QtCore/qscopedvaluerollback.h> -#include <QtCore/qatomic.h> #include <QtCore/private/qcore_mac_p.h> #include <QtPlatformHeaders/qcocoanativecontext.h> #include <dlfcn.h> @@ -322,6 +320,9 @@ void QCocoaGLContext::updateSurfaceFormat() QCocoaGLContext::~QCocoaGLContext() { + if (m_currentWindow && m_currentWindow.data()->handle()) + static_cast<QCocoaWindow *>(m_currentWindow.data()->handle())->setCurrentContext(0); + [m_context release]; } @@ -330,14 +331,6 @@ bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface) qCDebug(lcQpaOpenGLContext) << "Making" << m_context << "current" << "in" << QThread::currentThread() << "for" << surface; - // No need to make context current if it already is. This also ensures - // that we only lock the context once, meaning we don't need to keep - // track of how many times we've locked it to undo it in doneCurrent(). - // Note that we're not using QOpenGLContext::currentContext() here, as - // that has already been updated to match context() before this call. - if ([NSOpenGLContext currentContext] == m_context) - return true; - Q_ASSERT(surface->surface()->supportsOpenGL()); if (surface->surface()->surfaceClass() == QSurface::Offscreen) { @@ -345,14 +338,11 @@ bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface) return true; } - if (!setDrawable(surface)) + QWindow *window = static_cast<QCocoaWindow *>(surface)->window(); + if (!setActiveWindow(window)) { + qCDebug(lcQpaOpenGLContext) << "Failed to activate window, skipping makeCurrent"; return false; - - // The context may be owned and used by a dedicated render thread, but - // we will get notifications that trigger update() on the main thread, - // so we need to guard against concurrent uses of the context. We hold - // this lock until swapBuffer() or doneCurrent() gets called. - CGLLockContext(m_context.CGLContextObj); + } [m_context makeCurrentContext]; @@ -373,74 +363,43 @@ bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface) } } + update(); return true; } -/*! - Sets the drawable object of the NSOpenGLContext, which is the - frame buffer that is the target of OpenGL drawing operations. -*/ -bool QCocoaGLContext::setDrawable(QPlatformSurface *surface) +bool QCocoaGLContext::setActiveWindow(QWindow *window) { - Q_ASSERT(surface->surface()->surfaceClass() == QSurface::Window); - NSView *view = static_cast<QCocoaWindow *>(surface)->view(); - - if (view == m_context.view) + if (window == m_currentWindow.data()) return true; - m_observers.clear(); + Q_ASSERT(window->handle()); + QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); + NSView *view = cocoaWindow->view(); if ((m_context.view = view) != view) { - qCInfo(lcQpaOpenGLContext) << "Failed to set" << view << "as drawable for" << m_context; + qCDebug(lcQpaOpenGLContext) << "Associating" << view << "with" << m_context << "failed"; return false; } - qCInfo(lcQpaOpenGLContext) << "Set drawable for" << m_context << "to" << m_context.view; - - auto updateCallback = [&]() { update(); }; + qCDebug(lcQpaOpenGLContext) << m_context << "now associated with" << m_context.view; - if (view.layer) { - m_observers.append(QMacScopedObserver(view, NSViewFrameDidChangeNotification, updateCallback)); - m_observers.append(QMacScopedObserver(view.window, NSWindowDidChangeScreenNotification, updateCallback)); - } else { - m_observers.append(QMacScopedObserver(view, NSViewGlobalFrameDidChangeNotification, updateCallback)); - } + if (m_currentWindow && m_currentWindow.data()->handle()) + static_cast<QCocoaWindow *>(m_currentWindow.data()->handle())->setCurrentContext(0); - m_observers.append(QMacScopedObserver([NSApplication sharedApplication], - NSApplicationDidChangeScreenParametersNotification, updateCallback)); + m_currentWindow = window; + cocoaWindow->setCurrentContext(this); return true; } -// NSOpenGLContext is not re-entrant, which means that even when using separate -// contexts per thread, per view, and window, calls into the API will still deadlock. -// Note that this is different from the use of CGLLockContext and CGLUnlockContext -// to prevent concurrent access to the _same_ context from two different threads. -// The latter is expected due to NSOpenGLContext not being thread-safe, while the -// former is working around bugs in NSOpenGLContext that make it not re-entrant. -// For more information see https://openradar.appspot.com/37064579 +// NSOpenGLContext is not re-entrant (https://openradar.appspot.com/37064579) static QMutex s_contextMutex; void QCocoaGLContext::update() { - // Updating the context may result in a call to [NSSurface setFrame:], which - // will recurse back here through NSViewGlobalFrameDidChangeNotification. We - // could use a recursive mutex to prevent a deadlock, but since they are slower - // we opt for a manual recursion check. - static QAtomicPointer<void> updatingThread = nullptr; - if (updatingThread == QThread::currentThreadId()) - return; - - // Guard against concurrent access to the context in the case where there - // is a dedicated render thread operating on the context. See makeCurrent(). - CGLLockContext(m_context.CGLContextObj); - QMutexLocker locker(&s_contextMutex); - QScopedValueRollback<QAtomicPointer<void>> rollback(updatingThread, QThread::currentThreadId()); qCInfo(lcQpaOpenGLContext) << "Updating" << m_context << "for" << m_context.view; [m_context update]; - - CGLUnlockContext(m_context.CGLContextObj); } void QCocoaGLContext::swapBuffers(QPlatformSurface *surface) @@ -451,52 +410,37 @@ void QCocoaGLContext::swapBuffers(QPlatformSurface *surface) if (surface->surface()->surfaceClass() == QSurface::Offscreen) return; // Nothing to do - if (!setDrawable(surface)) { - qCWarning(lcQpaOpenGLContext) << "Can't flush" << m_context - << "without" << surface << "as drawable"; + QWindow *window = static_cast<QCocoaWindow *>(surface)->window(); + if (!setActiveWindow(window)) { + qCWarning(lcQpaOpenGLContext) << "Failed to activate window, skipping swapBuffers"; return; } QMutexLocker locker(&s_contextMutex); [m_context flushBuffer]; - - // We're done flushing, and should release the lock we have on the - // context. To ensure that we're not leaving the context current - // without a lock held on it, we need to couple this with actually - // clearing the context. This should not be a performance hit for the - // case where the same context is made current and then cleared, and - // QOpenGLContext::swapBuffers is documented as requiring makeCurrent - // again before beginning a new frame, so the user can't expect the - // context to be current after a call to swapBuffers(). We explicitly - // go via QOpenGLContext for this, instead of calling our platform - // method directly, as that will ensure QOpenGLContext records the - // fact that there is no longer a current context. We then end up - // in QCocoaGLContext::doneCurrent, where we clear the lock. - context()->doneCurrent(); } void QCocoaGLContext::doneCurrent() { - auto currentContext = QOpenGLContext::currentContext(); - if (!currentContext) - return; - - // QOpenGLContext::doneCurrent() clears the current context, but can - // be called on any context, not necessarily the current one. Since - // we rely on unlocking the context lock we must propagate the call - // to the right context. - if (context() != currentContext) { - currentContext->doneCurrent(); - return; - } - - Q_ASSERT([NSOpenGLContext currentContext] == m_context); - qCDebug(lcQpaOpenGLContext) << "Clearing current context" << [NSOpenGLContext currentContext] << "in" << QThread::currentThread(); + if (m_currentWindow && m_currentWindow.data()->handle()) + static_cast<QCocoaWindow *>(m_currentWindow.data()->handle())->setCurrentContext(nullptr); + + m_currentWindow.clear(); + [NSOpenGLContext clearCurrentContext]; - CGLUnlockContext(m_context.CGLContextObj); +} + +void QCocoaGLContext::windowWasHidden() +{ + // If the window is hidden, we need to unset the m_currentWindow + // variable so that succeeding makeCurrent's will not abort prematurely + // because of the optimization in setActiveWindow. + // Doing a full doneCurrent here is not preferable, because the GL context + // might be rendering in a different thread at this time. + m_currentWindow.clear(); } QSurfaceFormat QCocoaGLContext::format() const diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 612290c9bd..0f87109ada 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -72,6 +72,12 @@ #include <IOKit/graphics/IOGraphicsLib.h> +#if !QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14) +@interface NSApplication (MojaveForwardDeclarations) +@property (strong) NSAppearance *appearance NS_AVAILABLE_MAC(10_14); +@end +#endif + static void initResources() { Q_INIT_RESOURCE(qcocoaresources); @@ -133,6 +139,21 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) NSApplication *cocoaApplication = [QNSApplication sharedApplication]; qt_redirectNSApplicationSendEvent(); + if (__builtin_available(macOS 10.14, *)) { + // Disable dark appearance, unless the Info.plist or environment requests that it should be enabled + bool plistEnablesDarkAppearance = [[[NSBundle mainBundle] objectForInfoDictionaryKey: + @"NSRequiresAquaSystemAppearance"] boolValue]; + + bool hasEnvironmentRequiresAquaAppearance; + int environmentRequiresAquaAppearance = qEnvironmentVariableIntValue( + "QT_MAC_REQUIRES_AQUA_SYSTEM_APPEARANCE", &hasEnvironmentRequiresAquaAppearance); + bool environmentEnablesDarkAppearance = hasEnvironmentRequiresAquaAppearance + && environmentRequiresAquaAppearance == 0; + + if (!(plistEnablesDarkAppearance || environmentEnablesDarkAppearance)) + NSApp.appearance = [NSAppearance appearanceNamed:NSAppearanceNameAqua]; + } + if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) { // Applications launched from plain executables (without an app // bundle) are "background" applications that does not take keybaord diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index 7979e430ac..228df50d86 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm @@ -102,6 +102,10 @@ void *QCocoaNativeInterface::nativeResourceForWindow(const QByteArray &resourceS if (resourceString == "nsview") { return static_cast<QCocoaWindow *>(window->handle())->m_view; +#ifndef QT_NO_OPENGL + } else if (resourceString == "nsopenglcontext") { + return static_cast<QCocoaWindow *>(window->handle())->currentContext()->nativeContext(); +#endif } else if (resourceString == "nswindow") { return static_cast<QCocoaWindow *>(window->handle())->nativeWindow(); #if QT_CONFIG(vulkan) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 8f1bdb8af0..225c7eda84 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -169,6 +169,11 @@ public: NSUInteger windowStyleMask(Qt::WindowFlags flags); void setWindowZoomButton(Qt::WindowFlags flags); +#ifndef QT_NO_OPENGL + void setCurrentContext(QCocoaGLContext *context); + QCocoaGLContext *currentContext() const; +#endif + bool setWindowModified(bool modified) override; void setFrameStrutEventsEnabled(bool enabled) override; @@ -248,6 +253,9 @@ public: // for QNSView bool m_inSetVisible; bool m_inSetGeometry; bool m_inSetStyleMask; +#ifndef QT_NO_OPENGL + QCocoaGLContext *m_glContext; +#endif QCocoaMenuBar *m_menubar; bool m_needsInvalidateShadow; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index b79804fd0b..3148501006 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -41,6 +41,9 @@ #include "qcocoascreen.h" #include "qnswindowdelegate.h" #include "qcocoaeventdispatcher.h" +#ifndef QT_NO_OPENGL +#include "qcocoaglcontext.h" +#endif #include "qcocoahelpers.h" #include "qcocoanativeinterface.h" #include "qnsview.h" @@ -148,6 +151,9 @@ QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle) , m_inSetVisible(false) , m_inSetGeometry(false) , m_inSetStyleMask(false) +#ifndef QT_NO_OPENGL + , m_glContext(nullptr) +#endif , m_menubar(nullptr) , m_needsInvalidateShadow(false) , m_hasModalSession(false) @@ -397,6 +403,10 @@ void QCocoaWindow::setVisible(bool visible) [m_view setHidden:NO]; } else { // qDebug() << "close" << this; +#ifndef QT_NO_OPENGL + if (m_glContext) + m_glContext->windowWasHidden(); +#endif QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher()); QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = nullptr; if (cocoaEventDispatcher) @@ -1324,6 +1334,18 @@ bool QCocoaWindow::windowIsPopupType(Qt::WindowType type) const return ((type & Qt::Popup) == Qt::Popup); } +#ifndef QT_NO_OPENGL +void QCocoaWindow::setCurrentContext(QCocoaGLContext *context) +{ + m_glContext = context; +} + +QCocoaGLContext *QCocoaWindow::currentContext() const +{ + return m_glContext; +} +#endif + /*! Checks if the window is the content view of its immediate NSWindow. diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm index 1de256825a..65bc9f837d 100644 --- a/src/plugins/platforms/cocoa/qnsview_mouse.mm +++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm @@ -566,6 +566,42 @@ NSTimeInterval timestamp = [theEvent timestamp]; ulong qt_timestamp = timestamp * 1000; + Qt::ScrollPhase phase = Qt::NoScrollPhase; + if (theEvent.phase == NSEventPhaseMayBegin || theEvent.phase == NSEventPhaseBegan) { + // MayBegin is likely to happen. We treat it the same as an actual begin, + // and follow it with an update when the actual begin is delivered. + phase = m_scrolling ? Qt::ScrollUpdate : Qt::ScrollBegin; + m_scrolling = true; + } else if (theEvent.phase == NSEventPhaseStationary || theEvent.phase == NSEventPhaseChanged) { + phase = Qt::ScrollUpdate; + } else if (theEvent.phase == NSEventPhaseEnded) { + // A scroll event phase may be followed by a momentum phase after the user releases + // the finger, and in that case we don't want to send a Qt::ScrollEnd until after + // the momentum phase has ended. Unfortunately there isn't any guaranteed way of + // knowing whether or not a NSEventPhaseEnded will be followed by a momentum phase. + // The best we can do is to look at the event queue and hope that the system has + // had time to emit a momentum phase event. + if ([NSApp nextEventMatchingMask:NSScrollWheelMask untilDate:[NSDate distantPast] + inMode:@"QtMomementumEventSearchMode" dequeue:NO].momentumPhase == NSEventPhaseBegan) { + Q_ASSERT(pixelDelta.isNull() && angleDelta.isNull()); + return; // Ignore this event, as it has a delta of 0,0 + } + phase = Qt::ScrollEnd; + m_scrolling = false; + } else if (theEvent.momentumPhase == NSEventPhaseBegan) { + Q_ASSERT(!pixelDelta.isNull() && !angleDelta.isNull()); + phase = Qt::ScrollUpdate; // Send as update, it has a delta + } else if (theEvent.momentumPhase == NSEventPhaseChanged) { + phase = Qt::ScrollMomentum; + } else if (theEvent.phase == NSEventPhaseCancelled + || theEvent.momentumPhase == NSEventPhaseEnded + || theEvent.momentumPhase == NSEventPhaseCancelled) { + phase = Qt::ScrollEnd; + m_scrolling = false; + } else { + Q_ASSERT(theEvent.momentumPhase != NSEventPhaseStationary); + } + // Prevent keyboard modifier state from changing during scroll event streams. // A two-finger trackpad flick generates a stream of scroll events. We want // the keyboard modifier state to be the state at the beginning of the @@ -573,34 +609,16 @@ // mid-stream. One example of this happening would be when pressing cmd // after scrolling in Qt Creator: not taking the phase into account causes // the end of the event stream to be interpreted as font size changes. - NSEventPhase momentumPhase = [theEvent momentumPhase]; - if (momentumPhase == NSEventPhaseNone) + if (theEvent.momentumPhase == NSEventPhaseNone) m_currentWheelModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]]; - NSEventPhase phase = [theEvent phase]; - Qt::ScrollPhase ph = Qt::ScrollUpdate; - - // MayBegin is likely to happen. We treat it the same as an actual begin. - if (phase == NSEventPhaseMayBegin) { - m_scrolling = true; - ph = Qt::ScrollBegin; - } else if (phase == NSEventPhaseBegan) { - // If MayBegin did not happen, Began is the actual beginning. - if (!m_scrolling) - ph = Qt::ScrollBegin; - m_scrolling = true; - } else if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled || - momentumPhase == NSEventPhaseEnded || momentumPhase == NSEventPhaseCancelled) { - ph = Qt::ScrollEnd; - m_scrolling = false; - } else if (phase == NSEventPhaseNone && momentumPhase == NSEventPhaseNone) { - ph = Qt::NoScrollPhase; - } // "isInverted": natural OS X scrolling, inverted from the Qt/other platform/Jens perspective. bool isInverted = [theEvent isDirectionInvertedFromDevice]; - qCDebug(lcQpaMouse) << "scroll wheel @ window pos" << qt_windowPoint << "delta px" << pixelDelta << "angle" << angleDelta << "phase" << ph << (isInverted ? "inverted" : ""); - QWindowSystemInterface::handleWheelEvent(m_platformWindow->window(), qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, m_currentWheelModifiers, ph, source, isInverted); + qCDebug(lcQpaMouse) << "scroll wheel @ window pos" << qt_windowPoint << "delta px" << pixelDelta + << "angle" << angleDelta << "phase" << phase << (isInverted ? "inverted" : ""); + QWindowSystemInterface::handleWheelEvent(m_platformWindow->window(), qt_timestamp, qt_windowPoint, + qt_screenPoint, pixelDelta, angleDelta, m_currentWheelModifiers, phase, source, isInverted); } #endif // QT_CONFIG(wheelevent) diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index 87f48e0c84..c1c275144f 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -257,12 +257,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result) { -#ifdef Q_COMPILER_CLASS_ENUM enum : quint64 { signatureMask = 0xffffff00, miWpSignature = 0xff515700 }; -#else - static const quint64 signatureMask = 0xffffff00; - static const quint64 miWpSignature = 0xff515700; -#endif // !Q_COMPILER_CLASS_ENUM if (et == QtWindows::MouseWheelEvent) return translateMouseWheelEvent(window, hwnd, msg, result); diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index f25e6d13d8..c11be972b0 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -239,8 +239,8 @@ static QTouchDevice *createTouchDevice() QTouchDevice *QWindowsPointerHandler::ensureTouchDevice() { if (!m_touchDevice) - m_touchDevice.reset(createTouchDevice()); - return m_touchDevice.data(); + m_touchDevice = createTouchDevice(); + return m_touchDevice; } Qt::MouseButtons QWindowsPointerHandler::queryMouseButtons() @@ -400,7 +400,7 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, touchPoints.append(touchPoint); } - QWindowSystemInterface::handleTouchEvent(window, m_touchDevice.data(), touchPoints, + QWindowSystemInterface::handleTouchEvent(window, m_touchDevice, touchPoints, QWindowsKeyMapper::queryKeyboardModifiers()); if (!(QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch)) { diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.h b/src/plugins/platforms/windows/qwindowspointerhandler.h index 11bc9419d7..c4d0e0ce4a 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.h +++ b/src/plugins/platforms/windows/qwindowspointerhandler.h @@ -59,7 +59,7 @@ public: QWindowsPointerHandler() = default; bool translatePointerEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result); bool translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result); - QTouchDevice *touchDevice() const { return m_touchDevice.data(); } + QTouchDevice *touchDevice() const { return m_touchDevice; } QTouchDevice *ensureTouchDevice(); Qt::MouseButtons queryMouseButtons(); QWindow *windowUnderMouse() const { return m_windowUnderPointer.data(); } @@ -70,7 +70,7 @@ private: bool translateTouchEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vTouchInfo, unsigned int count); bool translatePenEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPenInfo); - QScopedPointer<QTouchDevice> m_touchDevice; + QTouchDevice *m_touchDevice = nullptr; QHash<int, QPointF> m_lastTouchPositions; QPointer<QWindow> m_windowUnderPointer; QPointer<QWindow> m_currentWindow; diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 29165ef72c..2eaf386d42 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -330,10 +330,7 @@ QRect QWindowsScreen::virtualGeometry(const QPlatformScreen *screen) // cf QScre return result; } -enum OrientationPreference // matching Win32 API ORIENTATION_PREFERENCE -#if defined(Q_COMPILER_CLASS_ENUM) || defined(Q_CC_MSVC) - : DWORD -#endif +enum OrientationPreference : DWORD // matching Win32 API ORIENTATION_PREFERENCE { orientationPreferenceNone = 0, orientationPreferenceLandscape = 0x1, diff --git a/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h b/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h index 99705927af..731e4b5432 100644 --- a/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h +++ b/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h @@ -61,7 +61,7 @@ class QWindowsThreadPoolRunner { Q_DISABLE_COPY(QWindowsThreadPoolRunner) -#ifndef QT_NO_THREAD +#if QT_CONFIG(thread) template <class RunnableFunction> // nested class implementing QRunnable to execute a function. class Runnable : public QRunnable { @@ -104,7 +104,7 @@ public: private: QMutex m_mutex; QWaitCondition m_condition; -#else // !QT_NO_THREAD +#else // QT_CONFIG(thread) public: QWindowsThreadPoolRunner() {} @@ -114,7 +114,7 @@ public: f(); return true; } -#endif // QT_NO_THREAD +#endif // QT_CONFIG(thread) }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.cpp index 98483216c0..16197c99b9 100644 --- a/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.cpp +++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.cpp @@ -126,7 +126,7 @@ AutomationControlType roleToControlType(QAccessible::Role role) {QAccessible::PropertyPage, AutomationControlType::AutomationControlType_Custom}, {QAccessible::Indicator, AutomationControlType::AutomationControlType_Custom}, {QAccessible::Graphic, AutomationControlType::AutomationControlType_Image}, - {QAccessible::StaticText, AutomationControlType::AutomationControlType_Edit}, + {QAccessible::StaticText, AutomationControlType::AutomationControlType_Text}, {QAccessible::EditableText, AutomationControlType::AutomationControlType_Edit}, {QAccessible::Button, AutomationControlType::AutomationControlType_Button}, {QAccessible::CheckBox, AutomationControlType::AutomationControlType_CheckBox}, diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp index a7641baea1..b751aaf8a3 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp @@ -163,9 +163,9 @@ bool QXcbGlxIntegration::handleXcbEvent(xcb_generic_event_t *event, uint respons // Unlock the display before calling the native event filter XUnlockDisplay(xdisplay); locked = false; - QByteArray genericEventFilterType = m_connection->nativeInterface()->genericEventFilterType(); + auto eventType = m_connection->nativeInterface()->nativeEventType(); long result = 0; - handled = dispatcher->filterNativeEvent(genericEventFilterType, &ev, &result); + handled = dispatcher->filterNativeEvent(eventType, &ev, &result); } #endif } diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index e73e6f3e61..c29eb29b7e 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -85,7 +85,8 @@ class QXcbBackingStore; class QXcbBackingStoreImage : public QXcbObject { public: - QXcbBackingStoreImage(QXcbScreen *screen, const QSize &size, uint depth, QImage::Format format); + QXcbBackingStoreImage(QXcbBackingStore *backingStore, const QSize &size); + QXcbBackingStoreImage(QXcbBackingStore *backingStore, const QSize &size, uint depth, QImage::Format format); ~QXcbBackingStoreImage() { destroy(true); } void resize(const QSize &size); @@ -109,10 +110,10 @@ public: xcb_shm_segment_info_t *shm_info = nullptr); private: - void createShmSegment(size_t segmentSize); - void destroyShmSegment(size_t segmentSize); + void init(const QSize &size, uint depth, QImage::Format format); - void create(const QSize &size, const xcb_format_t *fmt, QImage::Format format); + void createShmSegment(size_t segmentSize); + void destroyShmSegment(); void destroy(bool destroyShm); void ensureGC(xcb_drawable_t dst); @@ -120,10 +121,9 @@ private: void flushPixmap(const QRegion ®ion, bool fullRegion = false); void setClip(const QRegion ®ion); - xcb_window_t m_screen_root; - xcb_shm_segment_info_t m_shm_info; size_t m_segmentSize = 0; + QXcbBackingStore *m_backingStore = nullptr; xcb_image_t *m_xcb_image = nullptr; @@ -153,6 +153,9 @@ private: bool m_hasAlpha = false; bool m_clientSideScroll = false; + + const xcb_format_t *m_xcb_format = nullptr; + QImage::Format m_qimage_format = QImage::Format_Invalid; }; class QXcbGraphicsBuffer : public QPlatformGraphicsBuffer @@ -190,83 +193,108 @@ static inline size_t imageDataSize(const xcb_image_t *image) return static_cast<size_t>(image->stride) * image->height; } -QXcbBackingStoreImage::QXcbBackingStoreImage(QXcbScreen *screen, const QSize &size, uint depth, QImage::Format format) - : QXcbObject(screen->connection()) - , m_screen_root(screen->screen()->root) +QXcbBackingStoreImage::QXcbBackingStoreImage(QXcbBackingStore *backingStore, const QSize &size) + : QXcbObject(backingStore->connection()) + , m_backingStore(backingStore) { - const xcb_format_t *fmt = connection()->formatForDepth(depth); - Q_ASSERT(fmt); + auto window = static_cast<QXcbWindow *>(m_backingStore->window()->handle()); + init(size, window->depth(), window->imageFormat()); +} - memset(&m_shm_info, 0, sizeof m_shm_info); +QXcbBackingStoreImage::QXcbBackingStoreImage(QXcbBackingStore *backingStore, const QSize &size, + uint depth, QImage::Format format) + : QXcbObject(backingStore->connection()) + , m_backingStore(backingStore) +{ + init(size, depth, format); +} - m_hasAlpha = QImage::toPixelFormat(format).alphaUsage() == QPixelFormat::UsesAlpha; +void QXcbBackingStoreImage::init(const QSize &size, uint depth, QImage::Format format) +{ + m_xcb_format = connection()->formatForDepth(depth); + Q_ASSERT(m_xcb_format); + + m_qimage_format = format; + m_hasAlpha = QImage::toPixelFormat(m_qimage_format).alphaUsage() == QPixelFormat::UsesAlpha; if (!m_hasAlpha) - create(size, fmt, qt_maybeAlphaVersionWithSameDepth(format)); - else - create(size, fmt, format); + m_qimage_format = qt_maybeAlphaVersionWithSameDepth(m_qimage_format); + + memset(&m_shm_info, 0, sizeof m_shm_info); + + resize(size); } void QXcbBackingStoreImage::resize(const QSize &size) { - xcb_format_t fmt; - fmt.depth = m_xcb_image->depth; - fmt.bits_per_pixel = m_xcb_image->bpp; - fmt.scanline_pad = m_xcb_image->scanline_pad; - memset(fmt.pad0, 0, sizeof(fmt.pad0)); destroy(false); - create(size, &fmt, m_qimage.format()); -} -void QXcbBackingStoreImage::create(const QSize &size, const xcb_format_t *fmt, QImage::Format format) -{ + auto byteOrder = QSysInfo::ByteOrder == QSysInfo::BigEndian ? XCB_IMAGE_ORDER_MSB_FIRST + : XCB_IMAGE_ORDER_LSB_FIRST; m_xcb_image = xcb_image_create(size.width(), size.height(), XCB_IMAGE_FORMAT_Z_PIXMAP, - fmt->scanline_pad, - fmt->depth, fmt->bits_per_pixel, 0, - QSysInfo::ByteOrder == QSysInfo::BigEndian ? XCB_IMAGE_ORDER_MSB_FIRST : XCB_IMAGE_ORDER_LSB_FIRST, + m_xcb_format->scanline_pad, + m_xcb_format->depth, + m_xcb_format->bits_per_pixel, + 0, byteOrder, XCB_IMAGE_ORDER_MSB_FIRST, 0, ~0, 0); const size_t segmentSize = imageDataSize(m_xcb_image); - if (!segmentSize) - return; if (connection()->hasShm()) { - if (m_shm_info.shmaddr && (m_segmentSize < segmentSize || m_segmentSize / 2 >= segmentSize)) - destroyShmSegment(m_segmentSize); - if (!m_shm_info.shmaddr) { - qCDebug(lcQpaXcb) << "creating shared memory" << segmentSize << "for" - << size << "depth" << fmt->depth << "bits" << fmt->bits_per_pixel; - createShmSegment(segmentSize); + if (segmentSize == 0) { + if (m_segmentSize > 0) { + destroyShmSegment(); + qCDebug(lcQpaXcb) << "[" << m_backingStore->window() + << "] destroyed SHM segment due to resize to" << size; + } + } else { + // Destroy shared memory segment if it is double (or more) of what we actually + // need with new window size. Or if the new size is bigger than what we currently + // have allocated. + if (m_shm_info.shmaddr && (m_segmentSize < segmentSize || m_segmentSize / 2 >= segmentSize)) + destroyShmSegment(); + if (!m_shm_info.shmaddr) { + qCDebug(lcQpaXcb) << "[" << m_backingStore->window() + << "] creating shared memory" << segmentSize << "bytes for" + << size << "depth" << m_xcb_format->depth << "bits" + << m_xcb_format->bits_per_pixel; + createShmSegment(segmentSize); + } } } - m_xcb_image->data = m_shm_info.shmaddr ? m_shm_info.shmaddr : (uint8_t *)malloc(segmentSize); + if (segmentSize == 0) + return; - m_qimage = QImage( (uchar*) m_xcb_image->data, m_xcb_image->width, m_xcb_image->height, m_xcb_image->stride, format); + m_xcb_image->data = m_shm_info.shmaddr ? m_shm_info.shmaddr : (uint8_t *)malloc(segmentSize); + m_qimage = QImage(static_cast<uchar *>(m_xcb_image->data), m_xcb_image->width, + m_xcb_image->height, m_xcb_image->stride, m_qimage_format); m_graphics_buffer = new QXcbGraphicsBuffer(&m_qimage); m_xcb_pixmap = xcb_generate_id(xcb_connection()); + auto xcbScreen = static_cast<QXcbScreen *>(m_backingStore->window()->screen()->handle()); xcb_create_pixmap(xcb_connection(), m_xcb_image->depth, m_xcb_pixmap, - m_screen_root, + xcbScreen->root(), m_xcb_image->width, m_xcb_image->height); } void QXcbBackingStoreImage::destroy(bool destroyShm) { - if (m_xcb_image->data) { - if (m_shm_info.shmaddr) { - if (destroyShm) - destroyShmSegment(m_segmentSize); - } else { - free(m_xcb_image->data); + if (m_xcb_image) { + if (m_xcb_image->data) { + if (m_shm_info.shmaddr) { + if (destroyShm) + destroyShmSegment(); + } else { + free(m_xcb_image->data); + } } + xcb_image_destroy(m_xcb_image); } - xcb_image_destroy(m_xcb_image); - if (m_gc) { xcb_free_gc(xcb_connection(), m_gc); m_gc = 0; @@ -276,8 +304,12 @@ void QXcbBackingStoreImage::destroy(bool destroyShm) delete m_graphics_buffer; m_graphics_buffer = nullptr; - xcb_free_pixmap(xcb_connection(), m_xcb_pixmap); - m_xcb_pixmap = 0; + if (m_xcb_pixmap) { + xcb_free_pixmap(xcb_connection(), m_xcb_pixmap); + m_xcb_pixmap = 0; + } + + m_qimage = QImage(); } void QXcbBackingStoreImage::flushScrolledRegion(bool clientSideScroll) @@ -420,11 +452,8 @@ bool QXcbBackingStoreImage::createSystemVShmSegment(QXcbConnection *c, size_t se return true; } -void QXcbBackingStoreImage::destroyShmSegment(size_t segmentSize) +void QXcbBackingStoreImage::destroyShmSegment() { -#ifndef XCB_USE_SHM_FD - Q_UNUSED(segmentSize) -#endif auto cookie = xcb_shm_detach_checked(xcb_connection(), m_shm_info.shmseg); xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie); if (error) @@ -433,9 +462,9 @@ void QXcbBackingStoreImage::destroyShmSegment(size_t segmentSize) #ifdef XCB_USE_SHM_FD if (connection()->hasShmFd()) { - if (munmap(m_shm_info.shmaddr, segmentSize) == -1) { + if (munmap(m_shm_info.shmaddr, m_segmentSize) == -1) { qCWarning(lcQpaXcb, "munmap() failed (%d: %s) for %p with size %zu", - errno, strerror(errno), m_shm_info.shmaddr, segmentSize); + errno, strerror(errno), m_shm_info.shmaddr, m_segmentSize); } } else #endif @@ -894,7 +923,7 @@ void QXcbBackingStore::recreateImage(QXcbWindow *win, const QSize &size) if (m_image) m_image->resize(size); else - m_image = new QXcbBackingStoreImage(win->xcbScreen(), size, win->depth(), win->imageFormat()); + m_image = new QXcbBackingStoreImage(this, size); // Slow path for bgr888 VNC: Create an additional image, paint into that and // swap R and B while copying to m_image after each paint. @@ -1024,7 +1053,7 @@ void QXcbSystemTrayBackingStore::recreateImage(QXcbWindow *win, const QSize &siz if (m_image) m_image->resize(size); else - m_image = new QXcbBackingStoreImage(screen, size, 32, QImage::Format_ARGB32_Premultiplied); + m_image = new QXcbBackingStoreImage(this, size, 32, QImage::Format_ARGB32_Premultiplied); #endif // QT_CONFIG(xcb_render) } diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index 24eb13326c..84831cdbe5 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -49,10 +49,6 @@ #include <QtCore/QDebug> -#define class class_name // Workaround XCB-ICCCM 3.8 breakage -#include <xcb/xcb_icccm.h> -#undef class - QT_BEGIN_NAMESPACE #ifndef QT_NO_CLIPBOARD @@ -305,7 +301,7 @@ QXcbClipboard::~QXcbClipboard() connection()->sync(); // waiting until the clipboard manager fetches the content. - if (!waitForClipboardEvent(m_owner, XCB_SELECTION_NOTIFY, clipboard_timeout, true)) { + if (!waitForClipboardEvent(m_owner, XCB_SELECTION_NOTIFY, true)) { qWarning("QXcbClipboard: Unable to receive an event from the " "clipboard manager in a reasonable time"); } @@ -807,73 +803,44 @@ bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property, return ok; } - -namespace +xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t window, int type, bool checkManager) { - class Notify { - public: - Notify(xcb_window_t win, int t) - : window(win), type(t) {} - xcb_window_t window; - int type; - bool checkEvent(xcb_generic_event_t *event) const { - if (!event) - return false; - int t = event->response_type & 0x7f; - if (t != type) + QElapsedTimer timer; + timer.start(); + do { + auto e = connection()->checkEvent([window, type](xcb_generic_event_t *event, int eventType) { + if (eventType != type) return false; - if (t == XCB_PROPERTY_NOTIFY) { - xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event; - if (pn->window == window) + if (eventType == XCB_PROPERTY_NOTIFY) { + auto propertyNotify = reinterpret_cast<xcb_property_notify_event_t *>(event); + if (propertyNotify->window == window) return true; - } else if (t == XCB_SELECTION_NOTIFY) { - xcb_selection_notify_event_t *sn = (xcb_selection_notify_event_t *)event; - if (sn->requestor == window) + } else if (eventType == XCB_SELECTION_NOTIFY) { + auto selectionNotify = reinterpret_cast<xcb_selection_notify_event_t *>(event); + if (selectionNotify->requestor == window) return true; } return false; - } - }; - class ClipboardEvent { - public: - ClipboardEvent(QXcbConnection *c) - { clipboard = c->internAtom("CLIPBOARD"); } - xcb_atom_t clipboard; - bool checkEvent(xcb_generic_event_t *e) const { - if (!e) - return false; - int type = e->response_type & 0x7f; - if (type == XCB_SELECTION_REQUEST) { - xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)e; - return sr->selection == XCB_ATOM_PRIMARY || sr->selection == clipboard; - } else if (type == XCB_SELECTION_CLEAR) { - xcb_selection_clear_event_t *sc = (xcb_selection_clear_event_t *)e; - return sc->selection == XCB_ATOM_PRIMARY || sc->selection == clipboard; - } - return false; - } - }; -} - -xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t win, int type, int timeout, bool checkManager) -{ - QElapsedTimer timer; - timer.start(); - do { - Notify notify(win, type); - xcb_generic_event_t *e = connection()->checkEvent(notify); - if (e) + }); + if (e) // found the waited for event return e; if (checkManager) { auto reply = Q_XCB_REPLY(xcb_get_selection_owner, xcb_connection(), atom(QXcbAtom::CLIPBOARD_MANAGER)); if (!reply || reply->owner == XCB_NONE) - return 0; + return nullptr; } // process other clipboard events, since someone is probably requesting data from us - ClipboardEvent clipboard(connection()); - e = connection()->checkEvent(clipboard); + auto clipboardAtom = atom(QXcbAtom::CLIPBOARD); + e = connection()->checkEvent([clipboardAtom](xcb_generic_event_t *event, int type) { + xcb_atom_t selection = XCB_ATOM_NONE; + if (type == XCB_SELECTION_REQUEST) + selection = reinterpret_cast<xcb_selection_request_event_t *>(event)->selection; + else if (type == XCB_SELECTION_CLEAR) + selection = reinterpret_cast<xcb_selection_clear_event_t *>(event)->selection; + return selection == XCB_ATOM_PRIMARY || selection == clipboardAtom; + }); if (e) { connection()->handleXcbEvent(e); free(e); @@ -883,9 +850,9 @@ xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t win, int // sleep 50 ms, so we don't use up CPU cycles all the time. QThread::msleep(50); - } while (timer.elapsed() < timeout); + } while (timer.elapsed() < clipboard_timeout); - return 0; + return nullptr; } QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb_atom_t property, int nbytes, bool nullterm) @@ -907,7 +874,7 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb for (;;) { connection()->flush(); - xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_PROPERTY_NOTIFY, clipboard_timeout); + xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_PROPERTY_NOTIFY); if (!ge) break; xcb_property_notify_event_t *event = (xcb_property_notify_event_t *)ge; @@ -970,7 +937,7 @@ QByteArray QXcbClipboard::getSelection(xcb_atom_t selection, xcb_atom_t target, connection()->sync(); - xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_SELECTION_NOTIFY, clipboard_timeout); + xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_SELECTION_NOTIFY); bool no_selection = !ge || ((xcb_selection_notify_event_t *)ge)->property == XCB_NONE; free(ge); diff --git a/src/plugins/platforms/xcb/qxcbclipboard.h b/src/plugins/platforms/xcb/qxcbclipboard.h index bfeae13e10..abab42a613 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.h +++ b/src/plugins/platforms/xcb/qxcbclipboard.h @@ -89,7 +89,7 @@ public: QByteArray getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t t = 0); private: - xcb_generic_event_t *waitForClipboardEvent(xcb_window_t win, int type, int timeout, bool checkManager = false); + xcb_generic_event_t *waitForClipboardEvent(xcb_window_t window, int type, bool checkManager = false); xcb_atom_t sendTargetsSelection(QMimeData *d, xcb_window_t window, xcb_atom_t property); xcb_atom_t sendSelection(QMimeData *d, xcb_atom_t target, xcb_window_t window, xcb_atom_t property); diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 6fe1a121d8..48715e0812 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -761,22 +761,22 @@ QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id) #define HANDLE_PLATFORM_WINDOW_EVENT(event_t, windowMember, handler) \ { \ - event_t *e = reinterpret_cast<event_t *>(event); \ + auto e = reinterpret_cast<event_t *>(event); \ if (QXcbWindowEventListener *eventListener = windowEventListenerFromId(e->windowMember)) { \ - handled = eventListener->handleGenericEvent(event, &result); \ - if (!handled) \ - eventListener->handler(e); \ + if (eventListener->handleNativeEvent(event)) \ + return; \ + eventListener->handler(e); \ } \ } \ break; #define HANDLE_KEYBOARD_EVENT(event_t, handler) \ { \ - event_t *e = reinterpret_cast<event_t *>(event); \ + auto e = reinterpret_cast<event_t *>(event); \ if (QXcbWindowEventListener *eventListener = windowEventListenerFromId(e->event)) { \ - handled = eventListener->handleGenericEvent(event, &result); \ - if (!handled) \ - m_keyboard->handler(e); \ + if (eventListener->handleNativeEvent(event)) \ + return; \ + m_keyboard->handler(e); \ } \ } \ break; @@ -1002,7 +1002,7 @@ void QXcbConnection::handleXcbError(xcb_generic_error_t *error) { long result = 0; QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(); - if (dispatcher && dispatcher->filterNativeEvent(m_nativeInterface->genericEventFilterType(), error, &result)) + if (dispatcher && dispatcher->filterNativeEvent(m_nativeInterface->nativeEventType(), error, &result)) return; printXcbError("QXcbConnection: XCB error", error); @@ -1094,197 +1094,206 @@ namespace { void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) { - long result = 0; + if (Q_UNLIKELY(lcQpaEvents().isDebugEnabled())) + printXcbEvent(lcQpaEvents(), "Event", event); + + long result = 0; // Used only by MS Windows QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(); - bool handled = dispatcher && dispatcher->filterNativeEvent(m_nativeInterface->genericEventFilterType(), event, &result); + bool handledByNativeEventFilter = dispatcher && dispatcher->filterNativeEvent( + m_nativeInterface->nativeEventType(), event, &result); + if (handledByNativeEventFilter) + return; uint response_type = event->response_type & ~0x80; - if (!handled) { - switch (response_type) { - case XCB_EXPOSE: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent); - - case XCB_BUTTON_PRESS: { - xcb_button_press_event_t *ev = (xcb_button_press_event_t *)event; - m_keyboard->updateXKBStateFromCore(ev->state); - // the event explicitly contains the state of the three first buttons, - // the rest we need to manage ourselves - m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state); - setButtonState(translateMouseButton(ev->detail), true); - if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) - qCDebug(lcQpaXInputEvents, "legacy mouse press, button %d state %X", ev->detail, static_cast<unsigned int>(m_buttonState)); - HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent); - } - case XCB_BUTTON_RELEASE: { - xcb_button_release_event_t *ev = (xcb_button_release_event_t *)event; - m_keyboard->updateXKBStateFromCore(ev->state); - m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state); - setButtonState(translateMouseButton(ev->detail), false); - if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) - qCDebug(lcQpaXInputEvents, "legacy mouse release, button %d state %X", ev->detail, static_cast<unsigned int>(m_buttonState)); - HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent); - } - case XCB_MOTION_NOTIFY: { - xcb_motion_notify_event_t *ev = (xcb_motion_notify_event_t *)event; - m_keyboard->updateXKBStateFromCore(ev->state); - m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state); - if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) - qCDebug(lcQpaXInputEvents, "legacy mouse move %d,%d button %d state %X", ev->event_x, ev->event_y, - ev->detail, static_cast<unsigned int>(m_buttonState)); - HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent); - } - - case XCB_CONFIGURE_NOTIFY: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent); - case XCB_MAP_NOTIFY: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_map_notify_event_t, event, handleMapNotifyEvent); - case XCB_UNMAP_NOTIFY: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_unmap_notify_event_t, event, handleUnmapNotifyEvent); - case XCB_DESTROY_NOTIFY: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_destroy_notify_event_t, event, handleDestroyNotifyEvent); - case XCB_CLIENT_MESSAGE: - handleClientMessageEvent((xcb_client_message_event_t *)event); - break; - case XCB_ENTER_NOTIFY: -#if QT_CONFIG(xcb_xinput) - if (hasXInput2() && !xi2MouseEventsDisabled()) - break; + bool handled = true; + switch (response_type) { + case XCB_EXPOSE: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent); + case XCB_BUTTON_PRESS: { + auto ev = reinterpret_cast<xcb_button_press_event_t *>(event); + m_keyboard->updateXKBStateFromCore(ev->state); + // the event explicitly contains the state of the three first buttons, + // the rest we need to manage ourselves + m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state); + setButtonState(translateMouseButton(ev->detail), true); + if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) + qCDebug(lcQpaXInputEvents, "legacy mouse press, button %d state %X", + ev->detail, static_cast<unsigned int>(m_buttonState)); + HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent); + } + case XCB_BUTTON_RELEASE: { + auto ev = reinterpret_cast<xcb_button_release_event_t *>(event); + m_keyboard->updateXKBStateFromCore(ev->state); + m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state); + setButtonState(translateMouseButton(ev->detail), false); + if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) + qCDebug(lcQpaXInputEvents, "legacy mouse release, button %d state %X", + ev->detail, static_cast<unsigned int>(m_buttonState)); + HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent); + } + case XCB_MOTION_NOTIFY: { + auto ev = reinterpret_cast<xcb_motion_notify_event_t *>(event); + m_keyboard->updateXKBStateFromCore(ev->state); + m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state); + if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) + qCDebug(lcQpaXInputEvents, "legacy mouse move %d,%d button %d state %X", + ev->event_x, ev->event_y, ev->detail, static_cast<unsigned int>(m_buttonState)); + HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent); + } + case XCB_CONFIGURE_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent); + case XCB_MAP_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_map_notify_event_t, event, handleMapNotifyEvent); + case XCB_UNMAP_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_unmap_notify_event_t, event, handleUnmapNotifyEvent); + case XCB_DESTROY_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_destroy_notify_event_t, event, handleDestroyNotifyEvent); + case XCB_CLIENT_MESSAGE: { + auto clientMessage = reinterpret_cast<xcb_client_message_event_t *>(event); + if (clientMessage->format != 32) + return; +#if QT_CONFIG(draganddrop) + if (clientMessage->type == atom(QXcbAtom::XdndStatus)) + drag()->handleStatus(clientMessage); + else if (clientMessage->type == atom(QXcbAtom::XdndFinished)) + drag()->handleFinished(clientMessage); #endif - HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent); - case XCB_LEAVE_NOTIFY: + if (m_systemTrayTracker && clientMessage->type == atom(QXcbAtom::MANAGER)) + m_systemTrayTracker->notifyManagerClientMessageEvent(clientMessage); + HANDLE_PLATFORM_WINDOW_EVENT(xcb_client_message_event_t, window, handleClientMessageEvent); + } + case XCB_ENTER_NOTIFY: #if QT_CONFIG(xcb_xinput) - if (hasXInput2() && !xi2MouseEventsDisabled()) - break; + if (hasXInput2() && !xi2MouseEventsDisabled()) + break; #endif - m_keyboard->updateXKBStateFromCore(((xcb_leave_notify_event_t *)event)->state); - HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent); - case XCB_FOCUS_IN: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent); - case XCB_FOCUS_OUT: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent); - case XCB_KEY_PRESS: - { - xcb_key_press_event_t *kp = (xcb_key_press_event_t *)event; - m_keyboard->updateXKBStateFromCore(kp->state); - setTime(kp->time); - HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent); - } - case XCB_KEY_RELEASE: - m_keyboard->updateXKBStateFromCore(((xcb_key_release_event_t *)event)->state); - HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent); - case XCB_MAPPING_NOTIFY: - m_keyboard->updateKeymap(reinterpret_cast<xcb_mapping_notify_event_t *>(event)); + HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent); + case XCB_LEAVE_NOTIFY: +#if QT_CONFIG(xcb_xinput) + if (hasXInput2() && !xi2MouseEventsDisabled()) break; - case XCB_SELECTION_REQUEST: - { +#endif + m_keyboard->updateXKBStateFromCore(reinterpret_cast<xcb_leave_notify_event_t *>(event)->state); + HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent); + case XCB_FOCUS_IN: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent); + case XCB_FOCUS_OUT: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent); + case XCB_KEY_PRESS: + { + auto keyPress = reinterpret_cast<xcb_key_press_event_t *>(event); + m_keyboard->updateXKBStateFromCore(keyPress->state); + setTime(keyPress->time); + HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent); + } + case XCB_KEY_RELEASE: + m_keyboard->updateXKBStateFromCore(reinterpret_cast<xcb_key_release_event_t *>(event)->state); + HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent); + case XCB_MAPPING_NOTIFY: + m_keyboard->updateKeymap(reinterpret_cast<xcb_mapping_notify_event_t *>(event)); + break; + case XCB_SELECTION_REQUEST: + { #if QT_CONFIG(draganddrop) || QT_CONFIG(clipboard) - xcb_selection_request_event_t *sr = reinterpret_cast<xcb_selection_request_event_t *>(event); + auto selectionRequest = reinterpret_cast<xcb_selection_request_event_t *>(event); #endif #if QT_CONFIG(draganddrop) - if (sr->selection == atom(QXcbAtom::XdndSelection)) - m_drag->handleSelectionRequest(sr); - else + if (selectionRequest->selection == atom(QXcbAtom::XdndSelection)) + m_drag->handleSelectionRequest(selectionRequest); + else #endif - { + { #ifndef QT_NO_CLIPBOARD - m_clipboard->handleSelectionRequest(sr); + m_clipboard->handleSelectionRequest(selectionRequest); #endif - } - break; } - case XCB_SELECTION_CLEAR: - setTime((reinterpret_cast<xcb_selection_clear_event_t *>(event))->time); + break; + } + case XCB_SELECTION_CLEAR: + setTime((reinterpret_cast<xcb_selection_clear_event_t *>(event))->time); #ifndef QT_NO_CLIPBOARD - m_clipboard->handleSelectionClearRequest(reinterpret_cast<xcb_selection_clear_event_t *>(event)); + m_clipboard->handleSelectionClearRequest(reinterpret_cast<xcb_selection_clear_event_t *>(event)); #endif - handled = true; - break; - case XCB_SELECTION_NOTIFY: - setTime((reinterpret_cast<xcb_selection_notify_event_t *>(event))->time); - handled = false; - break; - case XCB_PROPERTY_NOTIFY: - { - xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event); - if (pn->atom == atom(QXcbAtom::_NET_WORKAREA)) { - QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(pn->window); - if (virtualDesktop) - virtualDesktop->updateWorkArea(); - } else { - HANDLE_PLATFORM_WINDOW_EVENT(xcb_property_notify_event_t, window, handlePropertyNotifyEvent); - } - break; + break; + case XCB_SELECTION_NOTIFY: + setTime((reinterpret_cast<xcb_selection_notify_event_t *>(event))->time); + break; + case XCB_PROPERTY_NOTIFY: + { + auto propertyNotify = reinterpret_cast<xcb_property_notify_event_t *>(event); + if (propertyNotify->atom == atom(QXcbAtom::_NET_WORKAREA)) { + QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(propertyNotify->window); + if (virtualDesktop) + virtualDesktop->updateWorkArea(); + } else { + HANDLE_PLATFORM_WINDOW_EVENT(xcb_property_notify_event_t, window, handlePropertyNotifyEvent); } + break; + } #if QT_CONFIG(xcb_xinput) - case XCB_GE_GENERIC: - // Here the windowEventListener is invoked from xi2HandleEvent() - if (hasXInput2() && isXIEvent(event, m_xiOpCode)) - xi2HandleEvent(reinterpret_cast<xcb_ge_event_t *>(event)); - break; + case XCB_GE_GENERIC: + // Here the windowEventListener is invoked from xi2HandleEvent() + if (hasXInput2() && isXIEvent(event, m_xiOpCode)) + xi2HandleEvent(reinterpret_cast<xcb_ge_event_t *>(event)); + break; #endif - default: - handled = false; - break; - } + default: + handled = false; // event type not recognized + break; } - if (!handled) { - if (has_xfixes && response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) { - xcb_xfixes_selection_notify_event_t *notify_event = reinterpret_cast<xcb_xfixes_selection_notify_event_t *>(event); - setTime(notify_event->timestamp); + if (handled) + return; + + handled = true; + if (has_xfixes && response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) { + auto notify_event = reinterpret_cast<xcb_xfixes_selection_notify_event_t *>(event); + setTime(notify_event->timestamp); #ifndef QT_NO_CLIPBOARD - m_clipboard->handleXFixesSelectionRequest(notify_event); + m_clipboard->handleXFixesSelectionRequest(notify_event); #endif - for (QXcbVirtualDesktop *virtualDesktop : qAsConst(m_virtualDesktops)) - virtualDesktop->handleXFixesSelectionNotify(notify_event); - - handled = true; - } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_NOTIFY) { - updateScreens(reinterpret_cast<xcb_randr_notify_event_t *>(event)); - handled = true; - } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) { - xcb_randr_screen_change_notify_event_t *change_event = reinterpret_cast<xcb_randr_screen_change_notify_event_t *>(event); - if (auto *virtualDesktop = virtualDesktopForRootWindow(change_event->root)) - virtualDesktop->handleScreenChange(change_event); - - handled = true; + for (QXcbVirtualDesktop *virtualDesktop : qAsConst(m_virtualDesktops)) + virtualDesktop->handleXFixesSelectionNotify(notify_event); + } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_NOTIFY) { + updateScreens(reinterpret_cast<xcb_randr_notify_event_t *>(event)); + } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) { + auto change_event = reinterpret_cast<xcb_randr_screen_change_notify_event_t *>(event); + if (auto virtualDesktop = virtualDesktopForRootWindow(change_event->root)) + virtualDesktop->handleScreenChange(change_event); #if QT_CONFIG(xkb) - } else if (response_type == xkb_first_event) { // https://bugs.freedesktop.org/show_bug.cgi?id=51295 - _xkb_event *xkb_event = reinterpret_cast<_xkb_event *>(event); - if (xkb_event->any.deviceID == m_keyboard->coreDeviceId()) { - switch (xkb_event->any.xkbType) { - // XkbNewKkdNotify and XkbMapNotify together capture all sorts of keymap - // updates (e.g. xmodmap, xkbcomp, setxkbmap), with minimal redundent recompilations. - case XCB_XKB_STATE_NOTIFY: - m_keyboard->updateXKBState(&xkb_event->state_notify); - handled = true; - break; - case XCB_XKB_MAP_NOTIFY: + } else if (response_type == xkb_first_event) { // https://bugs.freedesktop.org/show_bug.cgi?id=51295 + auto xkb_event = reinterpret_cast<_xkb_event *>(event); + if (xkb_event->any.deviceID == m_keyboard->coreDeviceId()) { + switch (xkb_event->any.xkbType) { + // XkbNewKkdNotify and XkbMapNotify together capture all sorts of keymap + // updates (e.g. xmodmap, xkbcomp, setxkbmap), with minimal redundent recompilations. + case XCB_XKB_STATE_NOTIFY: + m_keyboard->updateXKBState(&xkb_event->state_notify); + break; + case XCB_XKB_MAP_NOTIFY: + m_keyboard->updateKeymap(); + break; + case XCB_XKB_NEW_KEYBOARD_NOTIFY: { + xcb_xkb_new_keyboard_notify_event_t *ev = &xkb_event->new_keyboard_notify; + if (ev->changed & XCB_XKB_NKN_DETAIL_KEYCODES) m_keyboard->updateKeymap(); - handled = true; - break; - case XCB_XKB_NEW_KEYBOARD_NOTIFY: { - xcb_xkb_new_keyboard_notify_event_t *ev = &xkb_event->new_keyboard_notify; - if (ev->changed & XCB_XKB_NKN_DETAIL_KEYCODES) - m_keyboard->updateKeymap(); - break; - } - default: - break; + break; } + default: + break; } -#endif } +#endif + } else { + handled = false; // event type still not recognized } - if (!handled && m_glIntegration) - handled = m_glIntegration->handleXcbEvent(event, response_type); + if (handled) + return; -#if 0 - if (Q_UNLIKELY(lcQpaEvents().isDebugEnabled())) - printXcbEvent(lcQpaEvents(), handled ? "Handled" : "Unhandled", event); -#endif + if (m_glIntegration) + m_glIntegration->handleXcbEvent(event, response_type); } void QXcbConnection::addPeekFunc(PeekFunc f) @@ -1512,54 +1521,35 @@ void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom a, uint id) xcb_flush(xcb_connection()); } -namespace -{ - class PropertyNotifyEvent { - public: - PropertyNotifyEvent(xcb_window_t win, xcb_atom_t property) - : window(win), type(XCB_PROPERTY_NOTIFY), atom(property) {} - xcb_window_t window; - int type; - xcb_atom_t atom; - bool checkEvent(xcb_generic_event_t *event) const { - if (!event) - return false; - if ((event->response_type & ~0x80) != type) { - return false; - } else { - xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event); - if ((pn->window == window) && (pn->atom == atom)) - return true; - } - return false; - } - }; -} - xcb_timestamp_t QXcbConnection::getTimestamp() { // send a dummy event to myself to get the timestamp from X server. - xcb_window_t root_win = rootWindow(); - xcb_change_property(xcb_connection(), XCB_PROP_MODE_APPEND, root_win, atom(QXcbAtom::CLIP_TEMPORARY), - XCB_ATOM_INTEGER, 32, 0, NULL); + xcb_window_t window = rootWindow(); + xcb_atom_t dummyAtom = atom(QXcbAtom::CLIP_TEMPORARY); + xcb_change_property(xcb_connection(), XCB_PROP_MODE_APPEND, window, dummyAtom, + XCB_ATOM_INTEGER, 32, 0, nullptr); connection()->flush(); - PropertyNotifyEvent checker(root_win, atom(QXcbAtom::CLIP_TEMPORARY)); - xcb_generic_event_t *event = 0; + xcb_generic_event_t *event = nullptr; // lets keep this inside a loop to avoid a possible race condition, where // reader thread has not yet had the time to acquire the mutex in order // to add the new set of events to its event queue while (!event) { connection()->sync(); - event = checkEvent(checker); + event = checkEvent([window, dummyAtom](xcb_generic_event_t *event, int type) { + if (type != XCB_PROPERTY_NOTIFY) + return false; + auto propertyNotify = reinterpret_cast<xcb_property_notify_event_t *>(event); + return propertyNotify->window == window && propertyNotify->atom == dummyAtom; + }); } xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event); xcb_timestamp_t timestamp = pn->time; free(event); - xcb_delete_property(xcb_connection(), root_win, atom(QXcbAtom::CLIP_TEMPORARY)); + xcb_delete_property(xcb_connection(), window, dummyAtom); return timestamp; } @@ -1808,28 +1798,6 @@ void QXcbConnection::processXcbEvents() xcb_flush(xcb_connection()); } -void QXcbConnection::handleClientMessageEvent(const xcb_client_message_event_t *event) -{ - if (event->format != 32) - return; - -#if QT_CONFIG(draganddrop) - if (event->type == atom(QXcbAtom::XdndStatus)) { - drag()->handleStatus(event); - } else if (event->type == atom(QXcbAtom::XdndFinished)) { - drag()->handleFinished(event); - } -#endif - if (m_systemTrayTracker && event->type == atom(QXcbAtom::MANAGER)) - m_systemTrayTracker->notifyManagerClientMessageEvent(event); - - QXcbWindow *window = platformWindowFromId(event->window); - if (!window) - return; - - window->handleClientMessageEvent(event); -} - static const char * xcb_atomnames = { // window-manager <-> client protocols "WM_PROTOCOLS\0" @@ -2024,6 +1992,10 @@ static const char * xcb_atomnames = { "_COMPIZ_DECOR_DELETE_PIXMAP\0" "_COMPIZ_TOOLKIT_ACTION\0" "_GTK_LOAD_ICONTHEMES\0" + "AT_SPI_BUS\0" + "EDID\0" + "EDID_DATA\0" + "XFree86_DDC_EDID1_RAWDATA\0" // \0\0 terminates loop. }; diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index c88100e580..b0c36e61b0 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -295,6 +295,12 @@ namespace QXcbAtom { _COMPIZ_TOOLKIT_ACTION, _GTK_LOAD_ICONTHEMES, + AT_SPI_BUS, + + EDID, + EDID_DATA, + XFree86_DDC_EDID1_RAWDATA, + NAtoms }; } @@ -335,7 +341,7 @@ class QXcbWindowEventListener { public: virtual ~QXcbWindowEventListener() {} - virtual bool handleGenericEvent(xcb_generic_event_t *, long *) { return false; } + virtual bool handleNativeEvent(xcb_generic_event_t *) { return false; } virtual void handleExposeEvent(const xcb_expose_event_t *) {} virtual void handleClientMessageEvent(const xcb_client_message_event_t *) {} @@ -447,8 +453,8 @@ public: QXcbWindowEventListener *windowEventListenerFromId(xcb_window_t id); QXcbWindow *platformWindowFromId(xcb_window_t id); - template<typename T> - inline xcb_generic_event_t *checkEvent(T &checker); + template<typename Functor> + inline xcb_generic_event_t *checkEvent(Functor &&filter, bool removeFromQueue = true); typedef bool (*PeekFunc)(QXcbConnection *, xcb_generic_event_t *); void addPeekFunc(PeekFunc f); @@ -560,7 +566,6 @@ private: void initializeXShape(); void initializeXKB(); void initializeXSync(); - void handleClientMessageEvent(const xcb_client_message_event_t *event); QXcbScreen* findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc) const; QXcbScreen* findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output) const; QXcbVirtualDesktop* virtualDesktopForRootWindow(xcb_window_t rootWindow) const; @@ -741,21 +746,22 @@ Q_DECLARE_TYPEINFO(QXcbConnection::TabletData, Q_MOVABLE_TYPE); #endif #endif -template<typename T> -xcb_generic_event_t *QXcbConnection::checkEvent(T &checker) +template<typename Functor> +xcb_generic_event_t *QXcbConnection::checkEvent(Functor &&filter, bool removeFromQueue) { QXcbEventArray *eventqueue = m_reader->lock(); for (int i = 0; i < eventqueue->size(); ++i) { xcb_generic_event_t *event = eventqueue->at(i); - if (checker.checkEvent(event)) { - (*eventqueue)[i] = 0; + if (event && filter(event, event->response_type & ~0x80)) { + if (removeFromQueue) + (*eventqueue)[i] = nullptr; m_reader->unlock(); return event; } } m_reader->unlock(); - return 0; + return nullptr; } class QXcbConnectionGrabber diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index a327d8dea7..a3befc7384 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -581,8 +581,7 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) } if (eventListener) { - long result = 0; - if (eventListener->handleGenericEvent(reinterpret_cast<xcb_generic_event_t *>(event), &result)) + if (eventListener->handleNativeEvent(reinterpret_cast<xcb_generic_event_t *>(event))) return; } diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index 0d72da0701..2b8e507f30 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -781,12 +781,11 @@ namespace public: ClientMessageScanner(xcb_atom_t a) : atom(a) {} xcb_atom_t atom; - bool checkEvent(xcb_generic_event_t *event) const { - if (!event) + bool operator() (xcb_generic_event_t *event, int type) const { + if (type != XCB_CLIENT_MESSAGE) return false; - if ((event->response_type & 0x7f) != XCB_CLIENT_MESSAGE) - return false; - return ((xcb_client_message_event_t *)event)->type == atom; + auto clientMessage = reinterpret_cast<xcb_client_message_event_t *>(event); + return clientMessage->type == atom; } }; } @@ -794,12 +793,11 @@ namespace void QXcbDrag::handlePosition(QPlatformWindow * w, const xcb_client_message_event_t *event) { xcb_client_message_event_t *lastEvent = const_cast<xcb_client_message_event_t *>(event); - xcb_generic_event_t *nextEvent; ClientMessageScanner scanner(atom(QXcbAtom::XdndPosition)); - while ((nextEvent = connection()->checkEvent(scanner))) { + while (auto nextEvent = connection()->checkEvent(scanner)) { if (lastEvent != event) free(lastEvent); - lastEvent = (xcb_client_message_event_t *)nextEvent; + lastEvent = reinterpret_cast<xcb_client_message_event_t *>(nextEvent); } handle_xdnd_position(w, lastEvent); diff --git a/src/plugins/platforms/xcb/qxcbimage.cpp b/src/plugins/platforms/xcb/qxcbimage.cpp index e18a08755b..44c7d22344 100644 --- a/src/plugins/platforms/xcb/qxcbimage.cpp +++ b/src/plugins/platforms/xcb/qxcbimage.cpp @@ -69,7 +69,7 @@ QImage::Format imageFormatForMasks(int depth, int bits_per_pixel, int red_mask, if (red_mask == 0xff && blue_mask == 0xff0000) return QImage::Format_RGBA8888_Premultiplied; #else - if (red_mask == 0xff000000 && blue_mask == 0xff00) + if (unsigned(red_mask) == unsigned(0xff000000) && blue_mask == 0xff00) return QImage::Format_RGBA8888_Premultiplied; #endif if (red_mask == 0x3ff && blue_mask == 0x3ff00000) @@ -90,7 +90,7 @@ QImage::Format imageFormatForMasks(int depth, int bits_per_pixel, int red_mask, if (red_mask == 0xff && blue_mask == 0xff0000) return QImage::Format_RGBX8888; #else - if (red_mask == 0xff000000 && blue_mask == 0xff00) + if (unsigned(red_mask) == unsigned(0xff000000) && blue_mask == 0xff00) return QImage::Format_RGBX8888; #endif break; diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 5a2dac4a5a..20c169fc53 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -161,6 +161,13 @@ static constexpr const auto KeyTbl = qMakeArray( Xkb2Qt<XKB_KEY_KP_Decimal, Qt::Key_Period>, Xkb2Qt<XKB_KEY_KP_Divide, Qt::Key_Slash>, + // special non-XF86 function keys + + Xkb2Qt<XKB_KEY_Undo, Qt::Key_Undo>, + Xkb2Qt<XKB_KEY_Redo, Qt::Key_Redo>, + Xkb2Qt<XKB_KEY_Find, Qt::Key_Find>, + Xkb2Qt<XKB_KEY_Cancel, Qt::Key_Cancel>, + // International input method support keys // International & multi-key character composition @@ -1472,64 +1479,6 @@ void QXcbKeyboard::resolveMaskConflicts() } } -class KeyChecker -{ -public: - KeyChecker(xcb_window_t window, xcb_keycode_t code, xcb_timestamp_t time, quint16 state) - : m_window(window) - , m_code(code) - , m_time(time) - , m_state(state) - , m_error(false) - , m_release(true) - { - } - - bool checkEvent(xcb_generic_event_t *ev) - { - if (m_error || !ev) - return false; - - int type = ev->response_type & ~0x80; - if (type != XCB_KEY_PRESS && type != XCB_KEY_RELEASE) - return false; - - xcb_key_press_event_t *event = (xcb_key_press_event_t *)ev; - - if (event->event != m_window || event->detail != m_code || event->state != m_state) { - m_error = true; - return false; - } - - if (type == XCB_KEY_PRESS) { - m_error = !m_release || event->time - m_time > 10; - return !m_error; - } - - if (m_release) { - m_error = true; - return false; - } - - m_release = true; - m_time = event->time; - - return false; - } - - bool release() const { return m_release; } - xcb_timestamp_t time() const { return m_time; } - -private: - xcb_window_t m_window; - xcb_keycode_t m_code; - xcb_timestamp_t m_time; - quint16 m_state; - - bool m_error; - bool m_release; -}; - void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, xcb_keycode_t code, quint16 state, xcb_timestamp_t time, bool fromSendEvent) { @@ -1543,7 +1492,6 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, if (type == QEvent::KeyPress) targetWindow->updateNetWmUserTime(time); - ScopedXKBState sendEventState; if (fromSendEvent) { // Have a temporary keyboard state filled in from state @@ -1561,7 +1509,7 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, struct xkb_state *xkbState = fromSendEvent ? sendEventState.get() : m_xkbState.get(); xcb_keysym_t sym = xkb_state_key_get_one_sym(xkbState, code); - QString string = lookupString(xkbState, code); + QString text = lookupString(xkbState, code); Qt::KeyboardModifiers modifiers = translateModifiers(state); if (sym >= XKB_KEY_KP_Space && sym <= XKB_KEY_KP_9) @@ -1586,55 +1534,42 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, int qtcode = keysymToQtKey(latinKeysym != XKB_KEY_NoSymbol ? latinKeysym : sym, modifiers, xkbState, code); - bool isAutoRepeat = false; if (type == QEvent::KeyPress) { - if (m_autorepeat_code == code) { - isAutoRepeat = true; - m_autorepeat_code = 0; - } + if (m_isAutoRepeat && m_autoRepeatCode != code) + // Some other key was pressed while we are auto-repeating on a different key. + m_isAutoRepeat = false; } else { - // look ahead for auto-repeat - KeyChecker checker(source->xcb_window(), code, time, state); - xcb_generic_event_t *event = connection()->checkEvent(checker); - if (event) { - isAutoRepeat = true; - free(event); - } - m_autorepeat_code = isAutoRepeat ? code : 0; + m_isAutoRepeat = false; + // Look at the next event in the queue to see if we are auto-repeating. + connection()->checkEvent([this, time, code](xcb_generic_event_t *event, int type) { + if (type == XCB_KEY_PRESS) { + auto keyPress = reinterpret_cast<xcb_key_press_event_t *>(event); + m_isAutoRepeat = keyPress->time == time && keyPress->detail == code; + if (m_isAutoRepeat) + m_autoRepeatCode = code; + } + return true; + }, false /* removeFromQueue */); } bool filtered = false; - QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext(); - if (inputContext) { - QKeyEvent event(type, qtcode, modifiers, code, sym, state, string, isAutoRepeat, string.length()); + if (auto inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext()) { + QKeyEvent event(type, qtcode, modifiers, code, sym, state, text, m_isAutoRepeat, text.size()); event.setTimestamp(time); filtered = inputContext->filterEvent(&event); } - QWindow *window = targetWindow->window(); if (!filtered) { + QWindow *window = targetWindow->window(); #ifndef QT_NO_CONTEXTMENU if (type == QEvent::KeyPress && qtcode == Qt::Key_Menu) { const QPoint globalPos = window->screen()->handle()->cursor()->pos(); const QPoint pos = window->mapFromGlobal(globalPos); QWindowSystemInterface::handleContextMenuEvent(window, false, pos, globalPos, modifiers); } -#endif // QT_NO_CONTEXTMENU +#endif QWindowSystemInterface::handleExtendedKeyEvent(window, time, type, qtcode, modifiers, - code, sym, state, string, isAutoRepeat); - } - - if (isAutoRepeat && type == QEvent::KeyRelease) { - // since we removed it from the event queue using checkEvent we need to send the key press here - filtered = false; - if (inputContext) { - QKeyEvent event(QEvent::KeyPress, qtcode, modifiers, code, sym, state, string, isAutoRepeat, string.length()); - event.setTimestamp(time); - filtered = inputContext->filterEvent(&event); - } - if (!filtered) - QWindowSystemInterface::handleExtendedKeyEvent(window, time, QEvent::KeyPress, qtcode, modifiers, - code, sym, state, string, isAutoRepeat); + code, sym, state, text, m_isAutoRepeat); } } diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h index ab926eab84..95915fb2e6 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.h +++ b/src/plugins/platforms/xcb/qxcbkeyboard.h @@ -109,7 +109,8 @@ protected: private: bool m_config = false; - xcb_keycode_t m_autorepeat_code = 0; + bool m_isAutoRepeat = false; + xcb_keycode_t m_autoRepeatCode = 0; struct _mod_masks { uint alt; diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 26b9fcc15a..98bedea48a 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -92,8 +92,7 @@ static int resourceType(const QByteArray &key) return int(result - names); } -QXcbNativeInterface::QXcbNativeInterface() : - m_genericEventFilterType(QByteArrayLiteral("xcb_generic_event_t")) +QXcbNativeInterface::QXcbNativeInterface() { } @@ -409,7 +408,7 @@ void *QXcbNativeInterface::atspiBus() QXcbIntegration *integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration()); QXcbConnection *defaultConnection = integration->defaultConnection(); if (defaultConnection) { - xcb_atom_t atspiBusAtom = defaultConnection->internAtom("AT_SPI_BUS"); + auto atspiBusAtom = defaultConnection->atom(QXcbAtom::AT_SPI_BUS); auto reply = Q_XCB_REPLY(xcb_get_property, defaultConnection->xcb_connection(), false, defaultConnection->rootWindow(), atspiBusAtom, XCB_ATOM_STRING, 0, 128); diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index 5ec3827afd..d1f2747bea 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -98,7 +98,7 @@ public: QFunctionPointer platformFunction(const QByteArray &function) const override; - inline const QByteArray &genericEventFilterType() const { return m_genericEventFilterType; } + inline const QByteArray &nativeEventType() const { return m_nativeEventType; } void *displayForWindow(QWindow *window); void *connectionForWindow(QWindow *window); @@ -131,7 +131,7 @@ signals: void systemTrayWindowChanged(QScreen *screen); private: - const QByteArray m_genericEventFilterType; + const QByteArray m_nativeEventType = QByteArrayLiteral("xcb_generic_event_t"); xcb_atom_t m_sysTraySelectionAtom = XCB_ATOM_NONE; diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index b398768bbc..8c0ce8dd7e 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -906,16 +906,12 @@ QByteArray QXcbScreen::getEdid() const return result; // Try a bunch of atoms - xcb_atom_t atom = connection()->internAtom("EDID"); - result = getOutputProperty(atom); - if (result.isEmpty()) { - atom = connection()->internAtom("EDID_DATA"); - result = getOutputProperty(atom); - } - if (result.isEmpty()) { - atom = connection()->internAtom("XFree86_DDC_EDID1_RAWDATA"); - result = getOutputProperty(atom); - } + result = getOutputProperty(atom(QXcbAtom::EDID)); + if (result.isEmpty()) + result = getOutputProperty(atom(QXcbAtom::EDID_DATA)); + if (result.isEmpty()) + result = getOutputProperty(atom(QXcbAtom::XFree86_DDC_EDID1_RAWDATA)); + return result; } diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index d42d95f890..52c87ee8a4 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -275,11 +275,7 @@ QXcbWindow::QXcbWindow(QWindow *window) setConnection(xcbScreen()->connection()); } -#ifdef Q_COMPILER_CLASS_ENUM enum : quint32 { -#else -enum { -#endif baseEventMask = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_FOCUS_CHANGE, @@ -441,8 +437,6 @@ void QXcbWindow::create() connection()->addWindowEventListener(m_window, this); - xcb_change_window_attributes(xcb_connection(), m_window, mask, values); - propagateSizeHints(); xcb_atom_t properties[5]; @@ -738,13 +732,6 @@ void QXcbWindow::setVisible(bool visible) hide(); } -static inline bool testShowWithoutActivating(const QWindow *window) -{ - // QWidget-attribute Qt::WA_ShowWithoutActivating. - const QVariant showWithoutActivating = window->property("_q_showWithoutActivating"); - return showWithoutActivating.isValid() && showWithoutActivating.toBool(); -} - void QXcbWindow::show() { if (window()->isTopLevel()) { @@ -792,7 +779,9 @@ void QXcbWindow::show() updateNetWmStateBeforeMap(); } - if (testShowWithoutActivating(window())) + // QWidget-attribute Qt::WA_ShowWithoutActivating. + const auto showWithoutActivating = window()->property("_q_showWithoutActivating"); + if (showWithoutActivating.isValid() && showWithoutActivating.toBool()) updateNetWmUserTime(0); else if (connection()->time() != XCB_TIME_CURRENT_TIME) updateNetWmUserTime(connection()->time()); @@ -1813,67 +1802,34 @@ bool QXcbWindow::requestSystemTrayWindowDock() return true; } -class ExposeCompressor -{ -public: - ExposeCompressor(xcb_window_t window, QRegion *region) - : m_window(window) - , m_region(region) - , m_pending(true) - { - } - - bool checkEvent(xcb_generic_event_t *event) - { - if (!event) - return false; - if ((event->response_type & ~0x80) != XCB_EXPOSE) - return false; - xcb_expose_event_t *expose = (xcb_expose_event_t *)event; - if (expose->window != m_window) - return false; - if (expose->count == 0) - m_pending = false; - *m_region |= QRect(expose->x, expose->y, expose->width, expose->height); - return true; - } - - bool pending() const - { - return m_pending; - } - -private: - xcb_window_t m_window; - QRegion *m_region; - bool m_pending; -}; - -bool QXcbWindow::compressExposeEvent(QRegion &exposeRegion) -{ - ExposeCompressor compressor(m_window, &exposeRegion); - xcb_generic_event_t *filter = 0; - do { - filter = connection()->checkEvent(compressor); - free(filter); - } while (filter); - return compressor.pending(); -} - -bool QXcbWindow::handleGenericEvent(xcb_generic_event_t *event, long *result) +bool QXcbWindow::handleNativeEvent(xcb_generic_event_t *event) { - return QWindowSystemInterface::handleNativeEvent(window(), - connection()->nativeInterface()->genericEventFilterType(), - event, - result); + auto eventType = connection()->nativeInterface()->nativeEventType(); + long result = 0; // Used only by MS Windows + return QWindowSystemInterface::handleNativeEvent(window(), eventType, event, &result); } void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event) { QRect rect(event->x, event->y, event->width, event->height); - m_exposeRegion |= rect; - bool pending = compressExposeEvent(m_exposeRegion); + + bool pending = true; + xcb_generic_event_t *e = nullptr; + do { // compress expose events + e = connection()->checkEvent([this, &pending](xcb_generic_event_t *event, int type) { + if (type != XCB_EXPOSE) + return false; + auto expose = reinterpret_cast<xcb_expose_event_t *>(event); + if (expose->window != m_window) + return false; + if (expose->count == 0) + pending = false; + m_exposeRegion |= QRect(expose->x, expose->y, expose->width, expose->height); + return true; + }); + free(e); + } while (e); // if count is non-zero there are more expose events pending if (event->count == 0 || !pending) { @@ -2166,24 +2122,6 @@ static bool ignoreEnterEvent(quint8 mode, quint8 detail, QXcbConnection *conn = || detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL); } -class EnterEventChecker -{ -public: - bool checkEvent(xcb_generic_event_t *event) - { - if (!event) - return false; - if ((event->response_type & ~0x80) != XCB_ENTER_NOTIFY) - return false; - - xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *)event; - if (ignoreEnterEvent(enter->mode, enter->detail)) - return false; - - return true; - } -}; - void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, int root_y, quint8 mode, quint8 detail, xcb_timestamp_t timestamp) { @@ -2210,9 +2148,17 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y, if (ignoreLeaveEvent(mode, detail, connection()) || connection()->mousePressWindow()) return; - EnterEventChecker checker; - xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *)connection()->checkEvent(checker); - QXcbWindow *enterWindow = enter ? connection()->platformWindowFromId(enter->event) : 0; + // check if enter event is buffered + auto event = connection()->checkEvent([](xcb_generic_event_t *event, int type) { + if (type != XCB_ENTER_NOTIFY) + return false; + auto enter = reinterpret_cast<xcb_enter_notify_event_t *>(event); + if (ignoreEnterEvent(enter->mode, enter->detail)) + return false; + return true; + }); + auto enter = reinterpret_cast<xcb_enter_notify_event_t *>(event); + QXcbWindow *enterWindow = enter ? connection()->platformWindowFromId(enter->event) : nullptr; if (enterWindow) { QPoint local(enter->event_x, enter->event_y); diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 047ee2eae9..99e8e40725 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -121,7 +121,7 @@ public: QImage::Format imageFormat() const { return m_imageFormat; } bool imageNeedsRgbSwap() const { return m_imageRgbSwap; } - bool handleGenericEvent(xcb_generic_event_t *event, long *result) override; + bool handleNativeEvent(xcb_generic_event_t *event) override; void handleExposeEvent(const xcb_expose_event_t *event) override; void handleClientMessageEvent(const xcb_client_message_event_t *event) override; @@ -217,8 +217,6 @@ protected: void doFocusIn(); void doFocusOut(); - bool compressExposeEvent(QRegion &exposeRegion); - void handleButtonPressEvent(int event_x, int event_y, int root_x, int root_y, int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, QEvent::Type type, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); |