From 836a2fb8872217d2a04a209b89f2ac2ff86a4b99 Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Fri, 28 Sep 2018 17:37:58 +0200 Subject: [macOS] Fix position of sheets when using unifiedTitleAndToolBarOnMac MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modal sheets are supposed to appear below the toolbar if a toolbar exists, or below the title bar if a toolbar doesn't exist. In the unified title and toolbar mode, sheets should to appear directly below the toolbar, if the toolbar is positioned at the top of the window. Code-wise we achieve that by calling setUnifiedTitleAndToolBarOnMac on a QMainWindow, which results in adjusting the top content border of the NSWindow via [NSWindow setContentBorderThickness:forEdge], which Cocoa uses to position a modal sheet (the sheet top edge is aligned with the top edge of the content view + the Y border thickness value). The issue is that because NSWindow.titlebarAppearsTransparent is set to YES, for sheet presentation purposes, Cocoa considers the content view to begin at the position of the top left corner of the frame (where the title bar is), and thus sheets appear somewhere in the middle of the unified toolbar. To fix that we need to account for the title bar height in the border thickness value. Compute the title bar height from the window frame height - window content view height, and add it to the top border thickness value. Amends 8ac9addd946637401e4685c6e91d1a3cd5b2d768 Change-Id: Icf85c513035cc3710b438e60eb14dc04c5bbaced Fixes: QTBUG-65451 Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qcocoawindow.mm | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 9b10c8b053..00c3f7c22c 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1714,6 +1714,14 @@ void QCocoaWindow::applyContentBorderThickness(NSWindow *window) [window setStyleMask:[window styleMask] | NSTexturedBackgroundWindowMask]; window.titlebarAppearsTransparent = YES; + // Setting titlebarAppearsTransparent to YES means that the border thickness has to account + // for the title bar height as well, otherwise sheets will not be presented at the correct + // position, which should be (title bar height + top content border size). + const NSRect frameRect = window.frame; + const NSRect contentRect = [window contentRectForFrameRect:frameRect]; + const CGFloat titlebarHeight = frameRect.size.height - contentRect.size.height; + effectiveTopContentBorderThickness += titlebarHeight; + [window setContentBorderThickness:effectiveTopContentBorderThickness forEdge:NSMaxYEdge]; [window setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge]; -- cgit v1.2.3 From 091a386eaf91ad8932332a8aefc2df793de59f6c Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Tue, 9 Oct 2018 11:01:37 +0200 Subject: Use native visual ID when creating GBM surfaces for KMS According to the Khronos documentation, gbm_surface_create() will give a BAD_MATCH error if the format does not match the EGL_NATIVE_VISUAL_ID. Newer drivers have started to enforce this. Change-Id: I61360b0f52965ad8057e7de8f824ffca64fea904 Reviewed-by: Laszlo Agocs Reviewed-by: Dominik Holland --- .../eglfs_kms/qeglfskmsgbmscreen.cpp | 24 ++++++++++++++++++---- .../eglfs_kms/qeglfskmsgbmscreen.h | 2 +- .../eglfs_kms/qeglfskmsgbmwindow.cpp | 2 +- 3 files changed, 22 insertions(+), 6 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp index 4742143121..1b52bdf3ec 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp @@ -148,16 +148,32 @@ QPlatformCursor *QEglFSKmsGbmScreen::cursor() const } } -gbm_surface *QEglFSKmsGbmScreen::createSurface() +gbm_surface *QEglFSKmsGbmScreen::createSurface(EGLConfig eglConfig) { if (!m_gbm_surface) { - uint32_t gbmFormat = drmFormatToGbmFormat(m_output.drm_format); - qCDebug(qLcEglfsKmsDebug, "Creating gbm_surface for screen %s with format 0x%x", qPrintable(name()), gbmFormat); - m_gbm_surface = gbm_surface_create(static_cast(device())->gbmDevice(), + qCDebug(qLcEglfsKmsDebug, "Creating gbm_surface for screen %s", qPrintable(name())); + + const auto gbmDevice = static_cast(device())->gbmDevice(); + EGLint native_format = -1; + EGLBoolean success = eglGetConfigAttrib(display(), eglConfig, EGL_NATIVE_VISUAL_ID, &native_format); + qCDebug(qLcEglfsKmsDebug) << "Got native format" << hex << native_format << dec << "from eglGetConfigAttrib() with return code" << bool(success); + + if (success) + m_gbm_surface = gbm_surface_create(gbmDevice, + rawGeometry().width(), + rawGeometry().height(), + native_format, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + + if (!m_gbm_surface) { // fallback for older drivers + uint32_t gbmFormat = drmFormatToGbmFormat(m_output.drm_format); + qCDebug(qLcEglfsKmsDebug, "Could not create surface with EGL_NATIVE_VISUAL_ID, falling back to format %x", gbmFormat); + m_gbm_surface = gbm_surface_create(gbmDevice, rawGeometry().width(), rawGeometry().height(), gbmFormat, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + } } return m_gbm_surface; // not owned, gets destroyed in QEglFSKmsGbmIntegration::destroyNativeWindow() via QEglFSKmsGbmWindow::invalidateSurface() } diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h index f5a2122723..b94f44b7b1 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h @@ -59,7 +59,7 @@ public: QPlatformCursor *cursor() const override; - gbm_surface *createSurface(); + gbm_surface *createSurface(EGLConfig eglConfig); void resetSurface(); void initCloning(QPlatformScreen *screenThisScreenClones, diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.cpp index 110a592dec..65a7c4f38a 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.cpp @@ -53,7 +53,7 @@ void QEglFSKmsGbmWindow::resetSurface() m_config = QEglFSDeviceIntegration::chooseConfig(display, platformFormat); m_format = q_glFormatFromConfig(display, m_config, platformFormat); // One fullscreen window per screen -> the native window is simply the gbm_surface the screen created. - m_window = reinterpret_cast(gbmScreen->createSurface()); + m_window = reinterpret_cast(gbmScreen->createSurface(m_config)); PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC createPlatformWindowSurface = nullptr; const char *extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); -- cgit v1.2.3 From dc5f9d0c3101f95185d3c562d001e0af18f46a0b Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Tue, 2 Oct 2018 15:05:32 +0200 Subject: Only use a translucent background if there is support for alpha Change-Id: Ia8d9e543fac4b6e790fa38cf04c5a782d72d72df Reviewed-by: Eirik Aavitsland Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp index 8851ea59e5..ed482e5dae 100644 --- a/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp +++ b/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp @@ -62,8 +62,10 @@ QXcbNativeBackingStore::QXcbNativeBackingStore(QWindow *window) : QPlatformBackingStore(window) , m_translucentBackground(false) { - if (QXcbWindow *w = static_cast(window->handle())) - m_translucentBackground = w->connection()->hasXRender() && QImage::toPixelFormat(w->imageFormat()).alphaSize() > 0; + if (QXcbWindow *w = static_cast(window->handle())) { + m_translucentBackground = w->connection()->hasXRender() && + QImage::toPixelFormat(w->imageFormat()).alphaUsage() == QPixelFormat::UsesAlpha; + } } QXcbNativeBackingStore::~QXcbNativeBackingStore() -- cgit v1.2.3 From 3eebadc1734463afa469dcd08eab8c5d2557dec6 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Fri, 28 Sep 2018 11:40:10 +0200 Subject: Modernize the "mimetype" feature Change-Id: I9b67c2cbc0891a38ece18d521c86fbc7344dce7a Reviewed-by: Edward Welbourne Reviewed-by: Oswald Buddenhagen --- src/plugins/platforms/cocoa/qcocoaprintdevice.h | 2 ++ src/plugins/platforms/cocoa/qcocoaprintdevice.mm | 4 ++++ src/plugins/platformthemes/platformthemes.pro | 2 +- src/plugins/printsupport/cups/qppdprintdevice.cpp | 2 +- src/plugins/printsupport/cups/qppdprintdevice.h | 2 +- 5 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaprintdevice.h b/src/plugins/platforms/cocoa/qcocoaprintdevice.h index 20b27f3286..d267343b0e 100644 --- a/src/plugins/platforms/cocoa/qcocoaprintdevice.h +++ b/src/plugins/platforms/cocoa/qcocoaprintdevice.h @@ -98,7 +98,9 @@ protected: void loadOutputBins() const override; void loadDuplexModes() const override; void loadColorModes() const override; +#if QT_CONFIG(mimetype) void loadMimeTypes() const override; +#endif private: QPageSize createPageSize(const PMPaper &paper) const; diff --git a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm index bfe6cd09b6..0c54a3b771 100644 --- a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm +++ b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm @@ -39,7 +39,9 @@ #include "qcocoaprintdevice.h" +#if QT_CONFIG(mimetype) #include +#endif #include QT_BEGIN_NAMESPACE @@ -417,6 +419,7 @@ QPrint::ColorMode QCocoaPrintDevice::defaultColorMode() const return QPrint::GrayScale; } +#if QT_CONFIG(mimetype) void QCocoaPrintDevice::loadMimeTypes() const { // TODO Check how settings affect returned list @@ -438,6 +441,7 @@ void QCocoaPrintDevice::loadMimeTypes() const } m_haveMimeTypes = true; } +#endif // mimetype bool QCocoaPrintDevice::openPpdFile() { diff --git a/src/plugins/platformthemes/platformthemes.pro b/src/plugins/platformthemes/platformthemes.pro index 17b1d91c6a..02ed3406e7 100644 --- a/src/plugins/platformthemes/platformthemes.pro +++ b/src/plugins/platformthemes/platformthemes.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs QT_FOR_CONFIG += widgets-private -qtConfig(dbus):qtConfig(regularexpression): SUBDIRS += flatpak +qtConfig(dbus):qtConfig(regularexpression):qtConfig(mimetype): SUBDIRS += flatpak qtHaveModule(widgets):qtConfig(gtk3): SUBDIRS += gtk3 diff --git a/src/plugins/printsupport/cups/qppdprintdevice.cpp b/src/plugins/printsupport/cups/qppdprintdevice.cpp index 340b1a1ff4..f0a8105d21 100644 --- a/src/plugins/printsupport/cups/qppdprintdevice.cpp +++ b/src/plugins/printsupport/cups/qppdprintdevice.cpp @@ -463,7 +463,7 @@ bool QPpdPrintDevice::isFeatureAvailable(QPrintDevice::PrintDevicePropertyKey ke return QPlatformPrintDevice::isFeatureAvailable(key, params); } -#ifndef QT_NO_MIMETYPE +#if QT_CONFIG(mimetype) void QPpdPrintDevice::loadMimeTypes() const { // TODO No CUPS api? Need to manually load CUPS mime.types file? diff --git a/src/plugins/printsupport/cups/qppdprintdevice.h b/src/plugins/printsupport/cups/qppdprintdevice.h index 9867083bd7..596f9aa3f5 100644 --- a/src/plugins/printsupport/cups/qppdprintdevice.h +++ b/src/plugins/printsupport/cups/qppdprintdevice.h @@ -100,7 +100,7 @@ protected: void loadOutputBins() const override; void loadDuplexModes() const override; void loadColorModes() const override; -#ifndef QT_NO_MIMETYPE +#if QT_CONFIG(mimetype) void loadMimeTypes() const override; #endif -- cgit v1.2.3 From 656e89f875ad2008ca16cc673b687a22daa294c9 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 9 Oct 2018 07:44:46 +0200 Subject: qnsview_keys - fix a typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit that resulted in 'Cmd' reported as combo of Qt::Meta/Qt::Control and Qt::KeypadModifier. Task-number: QTBUG-71006 Change-Id: I3dddc56f4d404a1ceefb21d57ac120b6273456ec Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qnsview_keys.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qnsview_keys.mm b/src/plugins/platforms/cocoa/qnsview_keys.mm index 28db532ddc..ad751279bb 100644 --- a/src/plugins/platforms/cocoa/qnsview_keys.mm +++ b/src/plugins/platforms/cocoa/qnsview_keys.mm @@ -53,7 +53,7 @@ qtMods |= Qt::AltModifier; if (modifierFlags & NSEventModifierFlagCommand) qtMods |= dontSwapCtrlAndMeta ? Qt::MetaModifier : Qt::ControlModifier; - if (modifierFlags & NSEventModifierFlagCommand) + if (modifierFlags & NSEventModifierFlagNumericPad) qtMods |= Qt::KeypadModifier; return qtMods; } -- cgit v1.2.3 From f5204067a02bd0c13500ea6e66bb9211701f96db Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Thu, 11 Oct 2018 14:36:31 +0200 Subject: qt_mac_createRolePalettes: fix the highlight color for ItemViewPalette role MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While this requires from us calling a deprecated method, a (non-deprecated) method we were using gives a wrong color which is too bright/saturated. Task-number: QTBUG-70676 Change-Id: Icebeb53e351caa646c533595ca1a886e5eb6b5b8 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoasystemsettings.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm index c1711e7cd4..672b0e4f25 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm @@ -202,7 +202,7 @@ QHash qt_mac_createRolePalettes() qt_mac_toQBrush([NSColor unemphasizedSelectedTextColor])); } else { baseColors = [NSColor controlAlternatingRowBackgroundColors]; - activeHighlightColor = [NSColor selectedControlColor]; + activeHighlightColor = [NSColor alternateSelectedControlColor]; pal.setBrush(QPalette::Inactive, QPalette::HighlightedText, pal.brush(QPalette::Active, QPalette::Text)); } -- cgit v1.2.3 From a880780ff962dc31be24b508f811c1a2fd0b0f36 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Sun, 14 Oct 2018 19:46:20 +0200 Subject: Revert "XCB: Do not create instance of QPlatformIntegration for invalid displays" This reverts commit 67cc8fea106c35c7ca75bf476667d07b3bbf3257. I forgot about this patch and now it makes rebasing the local changes too time-consuming. Besides, 67cc8fea10 broke a build for -no-xcb-xlib. I will restore this patch, with adaptations to the new QXcb*Connection hierarchy. Task-number: QTBUG-68859 Change-Id: I938f32b5da22ce18f95d761f9b34e77fff923e24 Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbconnection.cpp | 58 +++++++-------------------- src/plugins/platforms/xcb/qxcbconnection.h | 17 +++----- src/plugins/platforms/xcb/qxcbintegration.cpp | 26 ++++++++---- src/plugins/platforms/xcb/qxcbintegration.h | 1 - src/plugins/platforms/xcb/qxcbmain.cpp | 12 ++---- 5 files changed, 41 insertions(+), 73 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 4e24c970b4..09b920a09e 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -525,59 +525,31 @@ void QXcbConnection::initializeScreens() } } -QXcbConnection *QXcbConnection::create(QXcbNativeInterface *nativeInterface, bool canGrabServer, - xcb_visualid_t defaultVisualId, - const char *displayNameIn) -{ - const QByteArray displayName = displayNameIn ? QByteArray(displayNameIn) : qgetenv("DISPLAY"); - int primaryScreenNumber = 0; - void *xlibDisplay = nullptr; - xcb_connection_t *connection = nullptr; +QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, xcb_visualid_t defaultVisualId, const char *displayName) + : m_canGrabServer(canGrabServer) + , m_defaultVisualId(defaultVisualId) + , m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY")) + , m_nativeInterface(nativeInterface) +{ #if QT_CONFIG(xcb_xlib) - Display *dpy = XOpenDisplay(displayName.constData()); + Display *dpy = XOpenDisplay(m_displayName.constData()); if (dpy) { - primaryScreenNumber = DefaultScreen(dpy); - connection = XGetXCBConnection(dpy); + m_primaryScreenNumber = DefaultScreen(dpy); + m_connection = XGetXCBConnection(dpy); XSetEventQueueOwner(dpy, XCBOwnsEventQueue); XSetErrorHandler(nullErrorHandler); XSetIOErrorHandler(ioErrorHandler); - xlibDisplay = dpy; + m_xlib_display = dpy; } #else - connection = xcb_connect(displayName.constData(), &primaryScreenNumber); + m_connection = xcb_connect(m_displayName.constData(), &m_primaryScreenNumber); #endif // QT_CONFIG(xcb_xlib) - if (Q_UNLIKELY(connection == nullptr)) { - qWarning("QXcbConnection: Could not connect to display \"%s\"", displayName.constData()); - return nullptr; - } - if (Q_UNLIKELY(xcb_connection_has_error(connection))) { -#if QT_CONFIG(xcb_xlib) - XCloseDisplay(static_cast(xlibDisplay)); -#else - xcb_disconnect(connection); -#endif - qWarning("QXcbConnection: Errors occurred connecting to display \"%s\"", displayName.constData()); - return nullptr; - } - return new QXcbConnection(connection, primaryScreenNumber, nativeInterface, - canGrabServer, defaultVisualId, displayName, xlibDisplay); -} + if (Q_UNLIKELY(!m_connection || xcb_connection_has_error(m_connection))) { + qCWarning(lcQpaScreen, "QXcbConnection: Could not connect to display %s", m_displayName.constData()); + return; + } -QXcbConnection::QXcbConnection(xcb_connection_t *c, int primaryScreenNumber, - QXcbNativeInterface *nativeInterface, bool canGrabServer, - xcb_visualid_t defaultVisualId, const QByteArray &displayName, - void *xlibDisplay) - : m_connection(c) - , m_canGrabServer(canGrabServer) - , m_defaultVisualId(defaultVisualId) - , m_primaryScreenNumber(primaryScreenNumber) - , m_displayName(displayName) - , m_nativeInterface(nativeInterface) -#if QT_CONFIG(xcb_xlib) - , m_xlib_display(xlibDisplay) -#endif -{ m_reader = new QXcbEventReader(this); m_reader->start(); diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index db45031cf4..a97a1f1002 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -380,16 +380,9 @@ class Q_XCB_EXPORT QXcbConnection : public QObject { Q_OBJECT public: - explicit QXcbConnection(xcb_connection_t *c, int primaryScreenNumber, - QXcbNativeInterface *nativeInterface, bool canGrabServer, - xcb_visualid_t defaultVisualId, const QByteArray &displayName, - void *xlibDisplay = nullptr); - + QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, xcb_visualid_t defaultVisualId, const char *displayName = 0); ~QXcbConnection(); - static QXcbConnection *create(QXcbNativeInterface *nativeInterface, bool canGrabServer, - xcb_visualid_t defaultVisualId, const char *displayName = nullptr); - QXcbConnection *connection() const { return const_cast(this); } bool isConnected() const; @@ -648,21 +641,21 @@ private: static bool xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value); #endif - xcb_connection_t *const m_connection; + xcb_connection_t *m_connection = nullptr; const xcb_setup_t *m_setup = nullptr; const bool m_canGrabServer; const xcb_visualid_t m_defaultVisualId; QList m_virtualDesktops; QList m_screens; - const int m_primaryScreenNumber; + int m_primaryScreenNumber = 0; xcb_atom_t m_allAtoms[QXcbAtom::NAtoms]; xcb_timestamp_t m_time = XCB_CURRENT_TIME; xcb_timestamp_t m_netWmUserTime = XCB_CURRENT_TIME; - const QByteArray m_displayName; + QByteArray m_displayName; QXcbKeyboard *m_keyboard = nullptr; #ifndef QT_NO_CLIPBOARD @@ -675,7 +668,7 @@ private: QXcbNativeInterface *m_nativeInterface = nullptr; #if QT_CONFIG(xcb_xlib) - void *const m_xlib_display; + void *m_xlib_display = nullptr; #endif QXcbEventReader *m_reader = nullptr; diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index db8dc09025..db8f816a86 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -192,15 +192,25 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char const int numParameters = parameters.size(); m_connections.reserve(1 + numParameters / 2); + auto conn = new QXcbConnection(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, displayName); + if (conn->isConnected()) + m_connections << conn; + else + delete conn; + + for (int i = 0; i < numParameters - 1; i += 2) { + qCDebug(lcQpaScreen) << "connecting to additional display: " << parameters.at(i) << parameters.at(i+1); + QString display = parameters.at(i) + QLatin1Char(':') + parameters.at(i+1); + conn = new QXcbConnection(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, display.toLatin1().constData()); + if (conn->isConnected()) + m_connections << conn; + else + delete conn; + } - if (QXcbConnection *defaultConnection = QXcbConnection::create(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, displayName)) { - m_connections.append(defaultConnection); - for (int i = 0; i < numParameters - 1; i += 2) { - qCDebug(lcQpaScreen) << "connecting to additional display: " << parameters.at(i) << parameters.at(i+1); - QString display = parameters.at(i) + QLatin1Char(':') + parameters.at(i+1); - if (QXcbConnection *connection = QXcbConnection::create(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, display.toLatin1().constData())) - m_connections.append(connection); - } + if (m_connections.isEmpty()) { + qCritical("Could not connect to any X display."); + exit(1); } m_fontDatabase.reset(new QGenericUnixFontDatabase()); diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index a2de22d53d..69e49cb7f6 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -103,7 +103,6 @@ public: QPlatformTheme *createPlatformTheme(const QString &name) const override; QVariant styleHint(StyleHint hint) const override; - bool hasDefaultConnection() const { return !m_connections.isEmpty(); } QXcbConnection *defaultConnection() const { return m_connections.first(); } QByteArray wmClass() const; diff --git a/src/plugins/platforms/xcb/qxcbmain.cpp b/src/plugins/platforms/xcb/qxcbmain.cpp index 539d033ca9..f8cb9a9269 100644 --- a/src/plugins/platforms/xcb/qxcbmain.cpp +++ b/src/plugins/platforms/xcb/qxcbmain.cpp @@ -52,16 +52,10 @@ public: QPlatformIntegration* QXcbIntegrationPlugin::create(const QString& system, const QStringList& parameters, int &argc, char **argv) { - if (!system.compare(QLatin1String("xcb"), Qt::CaseInsensitive)) { - QXcbIntegration *xcbIntegration = new QXcbIntegration(parameters, argc, argv); - if (!xcbIntegration->hasDefaultConnection()) { - delete xcbIntegration; - return nullptr; - } - return xcbIntegration; - } + if (!system.compare(QLatin1String("xcb"), Qt::CaseInsensitive)) + return new QXcbIntegration(parameters, argc, argv); - return nullptr; + return 0; } QT_END_NAMESPACE -- cgit v1.2.3 From 243c3044b647357ca6df79ac1497ae43de957d31 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Fri, 31 Aug 2018 13:03:47 +0200 Subject: xcb: lock-free event processing For details how this works refer to the documentation in the patch. The follow-up patches will switch to calling processXcbEvents() on every event loop iteration. With the existing code that would mean frequent locking of shared data (event queue). Acquiring a lock is fast, but lock contention isn't. To avoid potential problems, reimplement xcb event processing to be lock-free. Besides theoretical performance benefits, this definitally improves code readability in qxcbconnection.cpp. Thanks to Mikhail Svetkin for questioning the design of the existing code. Done-with: Mikhail Svetkin Change-Id: I935f2b6ca802580f5c80205aef7b2f9afc172d26 Reviewed-by: Mikhail Svetkin Reviewed-by: Thiago Macieira --- src/plugins/platforms/xcb/qxcbclipboard.cpp | 14 +- src/plugins/platforms/xcb/qxcbconnection.cpp | 290 +++---------------- src/plugins/platforms/xcb/qxcbconnection.h | 85 +----- src/plugins/platforms/xcb/qxcbdrag.cpp | 4 +- src/plugins/platforms/xcb/qxcbeventqueue.cpp | 332 ++++++++++++++++++++++ src/plugins/platforms/xcb/qxcbeventqueue.h | 160 +++++++++++ src/plugins/platforms/xcb/qxcbintegration.cpp | 3 +- src/plugins/platforms/xcb/qxcbkeyboard.cpp | 5 +- src/plugins/platforms/xcb/qxcbnativeinterface.cpp | 10 +- src/plugins/platforms/xcb/qxcbnativeinterface.h | 4 +- src/plugins/platforms/xcb/qxcbwindow.cpp | 35 ++- src/plugins/platforms/xcb/xcb_qpa_lib.pro | 6 +- 12 files changed, 589 insertions(+), 359 deletions(-) create mode 100644 src/plugins/platforms/xcb/qxcbeventqueue.cpp create mode 100644 src/plugins/platforms/xcb/qxcbeventqueue.h (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index 84831cdbe5..3fd14a659e 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -807,18 +807,18 @@ xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t window, i { QElapsedTimer timer; timer.start(); + QXcbEventQueue *queue = connection()->eventQueue(); do { - auto e = connection()->checkEvent([window, type](xcb_generic_event_t *event, int eventType) { + auto e = queue->peek([window, type](xcb_generic_event_t *event, int eventType) { if (eventType != type) return false; if (eventType == XCB_PROPERTY_NOTIFY) { auto propertyNotify = reinterpret_cast(event); - if (propertyNotify->window == window) - return true; - } else if (eventType == XCB_SELECTION_NOTIFY) { + return propertyNotify->window == window; + } + if (eventType == XCB_SELECTION_NOTIFY) { auto selectionNotify = reinterpret_cast(event); - if (selectionNotify->requestor == window) - return true; + return selectionNotify->requestor == window; } return false; }); @@ -833,7 +833,7 @@ xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t window, i // process other clipboard events, since someone is probably requesting data from us auto clipboardAtom = atom(QXcbAtom::CLIPBOARD); - e = connection()->checkEvent([clipboardAtom](xcb_generic_event_t *event, int type) { + e = queue->peek([clipboardAtom](xcb_generic_event_t *event, int type) { xcb_atom_t selection = XCB_ATOM_NONE; if (type == XCB_SELECTION_REQUEST) selection = reinterpret_cast(event)->selection; diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 09b920a09e..4d3f62791c 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -57,6 +57,7 @@ #include "qxcbglintegration.h" #include "qxcbcursor.h" #include "qxcbbackingstore.h" +#include "qxcbeventqueue.h" #include #include @@ -97,6 +98,7 @@ Q_LOGGING_CATEGORY(lcQpaXInputDevices, "qt.qpa.input.devices") Q_LOGGING_CATEGORY(lcQpaXInputEvents, "qt.qpa.input.events") Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen") Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events") +Q_LOGGING_CATEGORY(lcQpaEventReader, "qt.qpa.events.reader") Q_LOGGING_CATEGORY(lcQpaXcb, "qt.qpa.xcb") // for general (uncategorized) XCB logging Q_LOGGING_CATEGORY(lcQpaPeeker, "qt.qpa.peeker") Q_LOGGING_CATEGORY(lcQpaKeyboard, "qt.qpa.xkeyboard") @@ -550,8 +552,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra return; } - m_reader = new QXcbEventReader(this); - m_reader->start(); + m_eventQueue = new QXcbEventQueue(this); xcb_extension_t *extensions[] = { &xcb_shm_id, &xcb_xfixes_id, &xcb_randr_id, &xcb_shape_id, &xcb_sync_id, @@ -618,12 +619,8 @@ QXcbConnection::~QXcbConnection() #if QT_CONFIG(draganddrop) delete m_drag; #endif - if (m_reader && m_reader->isRunning()) { - sendConnectionEvent(QXcbAtom::_QT_CLOSE_CONNECTION); - m_reader->wait(); - } - - delete m_reader; + if (m_eventQueue) + delete m_eventQueue; QXcbIntegration *integration = QXcbIntegration::instance(); // Delete screens in reverse order to avoid crash in case of multiple screens @@ -1226,151 +1223,6 @@ void QXcbConnection::addPeekFunc(PeekFunc f) m_peekFuncs.append(f); } -qint32 QXcbConnection::generatePeekerId() -{ - qint32 peekerId = m_peekerIdSource++; - m_peekerToCachedIndex.insert(peekerId, 0); - return peekerId; -} - -bool QXcbConnection::removePeekerId(qint32 peekerId) -{ - if (!m_peekerToCachedIndex.contains(peekerId)) { - qCWarning(lcQpaXcb, "failed to remove unknown peeker id: %d", peekerId); - return false; - } - m_peekerToCachedIndex.remove(peekerId); - if (m_peekerToCachedIndex.isEmpty()) { - m_peekerIdSource = 0; // Once the hash becomes empty, we can start reusing IDs - m_peekerIndexCacheDirty = false; - } - return true; -} - -bool QXcbConnection::peekEventQueue(PeekerCallback peeker, void *peekerData, - PeekOptions option, qint32 peekerId) -{ - bool peekerIdProvided = peekerId != -1; - if (peekerIdProvided && !m_peekerToCachedIndex.contains(peekerId)) { - qCWarning(lcQpaXcb, "failed to find index for unknown peeker id: %d", peekerId); - return false; - } - - bool peekFromCachedIndex = option.testFlag(PeekOption::PeekFromCachedIndex); - if (peekFromCachedIndex && !peekerIdProvided) { - qCWarning(lcQpaXcb, "PeekOption::PeekFromCachedIndex requires peeker id"); - return false; - } - - if (peekerIdProvided && m_peekerIndexCacheDirty) { - // When the main event loop has flushed the buffered XCB events into the window - // system event queue, the cached indices are not valid anymore and need reset. - auto it = m_peekerToCachedIndex.begin(); - while (it != m_peekerToCachedIndex.constEnd()) { - (*it) = 0; - ++it; - } - m_peekerIndexCacheDirty = false; - } - - qint32 peekerIndex = peekFromCachedIndex ? m_peekerToCachedIndex.value(peekerId) : 0; - qint32 startingIndex = peekerIndex; - bool result = false; - m_mainEventLoopFlushedQueue = false; - - QXcbEventArray *eventqueue = m_reader->lock(); - - if (Q_UNLIKELY(lcQpaPeeker().isDebugEnabled())) { - qCDebug(lcQpaPeeker, "[%d] peeker index: %d | mode: %s | queue size: %d", peekerId, - peekerIndex, peekFromCachedIndex ? "cache" : "start", eventqueue->size()); - } - while (peekerIndex < eventqueue->size() && !result && !m_mainEventLoopFlushedQueue) { - xcb_generic_event_t *event = eventqueue->at(peekerIndex++); - if (!event) - continue; - if (Q_UNLIKELY(lcQpaPeeker().isDebugEnabled())) { - QString debug = QString((QLatin1String("[%1] peeking at index: %2"))) - .arg(peekerId).arg(peekerIndex - 1); - printXcbEvent(lcQpaPeeker(), debug.toLatin1(), event); - } - // A peeker may call QCoreApplication::processEvents(), which has two implications: - // 1) We need to make the lock available for QXcbConnection::processXcbEvents(), - // otherwise we will deadlock; - // 2) QXcbConnection::processXcbEvents() will flush the queue we are currently - // looping through; - m_reader->unlock(); - result = peeker(event, peekerData); - m_reader->lock(); - } - - m_reader->unlock(); - - if (peekerIdProvided && peekerIndex != startingIndex && !m_mainEventLoopFlushedQueue) { - auto it = m_peekerToCachedIndex.find(peekerId); - // Make sure that a peeker callback did not remove the peeker id - if (it != m_peekerToCachedIndex.constEnd()) - (*it) = peekerIndex; - } - - return result; -} - -QXcbEventReader::QXcbEventReader(QXcbConnection *connection) - : m_connection(connection) -{ -} - -void QXcbEventReader::start() -{ - connect(this, &QXcbEventReader::eventPending, m_connection, &QXcbConnection::processXcbEvents, Qt::QueuedConnection); - connect(this, &QXcbEventReader::finished, m_connection, &QXcbConnection::processXcbEvents); - QThread::start(); -} - -void QXcbEventReader::registerEventDispatcher(QAbstractEventDispatcher *dispatcher) -{ - // Flush the xcb connection before the event dispatcher is going to block. - connect(dispatcher, &QAbstractEventDispatcher::aboutToBlock, m_connection, &QXcbConnection::flush); -} - -void QXcbEventReader::run() -{ - xcb_generic_event_t *event; - while (m_connection && (event = xcb_wait_for_event(m_connection->xcb_connection()))) { - m_mutex.lock(); - addEvent(event); - while (m_connection && (event = xcb_poll_for_queued_event(m_connection->xcb_connection()))) - addEvent(event); - m_mutex.unlock(); - emit eventPending(); - } - - m_mutex.lock(); - for (int i = 0; i < m_events.size(); ++i) - free(m_events.at(i)); - m_events.clear(); - m_mutex.unlock(); -} - -void QXcbEventReader::addEvent(xcb_generic_event_t *event) -{ - if ((event->response_type & ~0x80) == XCB_CLIENT_MESSAGE - && (reinterpret_cast(event))->type == m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION)) - m_connection = 0; - m_events << event; -} - -QXcbEventArray *QXcbEventReader::lock() -{ - m_mutex.lock(); - return &m_events; -} - -void QXcbEventReader::unlock() -{ - m_mutex.unlock(); -} - void QXcbConnection::setFocusWindow(QWindow *w) { m_focusWindow = w ? static_cast(w->handle()) : nullptr; @@ -1397,31 +1249,6 @@ void QXcbConnection::ungrabServer() xcb_ungrab_server(m_connection); } -void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom a, uint id) -{ - xcb_client_message_event_t event; - memset(&event, 0, sizeof(event)); - - const xcb_window_t eventListener = xcb_generate_id(m_connection); - xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup); - xcb_screen_t *screen = it.data; - xcb_create_window(m_connection, XCB_COPY_FROM_PARENT, - eventListener, screen->root, - 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY, - screen->root_visual, 0, 0); - - event.response_type = XCB_CLIENT_MESSAGE; - event.format = 32; - event.sequence = 0; - event.window = eventListener; - event.type = atom(a); - event.data.data32[0] = id; - - xcb_send_event(xcb_connection(), false, eventListener, XCB_EVENT_MASK_NO_EVENT, reinterpret_cast(&event)); - xcb_destroy_window(m_connection, eventListener); - xcb_flush(xcb_connection()); -} - xcb_timestamp_t QXcbConnection::getTimestamp() { // send a dummy event to myself to get the timestamp from X server. @@ -1433,12 +1260,10 @@ xcb_timestamp_t QXcbConnection::getTimestamp() connection()->flush(); 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([window, dummyAtom](xcb_generic_event_t *event, int type) { + event = eventQueue()->peek([window, dummyAtom](xcb_generic_event_t *event, int type) { if (type != XCB_PROPERTY_NOTIFY) return false; auto propertyNotify = reinterpret_cast(event); @@ -1546,10 +1371,6 @@ static inline bool isXIType(xcb_generic_event_t *event, int opCode, uint16_t typ return e->event_type == type; } #endif -static inline bool isValid(xcb_generic_event_t *event) -{ - return event && (event->response_type & ~0x80); -} /*! \internal @@ -1563,22 +1384,18 @@ static inline bool isValid(xcb_generic_event_t *event) 3) Or add public API to Qt for disabling event compression QTBUG-44964 */ -bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex, QXcbEventArray *eventqueue) const +bool QXcbConnection::compressEvent(xcb_generic_event_t *event) const { uint responseType = event->response_type & ~0x80; - int nextIndex = currentIndex + 1; if (responseType == XCB_MOTION_NOTIFY) { // compress XCB_MOTION_NOTIFY notify events - for (int j = nextIndex; j < eventqueue->size(); ++j) { - xcb_generic_event_t *next = eventqueue->at(j); - if (!isValid(next)) - continue; - if (next->response_type == XCB_MOTION_NOTIFY) - return true; - } - return false; + return m_eventQueue->peek(QXcbEventQueue::PeekRetainMatch, + [](xcb_generic_event_t *, int type) { + return type == XCB_MOTION_NOTIFY; + }); } + #if QT_CONFIG(xcb_xinput) // compress XI_* events if (responseType == XCB_GE_GENERIC) { @@ -1588,50 +1405,44 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex, // compress XI_Motion if (isXIType(event, m_xiOpCode, XCB_INPUT_MOTION)) { #if QT_CONFIG(tabletevent) - auto *xdev = reinterpret_cast(event); + auto xdev = reinterpret_cast(event); if (!QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents) && const_cast(this)->tabletDataForDevice(xdev->sourceid)) return false; #endif // QT_CONFIG(tabletevent) - for (int j = nextIndex; j < eventqueue->size(); ++j) { - xcb_generic_event_t *next = eventqueue->at(j); - if (!isValid(next)) - continue; - if (isXIType(next, m_xiOpCode, XCB_INPUT_MOTION)) - return true; - } - return false; + return m_eventQueue->peek(QXcbEventQueue::PeekRetainMatch, + [this](xcb_generic_event_t *next, int) { + return isXIType(next, m_xiOpCode, XCB_INPUT_MOTION); + }); } + // compress XI_TouchUpdate for the same touch point id if (isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE)) { - auto *touchUpdateEvent = reinterpret_cast(event); + auto touchUpdateEvent = reinterpret_cast(event); uint32_t id = touchUpdateEvent->detail % INT_MAX; - for (int j = nextIndex; j < eventqueue->size(); ++j) { - xcb_generic_event_t *next = eventqueue->at(j); - if (!isValid(next)) - continue; - if (isXIType(next, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE)) { - auto *touchUpdateNextEvent = reinterpret_cast(next); - if (id == touchUpdateNextEvent->detail % INT_MAX) - return true; - } - } - return false; + return m_eventQueue->peek(QXcbEventQueue::PeekRetainMatch, + [this, &id](xcb_generic_event_t *next, int) { + if (!isXIType(next, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE)) + return false; + auto touchUpdateNextEvent = reinterpret_cast(next); + return id == touchUpdateNextEvent->detail % INT_MAX; + }); } + return false; } #endif + if (responseType == XCB_CONFIGURE_NOTIFY) { // compress multiple configure notify events for the same window - for (int j = nextIndex; j < eventqueue->size(); ++j) { - xcb_generic_event_t *next = eventqueue->at(j); - if (isValid(next) && next->response_type == XCB_CONFIGURE_NOTIFY - && reinterpret_cast(next)->event == reinterpret_cast(event)->event) - { - return true; - } - } - return false; + return m_eventQueue->peek(QXcbEventQueue::PeekRetainMatch, + [event](xcb_generic_event_t *next, int type) { + if (type != XCB_CONFIGURE_NOTIFY) + return false; + auto currentEvent = reinterpret_cast(event); + auto nextEvent = reinterpret_cast(next); + return currentEvent->event == nextEvent->event; + }); } return false; @@ -1645,22 +1456,17 @@ void QXcbConnection::processXcbEvents() exit(1); } - QXcbEventArray *eventqueue = m_reader->lock(); + m_eventQueue->flushBufferedEvents(); - for (int i = 0; i < eventqueue->size(); ++i) { - xcb_generic_event_t *event = eventqueue->at(i); - if (!event) - continue; + while (xcb_generic_event_t *event = m_eventQueue->takeFirst()) { QScopedPointer eventGuard(event); - (*eventqueue)[i] = 0; if (!(event->response_type & ~0x80)) { handleXcbError(reinterpret_cast(event)); continue; } - if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)) && - compressEvent(event, i, eventqueue)) + compressEvent(event)) continue; #ifndef QT_NO_CLIPBOARD @@ -1679,21 +1485,19 @@ void QXcbConnection::processXcbEvents() m_peekFuncs.erase(std::remove_if(m_peekFuncs.begin(), m_peekFuncs.end(), isWaitingFor), m_peekFuncs.end()); - m_reader->unlock(); - handleXcbEvent(event); - m_reader->lock(); - } - - eventqueue->clear(); - m_reader->unlock(); + handleXcbEvent(event); - m_peekerIndexCacheDirty = m_mainEventLoopFlushedQueue = true; + // The lock-based solution used to free the lock inside this loop, + // hence allowing for more events to arrive. ### Check if we want + // this flush here after QTBUG-70095 + m_eventQueue->flushBufferedEvents(); + } // Indicate with a null event that the event the callbacks are waiting for // is not in the queue currently. for (PeekFunc f : qAsConst(m_peekFuncs)) - f(this, 0); + f(this, nullptr); m_peekFuncs.clear(); xcb_flush(xcb_connection()); diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index a97a1f1002..29a233496b 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -47,15 +47,14 @@ #include "qxcbexport.h" #include #include -#include #include -#include #include -#include #include #include #include +#include "qxcbeventqueue.h" + #include #include @@ -84,6 +83,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaXcb) Q_DECLARE_LOGGING_CATEGORY(lcQpaPeeker) Q_DECLARE_LOGGING_CATEGORY(lcQpaKeyboard) Q_DECLARE_LOGGING_CATEGORY(lcQpaXDnd) +Q_DECLARE_LOGGING_CATEGORY(lcQpaEventReader) class QXcbVirtualDesktop; class QXcbScreen; @@ -305,35 +305,6 @@ namespace QXcbAtom { }; } -typedef QVarLengthArray QXcbEventArray; - -class QXcbConnection; -class QXcbEventReader : public QThread -{ - Q_OBJECT -public: - QXcbEventReader(QXcbConnection *connection); - - void run() override; - - QXcbEventArray *lock(); - void unlock(); - - void start(); - - void registerEventDispatcher(QAbstractEventDispatcher *dispatcher); - -signals: - void eventPending(); - -private: - void addEvent(xcb_generic_event_t *event); - - QMutex m_mutex; - QXcbEventArray m_events; - QXcbConnection *m_connection; -}; - class QXcbWindowEventListener { public: @@ -375,7 +346,6 @@ private: QXcbWindow *m_window; }; -class QAbstractEventDispatcher; class Q_XCB_EXPORT QXcbConnection : public QObject { Q_OBJECT @@ -385,6 +355,7 @@ public: QXcbConnection *connection() const { return const_cast(this); } bool isConnected() const; + QXcbEventQueue *eventQueue() const { return m_eventQueue; } const QList &virtualDesktops() const { return m_virtualDesktops; } const QList &screens() const { return m_screens; } @@ -445,21 +416,9 @@ public: QXcbWindowEventListener *windowEventListenerFromId(xcb_window_t id); QXcbWindow *platformWindowFromId(xcb_window_t id); - template - inline xcb_generic_event_t *checkEvent(Functor &&filter, bool removeFromQueue = true); - typedef bool (*PeekFunc)(QXcbConnection *, xcb_generic_event_t *); void addPeekFunc(PeekFunc f); - // Peek at all queued events - qint32 generatePeekerId(); - bool removePeekerId(qint32 peekerId); - enum PeekOption { PeekDefault = 0, PeekFromCachedIndex = 1 }; // see qx11info_x11.h - Q_DECLARE_FLAGS(PeekOptions, PeekOption) - typedef bool (*PeekerCallback)(xcb_generic_event_t *event, void *peekerData); - bool peekEventQueue(PeekerCallback peeker, void *peekerData = nullptr, - PeekOptions option = PeekDefault, qint32 peekerId = -1); - inline xcb_timestamp_t time() const { return m_time; } inline void setTime(xcb_timestamp_t t) { if (t > m_time) m_time = t; } @@ -530,24 +489,20 @@ public: void abortSystemMoveResizeForTouch(); bool isTouchScreen(int id); #endif - QXcbEventReader *eventReader() const { return m_reader; } bool canGrab() const { return m_canGrabServer; } QXcbGlIntegration *glIntegration() const; + void flush() { xcb_flush(m_connection); } + protected: bool event(QEvent *e) override; -public slots: - void flush() { xcb_flush(m_connection); } - -private slots: void processXcbEvents(); private: void initializeAllAtoms(); - void sendConnectionEvent(QXcbAtom::Atom atom, uint id = 0); void initializeShm(); void initializeXFixes(); void initializeXRender(); @@ -567,7 +522,7 @@ private: xcb_randr_get_output_info_reply_t *outputInfo); void destroyScreen(QXcbScreen *screen); void initializeScreens(); - bool compressEvent(xcb_generic_event_t *event, int currentIndex, QXcbEventArray *eventqueue) const; + bool compressEvent(xcb_generic_event_t *event) const; bool m_xi2Enabled = false; #if QT_CONFIG(xcb_xinput) @@ -670,7 +625,7 @@ private: #if QT_CONFIG(xcb_xlib) void *m_xlib_display = nullptr; #endif - QXcbEventReader *m_reader = nullptr; + QXcbEventQueue *m_eventQueue = nullptr; #if QT_CONFIG(xcb_xinput) QHash m_touchDevices; @@ -722,11 +677,7 @@ private: xcb_window_t m_qtSelectionOwner = 0; - bool m_mainEventLoopFlushedQueue = false; - qint32 m_peekerIdSource = 0; - bool m_peekerIndexCacheDirty = false; - QHash m_peekerToCachedIndex; - friend class QXcbEventReader; + friend class QXcbEventQueue; QByteArray m_xdgCurrentDesktop; }; @@ -737,24 +688,6 @@ Q_DECLARE_TYPEINFO(QXcbConnection::TabletData, Q_MOVABLE_TYPE); #endif #endif -template -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 (event && filter(event, event->response_type & ~0x80)) { - if (removeFromQueue) - (*eventqueue)[i] = nullptr; - m_reader->unlock(); - return event; - } - } - m_reader->unlock(); - return nullptr; -} - class QXcbConnectionGrabber { public: diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index 2b8e507f30..aa329d8cb7 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -794,7 +794,7 @@ void QXcbDrag::handlePosition(QPlatformWindow * w, const xcb_client_message_even { xcb_client_message_event_t *lastEvent = const_cast(event); ClientMessageScanner scanner(atom(QXcbAtom::XdndPosition)); - while (auto nextEvent = connection()->checkEvent(scanner)) { + while (auto nextEvent = connection()->eventQueue()->peek(scanner)) { if (lastEvent != event) free(lastEvent); lastEvent = reinterpret_cast(nextEvent); @@ -846,7 +846,7 @@ void QXcbDrag::handleStatus(const xcb_client_message_event_t *event) xcb_client_message_event_t *lastEvent = const_cast(event); xcb_generic_event_t *nextEvent; ClientMessageScanner scanner(atom(QXcbAtom::XdndStatus)); - while ((nextEvent = connection()->checkEvent(scanner))) { + while ((nextEvent = connection()->eventQueue()->peek(scanner))) { if (lastEvent != event) free(lastEvent); lastEvent = (xcb_client_message_event_t *)nextEvent; diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.cpp b/src/plugins/platforms/xcb/qxcbeventqueue.cpp new file mode 100644 index 0000000000..e530928ccb --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbeventqueue.cpp @@ -0,0 +1,332 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qxcbeventqueue.h" +#include "qxcbconnection.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QXcbEventQueue + \internal + + Lock-free event passing: + + The lock-free solution uses a singly-linked list to pass events from the + reader thread to the main thread. An atomic operation is used to sync the + tail node of the list between threads. The reader thread takes special care + when accessing the tail node. It does not dequeue the last node and does not + access (read or write) the tail node's 'next' member. This lets the reader + add more items at the same time as the main thread is dequeuing nodes from + the head. A custom linked list implementation is used, because QLinkedList + does not have any thread-safety guarantees and the custom list is more + lightweight - no reference counting, back links, etc. + + Memory management: + + In a normally functioning application, XCB plugin won't buffer more than few + batches of events, couple events per batch. Instead of constantly calling + new / delete, we can create a pool of nodes that we reuse. The main thread + uses an atomic operation to sync how many nodes have been restored (available + for reuse). If at some point a user application will block the main thread + for a long time, we might run out of nodes in the pool. Then we create nodes + on a heap. These will be automatically "garbage collected" out of the linked + list, once the main thread stops blocking. +*/ + +QXcbEventQueue::QXcbEventQueue(QXcbConnection *connection) + : m_connection(connection) +{ + connect(this, &QXcbEventQueue::eventsPending, m_connection, &QXcbConnection::processXcbEvents, Qt::QueuedConnection); + connect(this, &QXcbEventQueue::finished, m_connection, &QXcbConnection::processXcbEvents); + + // Lets init the list with one node, so we don't have to check for + // this special case in various places. + m_head = m_flushedTail = qXcbEventNodeFactory(nullptr); + m_tail.store(m_head, std::memory_order_release); + + start(); +} + +QXcbEventQueue::~QXcbEventQueue() +{ + if (isRunning()) { + sendCloseConnectionEvent(); + wait(); + } + + while (xcb_generic_event_t *event = takeFirst()) + free(event); + + if (m_head && m_head->fromHeap) + delete m_head; // the deferred node + + qCDebug(lcQpaEventReader) << "nodes on heap:" << m_nodesOnHeap; +} + +void QXcbEventQueue::registerEventDispatcher(QAbstractEventDispatcher *dispatcher) +{ + // Flush the xcb connection before the event dispatcher is going to block. + connect(dispatcher, &QAbstractEventDispatcher::aboutToBlock, m_connection, &QXcbConnection::flush); +} + +xcb_generic_event_t *QXcbEventQueue::takeFirst() +{ + if (isEmpty()) + return nullptr; + + xcb_generic_event_t *event = nullptr; + do { + event = m_head->event; + if (m_head == m_flushedTail) { + // defer dequeuing until next successful flush of events + if (event) // check if not cleared already by some filter + m_head->event = nullptr; // if not, clear it + } else { + dequeueNode(); + if (!event) + continue; // consumed by filter or deferred node + } + } while (!isEmpty() && !event); + + m_queueModified = m_peekerIndexCacheDirty = true; + + return event; +} + +void QXcbEventQueue::dequeueNode() +{ + QXcbEventNode *node = m_head; + m_head = m_head->next; + if (node->fromHeap) + delete node; + else + m_nodesRestored.fetch_add(1, std::memory_order_release); +} + +void QXcbEventQueue::flushBufferedEvents() +{ + m_flushedTail = m_tail.load(std::memory_order_acquire); +} + +QXcbEventNode *QXcbEventQueue::qXcbEventNodeFactory(xcb_generic_event_t *event) +{ + static QXcbEventNode qXcbNodePool[PoolSize]; + + if (m_freeNodes == 0) // out of nodes, check if the main thread has released any + m_freeNodes = m_nodesRestored.exchange(0, std::memory_order_acquire); + + if (m_freeNodes) { + m_freeNodes--; + if (m_poolIndex == PoolSize) { + // wrap back to the beginning, we always take and restore nodes in-order + m_poolIndex = 0; + } + QXcbEventNode *node = &qXcbNodePool[m_poolIndex++]; + node->event = event; + node->next = nullptr; + return node; + } + + // the main thread is not flushing events and thus the pool has become empty + auto node = new QXcbEventNode(event); + node->fromHeap = true; + qCDebug(lcQpaEventReader) << "[heap] " << m_nodesOnHeap++; + return node; +} + +void QXcbEventQueue::run() +{ + xcb_generic_event_t *event = nullptr; + xcb_connection_t *connection = m_connection->xcb_connection(); + QXcbEventNode *tail = m_head; + + auto enqueueEvent = [&tail, this](xcb_generic_event_t *event) { + if (!isCloseConnectionEvent(event)) { + tail->next = qXcbEventNodeFactory(event); + tail = tail->next; + m_tail.store(tail, std::memory_order_release); + } + }; + + while (!m_closeConnectionDetected && (event = xcb_wait_for_event(connection))) { + enqueueEvent(event); + while (!m_closeConnectionDetected && (event = xcb_poll_for_queued_event(connection))) + enqueueEvent(event); + + emit eventsPending(); + } +} + +qint32 QXcbEventQueue::generatePeekerId() +{ + const qint32 peekerId = m_peekerIdSource++; + m_peekerToNode.insert(peekerId, nullptr); + return peekerId; +} + +bool QXcbEventQueue::removePeekerId(qint32 peekerId) +{ + const auto it = m_peekerToNode.find(peekerId); + if (it == m_peekerToNode.constEnd()) { + qCWarning(lcQpaXcb, "failed to remove unknown peeker id: %d", peekerId); + return false; + } + m_peekerToNode.erase(it); + if (m_peekerToNode.isEmpty()) { + m_peekerIdSource = 0; // Once the hash becomes empty, we can start reusing IDs + m_peekerIndexCacheDirty = false; + } + return true; +} + +bool QXcbEventQueue::peekEventQueue(PeekerCallback peeker, void *peekerData, + PeekOptions option, qint32 peekerId) +{ + const bool peekerIdProvided = peekerId != -1; + auto peekerToNodeIt = m_peekerToNode.find(peekerId); + + if (peekerIdProvided && peekerToNodeIt == m_peekerToNode.constEnd()) { + qCWarning(lcQpaXcb, "failed to find index for unknown peeker id: %d", peekerId); + return false; + } + + const bool useCache = option.testFlag(PeekOption::PeekFromCachedIndex); + if (useCache && !peekerIdProvided) { + qCWarning(lcQpaXcb, "PeekOption::PeekFromCachedIndex requires peeker id"); + return false; + } + + if (peekerIdProvided && m_peekerIndexCacheDirty) { + for (auto &node : m_peekerToNode) // reset cache + node = nullptr; + m_peekerIndexCacheDirty = false; + } + + flushBufferedEvents(); + if (isEmpty()) + return false; + + const auto startNode = [this, useCache, peekerToNodeIt]() -> QXcbEventNode * { + if (useCache) { + const QXcbEventNode *cachedNode = peekerToNodeIt.value(); + if (!cachedNode) + return m_head; // cache was reset + if (cachedNode == m_flushedTail) + return nullptr; // no new events since the last call + return cachedNode->next; + } + return m_head; + }(); + + if (!startNode) + return false; + + // A peeker may call QCoreApplication::processEvents(), which will cause + // QXcbConnection::processXcbEvents() to modify the queue we are currently + // looping through; + m_queueModified = false; + bool result = false; + + QXcbEventNode *node = startNode; + do { + xcb_generic_event_t *event = node->event; + if (event && peeker(event, peekerData)) { + result = true; + break; + } + if (node == m_flushedTail) + break; + node = node->next; + } while (!m_queueModified); + + // Update the cached index if the queue was not modified, and hence the + // cache is still valid. + if (peekerIdProvided && node != startNode && !m_queueModified) { + // Before updating, make sure that a peeker callback did not remove + // the peeker id. + peekerToNodeIt = m_peekerToNode.find(peekerId); + if (peekerToNodeIt != m_peekerToNode.constEnd()) + *peekerToNodeIt = node; // id still in the cache, update node + } + + return result; +} + +void QXcbEventQueue::sendCloseConnectionEvent() const +{ + // A hack to close XCB connection. Apparently XCB does not have any APIs for this? + xcb_client_message_event_t event; + memset(&event, 0, sizeof(event)); + + xcb_connection_t *c = m_connection->xcb_connection(); + const xcb_window_t window = xcb_generate_id(c); + xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_connection->m_setup); + xcb_screen_t *screen = it.data; + xcb_create_window(c, XCB_COPY_FROM_PARENT, + window, screen->root, + 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY, + screen->root_visual, 0, nullptr); + + event.response_type = XCB_CLIENT_MESSAGE; + event.format = 32; + event.sequence = 0; + event.window = window; + event.type = m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION); + event.data.data32[0] = 0; + + xcb_send_event(c, false, window, XCB_EVENT_MASK_NO_EVENT, reinterpret_cast(&event)); + xcb_destroy_window(c, window); + xcb_flush(c); +} + +bool QXcbEventQueue::isCloseConnectionEvent(const xcb_generic_event_t *event) +{ + if (event && (event->response_type & ~0x80) == XCB_CLIENT_MESSAGE) { + auto clientMessage = reinterpret_cast(event); + if (clientMessage->type == m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION)) + m_closeConnectionDetected = true; + } + return m_closeConnectionDetected; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.h b/src/plugins/platforms/xcb/qxcbeventqueue.h new file mode 100644 index 0000000000..5b0d8bf3d6 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbeventqueue.h @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QXCBEVENTQUEUE_H +#define QXCBEVENTQUEUE_H + +#include +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +struct QXcbEventNode { + QXcbEventNode(xcb_generic_event_t *e = nullptr) + : event(e) { } + + xcb_generic_event_t *event; + QXcbEventNode *next = nullptr; + bool fromHeap = false; +}; + +class QXcbConnection; +class QAbstractEventDispatcher; + +class QXcbEventQueue : public QThread +{ + Q_OBJECT +public: + QXcbEventQueue(QXcbConnection *connection); + ~QXcbEventQueue(); + + enum { PoolSize = 100 }; // 2.4 kB with 100 nodes + + enum PeekOption { + PeekDefault = 0, // see qx11info_x11.h for docs + PeekFromCachedIndex = 1, + PeekRetainMatch = 2, + PeekRemoveMatch = 3, + PeekRemoveMatchContinue = 4 + }; + Q_DECLARE_FLAGS(PeekOptions, PeekOption) + + void run() override; + + void registerEventDispatcher(QAbstractEventDispatcher *dispatcher); + + bool isEmpty() const { return m_head == m_flushedTail && !m_head->event; } + xcb_generic_event_t *takeFirst(); + void flushBufferedEvents(); + + // ### peek() and peekEventQueue() could be unified. Note that peekEventQueue() + // is public API exposed via QX11Extras/QX11Info. + template + xcb_generic_event_t *peek(Peeker &&peeker) { + return peek(PeekRemoveMatch, std::forward(peeker)); + } + template + inline xcb_generic_event_t *peek(PeekOption config, Peeker &&peeker); + + qint32 generatePeekerId(); + bool removePeekerId(qint32 peekerId); + + using PeekerCallback = bool (*)(xcb_generic_event_t *event, void *peekerData); + bool peekEventQueue(PeekerCallback peeker, void *peekerData = nullptr, + PeekOptions option = PeekDefault, qint32 peekerId = -1); +signals: + void eventsPending(); + +private: + QXcbEventNode *qXcbEventNodeFactory(xcb_generic_event_t *event); + void dequeueNode(); + + void sendCloseConnectionEvent() const; + bool isCloseConnectionEvent(const xcb_generic_event_t *event); + + QXcbEventNode *m_head = nullptr; + QXcbEventNode *m_flushedTail = nullptr; + std::atomic m_tail { nullptr }; + std::atomic_uint m_nodesRestored { 0 }; + + QXcbConnection *m_connection = nullptr; + bool m_closeConnectionDetected = false; + + uint m_freeNodes = PoolSize; + uint m_poolIndex = 0; + + qint32 m_peekerIdSource = 0; + bool m_queueModified = false; + bool m_peekerIndexCacheDirty = false; + QHash m_peekerToNode; + + // debug stats + quint64 m_nodesOnHeap = 0; +}; + +template +xcb_generic_event_t *QXcbEventQueue::peek(PeekOption option, Peeker &&peeker) +{ + flushBufferedEvents(); + if (isEmpty()) + return nullptr; + + QXcbEventNode *node = m_head; + do { + xcb_generic_event_t *event = node->event; + if (event && peeker(event, event->response_type & ~0x80)) { + if (option == PeekRemoveMatch || option == PeekRemoveMatchContinue) + node->event = nullptr; + if (option != PeekRemoveMatchContinue) + return event; + } + if (node == m_flushedTail) + break; + node = node->next; + } while (true); + + return nullptr; +} + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index db8f816a86..b1a1ed93cd 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -46,6 +46,7 @@ #include "qxcbbackingstore.h" #include "qxcbnativeinterface.h" #include "qxcbclipboard.h" +#include "qxcbeventqueue.h" #if QT_CONFIG(draganddrop) #include "qxcbdrag.h" #endif @@ -344,7 +345,7 @@ QAbstractEventDispatcher *QXcbIntegration::createEventDispatcher() const { QAbstractEventDispatcher *dispatcher = createUnixEventDispatcher(); for (int i = 0; i < m_connections.size(); i++) - m_connections[i]->eventReader()->registerEventDispatcher(dispatcher); + m_connections[i]->eventQueue()->registerEventDispatcher(dispatcher); return dispatcher; } diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 20c169fc53..ad06f24c14 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -1541,7 +1541,8 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, } else { 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) { + connection()->eventQueue()->peek(QXcbEventQueue::PeekRetainMatch, + [this, time, code](xcb_generic_event_t *event, int type) { if (type == XCB_KEY_PRESS) { auto keyPress = reinterpret_cast(event); m_isAutoRepeat = keyPress->time == time && keyPress->detail == code; @@ -1549,7 +1550,7 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, m_autoRepeatCode = code; } return true; - }, false /* removeFromQueue */); + }); } bool filtered = false; diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 98bedea48a..524af5a2a7 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -437,20 +437,20 @@ void QXcbNativeInterface::setAppUserTime(QScreen* screen, xcb_timestamp_t time) qint32 QXcbNativeInterface::generatePeekerId() { QXcbIntegration *integration = QXcbIntegration::instance(); - return integration->defaultConnection()->generatePeekerId(); + return integration->defaultConnection()->eventQueue()->generatePeekerId(); } bool QXcbNativeInterface::removePeekerId(qint32 peekerId) { QXcbIntegration *integration = QXcbIntegration::instance(); - return integration->defaultConnection()->removePeekerId(peekerId); + return integration->defaultConnection()->eventQueue()->removePeekerId(peekerId); } -bool QXcbNativeInterface::peekEventQueue(QXcbConnection::PeekerCallback peeker, void *peekerData, - QXcbConnection::PeekOptions option, qint32 peekerId) +bool QXcbNativeInterface::peekEventQueue(QXcbEventQueue::PeekerCallback peeker, void *peekerData, + QXcbEventQueue::PeekOptions option, qint32 peekerId) { QXcbIntegration *integration = QXcbIntegration::instance(); - return integration->defaultConnection()->peekEventQueue(peeker, peekerData, option, peekerId); + return integration->defaultConnection()->eventQueue()->peekEventQueue(peeker, peekerData, option, peekerId); } void QXcbNativeInterface::setStartupId(const char *data) diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index d1f2747bea..4656f46be5 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -118,8 +118,8 @@ public: static qint32 generatePeekerId(); static bool removePeekerId(qint32 peekerId); - static bool peekEventQueue(QXcbConnection::PeekerCallback peeker, void *peekerData = nullptr, - QXcbConnection::PeekOptions option = QXcbConnection::PeekDefault, + static bool peekEventQueue(QXcbEventQueue::PeekerCallback peeker, void *peekerData = nullptr, + QXcbEventQueue::PeekOptions option = QXcbEventQueue::PeekDefault, qint32 peekerId = -1); Q_INVOKABLE QString dumpConnectionNativeWindows(const QXcbConnection *connection, WId root) const; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 69fc6c2951..772309c6ae 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -1818,21 +1818,20 @@ void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event) m_exposeRegion |= rect; 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(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); + + connection()->eventQueue()->peek(QXcbEventQueue::PeekRemoveMatchContinue, + [this, &pending](xcb_generic_event_t *event, int type) { + if (type != XCB_EXPOSE) + return false; + auto expose = reinterpret_cast(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); + free(expose); + return true; + }); // if count is non-zero there are more expose events pending if (event->count == 0 || !pending) { @@ -2152,13 +2151,11 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y, return; // check if enter event is buffered - auto event = connection()->checkEvent([](xcb_generic_event_t *event, int type) { + auto event = connection()->eventQueue()->peek([](xcb_generic_event_t *event, int type) { if (type != XCB_ENTER_NOTIFY) return false; auto enter = reinterpret_cast(event); - if (ignoreEnterEvent(enter->mode, enter->detail)) - return false; - return true; + return !ignoreEnterEvent(enter->mode, enter->detail); }); auto enter = reinterpret_cast(event); QXcbWindow *enterWindow = enter ? connection()->platformWindowFromId(enter->event) : nullptr; diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index 9390d04983..fbda8c39b9 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -27,7 +27,8 @@ SOURCES = \ qxcbcursor.cpp \ qxcbimage.cpp \ qxcbxsettings.cpp \ - qxcbsystemtraytracker.cpp + qxcbsystemtraytracker.cpp \ + qxcbeventqueue.cpp HEADERS = \ qxcbclipboard.h \ @@ -45,7 +46,8 @@ HEADERS = \ qxcbimage.h \ qxcbxsettings.h \ qxcbsystemtraytracker.h \ - qxcbxkbcommon.h + qxcbxkbcommon.h \ + qxcbeventqueue.h qtConfig(draganddrop) { SOURCES += qxcbdrag.cpp -- cgit v1.2.3 From 502a6cc2537f2b26d5cce1caec7504cc89047db1 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Fri, 7 Sep 2018 15:06:27 +0200 Subject: xcb: localize handling of Qt::AA_Compress* flags Handle both of them inside the QXcbConnection::compressEvent(). Change-Id: Ibe7184ba5c5b636013145e887c817dca701345ad Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/qxcbconnection.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 4d3f62791c..c1f0b71414 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -1386,6 +1386,9 @@ static inline bool isXIType(xcb_generic_event_t *event, int opCode, uint16_t typ */ bool QXcbConnection::compressEvent(xcb_generic_event_t *event) const { + if (!QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)) + return false; + uint responseType = event->response_type & ~0x80; if (responseType == XCB_MOTION_NOTIFY) { @@ -1465,8 +1468,7 @@ void QXcbConnection::processXcbEvents() handleXcbError(reinterpret_cast(event)); continue; } - if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)) && - compressEvent(event)) + if (compressEvent(event)) continue; #ifndef QT_NO_CLIPBOARD -- cgit v1.2.3 From 1f6bfc220774e9407fe88916843b76ed103cff72 Mon Sep 17 00:00:00 2001 From: Cristian Maureira-Fredes Date: Mon, 3 Sep 2018 14:02:13 +0200 Subject: Doc: Move literal code block to a separate file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to override this snippet for the documentation we generate for Qt for Python, and it is easier to have it on a separate file. Task-number: PYSIDE-801 Task-number: PYSIDE-691 Change-Id: Ideb5b6af25024279f167137d3b65660bb9c96a7e Reviewed-by: Topi Reiniö --- .../code/src_plugins_platforms_qnx_qqnxwindow.cpp | 52 ++++++++++++++++++++++ src/plugins/platforms/qnx/qqnxwindow.cpp | 14 +----- 2 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 src/plugins/doc/snippets/code/src_plugins_platforms_qnx_qqnxwindow.cpp (limited to 'src/plugins') diff --git a/src/plugins/doc/snippets/code/src_plugins_platforms_qnx_qqnxwindow.cpp b/src/plugins/doc/snippets/code/src_plugins_platforms_qnx_qqnxwindow.cpp new file mode 100644 index 0000000000..ce82533c3e --- /dev/null +++ b/src/plugins/doc/snippets/code/src_plugins_platforms_qnx_qqnxwindow.cpp @@ -0,0 +1,52 @@ +/*************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] + QQuickView *view = new QQuickView(parent); + view->create(); + QGuiApplication::platformNativeInterface()->setWindowProperty(view->handle(), "qnxWindowGroup", + group); +//! [0] + +//! [1] + QQuickView *view = new QQuickView(parent); + view->create(); + QGuiApplication::platformNativeInterface()->setWindowProperty(view->handle(), "qnxWindowGroup", + QVariant()); +//! [1] diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp index 5d9eaaa3ea..2096bc789e 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxwindow.cpp @@ -132,22 +132,12 @@ DECLARE_DEBUG_VAR(statistics) setWindowProperty function of the native interface to set the \e qnxWindowGroup property to the desired value, for example: - \code - QQuickView *view = new QQuickView(parent); - view->create(); - QGuiApplication::platformNativeInterface()->setWindowProperty(view->handle(), "qnxWindowGroup", - group); - \endcode + \snippet code/src_plugins_platforms_qnx_qqnxwindow.cpp 0 To leave the current window group, one passes a null value for the property value, for example: - \code - QQuickView *view = new QQuickView(parent); - view->create(); - QGuiApplication::platformNativeInterface()->setWindowProperty(view->handle(), "qnxWindowGroup", - QVariant()); - \endcode + \snippet code/src_plugins_platforms_qnx_qqnxwindow.cpp 1 \section1 Window Id -- cgit v1.2.3 From 80b1cce0cfe5d8e527731b921fd5d0c1a007afd5 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Tue, 18 Sep 2018 21:51:57 +0200 Subject: xcb: call processXcbEvents() on every event loop iteration It is necessary for QTBUG-69687. The original code processes the xcb event queue only when new events have arrived, but if we want to do an event filtering that buffers some events and processes them later based on set/unset flags (e.g. QEventLoop::ExcludeUserInputEvents), we need to call processXcbEvents() on every event loop iteration, not only when new events have arrived from X server. The required functionality is implemented by having custom event dispatchers, instead of using the generic ones from QtGenericUnixDispatcher:: createUnixEventDispatcher() / eventdispatcher_support-private. This also enables for further customizations, as might be necessary by QTBUG-70095. Task-number: QTBUG-69687 Change-Id: I1f8b2400d26cccf17279d57bb4b678e40c615f33 Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbconnection.h | 3 +- src/plugins/platforms/xcb/qxcbeventdispatcher.cpp | 161 ++++++++++++++++++++++ src/plugins/platforms/xcb/qxcbeventdispatcher.h | 117 ++++++++++++++++ src/plugins/platforms/xcb/qxcbeventqueue.cpp | 4 +- src/plugins/platforms/xcb/qxcbintegration.cpp | 4 +- src/plugins/platforms/xcb/qxcbintegration.h | 1 - src/plugins/platforms/xcb/xcb_qpa_lib.pro | 10 +- 7 files changed, 289 insertions(+), 11 deletions(-) create mode 100644 src/plugins/platforms/xcb/qxcbeventdispatcher.cpp create mode 100644 src/plugins/platforms/xcb/qxcbeventdispatcher.h (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 29a233496b..3fb64f01a4 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -495,12 +495,11 @@ public: QXcbGlIntegration *glIntegration() const; void flush() { xcb_flush(m_connection); } + void processXcbEvents(); protected: bool event(QEvent *e) override; - void processXcbEvents(); - private: void initializeAllAtoms(); void initializeShm(); diff --git a/src/plugins/platforms/xcb/qxcbeventdispatcher.cpp b/src/plugins/platforms/xcb/qxcbeventdispatcher.cpp new file mode 100644 index 0000000000..252c1c62e3 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbeventdispatcher.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qxcbeventdispatcher.h" +#include "qxcbconnection.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +QXcbUnixEventDispatcher::QXcbUnixEventDispatcher(QXcbConnection *connection, QObject *parent) + : QEventDispatcherUNIX(parent) + , m_connection(connection) +{ +} + +QXcbUnixEventDispatcher::~QXcbUnixEventDispatcher() +{ +} + +bool QXcbUnixEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) +{ + const bool didSendEvents = QEventDispatcherUNIX::processEvents(flags); + m_connection->processXcbEvents(); + // The following line should not be necessary after QTBUG-70095 + return QWindowSystemInterface::sendWindowSystemEvents(flags) || didSendEvents; +} + +bool QXcbUnixEventDispatcher::hasPendingEvents() +{ + extern uint qGlobalPostedEventsCount(); + return qGlobalPostedEventsCount() || QWindowSystemInterface::windowSystemEventsQueued(); +} + +void QXcbUnixEventDispatcher::flush() +{ + if (qApp) + qApp->sendPostedEvents(); +} + +#if QT_CONFIG(glib) +struct XcbEventSource +{ + GSource source; + QXcbGlibEventDispatcher *dispatcher; + QXcbGlibEventDispatcherPrivate *dispatcher_p; + QXcbConnection *connection = nullptr; +}; + +static gboolean xcbSourcePrepare(GSource *source, gint *timeout) +{ + Q_UNUSED(timeout) + auto xcbEventSource = reinterpret_cast(source); + return xcbEventSource->dispatcher_p->wakeUpCalled; +} + +static gboolean xcbSourceCheck(GSource *source) +{ + return xcbSourcePrepare(source, nullptr); +} + +static gboolean xcbSourceDispatch(GSource *source, GSourceFunc, gpointer) +{ + auto xcbEventSource = reinterpret_cast(source); + xcbEventSource->connection->processXcbEvents(); + // The following line should not be necessary after QTBUG-70095 + QWindowSystemInterface::sendWindowSystemEvents(xcbEventSource->dispatcher->flags()); + return true; +} + +QXcbGlibEventDispatcher::QXcbGlibEventDispatcher(QXcbConnection *connection, QObject *parent) + : QEventDispatcherGlib(*new QXcbGlibEventDispatcherPrivate(), parent) +{ + Q_D(QXcbGlibEventDispatcher); + + m_xcbEventSourceFuncs.prepare = xcbSourcePrepare; + m_xcbEventSourceFuncs.check = xcbSourceCheck; + m_xcbEventSourceFuncs.dispatch = xcbSourceDispatch; + m_xcbEventSourceFuncs.finalize = nullptr; + + m_xcbEventSource = reinterpret_cast( + g_source_new(&m_xcbEventSourceFuncs, sizeof(XcbEventSource))); + + m_xcbEventSource->dispatcher = this; + m_xcbEventSource->dispatcher_p = d_func(); + m_xcbEventSource->connection = connection; + + g_source_set_can_recurse(&m_xcbEventSource->source, true); + g_source_attach(&m_xcbEventSource->source, d->mainContext); +} + +QXcbGlibEventDispatcherPrivate::QXcbGlibEventDispatcherPrivate() +{ +} + +QXcbGlibEventDispatcher::~QXcbGlibEventDispatcher() +{ + g_source_destroy(&m_xcbEventSource->source); + g_source_unref(&m_xcbEventSource->source); +} + +bool QXcbGlibEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) +{ + m_flags = flags; + return QEventDispatcherGlib::processEvents(m_flags); +} + +#endif // QT_CONFIG(glib) + +QAbstractEventDispatcher *QXcbEventDispatcher::createEventDispatcher(QXcbConnection *connection) +{ +#if QT_CONFIG(glib) + if (qEnvironmentVariableIsEmpty("QT_NO_GLIB") && QEventDispatcherGlib::versionSupported()) { + qCDebug(lcQpaXcb, "using glib dispatcher"); + return new QXcbGlibEventDispatcher(connection); + } else +#endif + { + qCDebug(lcQpaXcb, "using unix dispatcher"); + return new QXcbUnixEventDispatcher(connection); + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbeventdispatcher.h b/src/plugins/platforms/xcb/qxcbeventdispatcher.h new file mode 100644 index 0000000000..6aadd63a70 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbeventdispatcher.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QXCBEVENTDISPATCHER_H +#define QXCBEVENTDISPATCHER_H + +#include +#include + +#include +#if QT_CONFIG(glib) +#include +#include +#endif + +QT_BEGIN_NAMESPACE + +class QXcbConnection; + +class QXcbUnixEventDispatcher : public QEventDispatcherUNIX +{ + Q_OBJECT +public: + explicit QXcbUnixEventDispatcher(QXcbConnection *connection, QObject *parent = nullptr); + ~QXcbUnixEventDispatcher(); + bool processEvents(QEventLoop::ProcessEventsFlags flags) override; + + // Maybe some user code depends on deprecated QUnixEventDispatcherQPA:: + // hasPendingEvents() / flush() implementation, so keep it around until + // Qt 6. These methods are deprecated in QAbstractEventDispatcher. + bool hasPendingEvents() override; // ### Qt 6 remove + void flush() override; // ### Qt 6 remove + +private: + QXcbConnection *m_connection; +}; + +#if QT_CONFIG(glib) + +struct XcbEventSource; +class QXcbGlibEventDispatcherPrivate; + +class QXcbGlibEventDispatcher : public QEventDispatcherGlib +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QXcbGlibEventDispatcher) + +public: + explicit QXcbGlibEventDispatcher(QXcbConnection *connection, QObject *parent = nullptr); + ~QXcbGlibEventDispatcher(); + + bool processEvents(QEventLoop::ProcessEventsFlags flags) override; + QEventLoop::ProcessEventsFlags flags() const { return m_flags; } + +private: + XcbEventSource *m_xcbEventSource; + GSourceFuncs m_xcbEventSourceFuncs; + QEventLoop::ProcessEventsFlags m_flags; +}; + +class QXcbGlibEventDispatcherPrivate : public QEventDispatcherGlibPrivate +{ + Q_DECLARE_PUBLIC(QXcbGlibEventDispatcher) + +public: + QXcbGlibEventDispatcherPrivate(); +}; + +#endif // QT_CONFIG(glib) + +class QXcbEventDispatcher +{ +public: + static QAbstractEventDispatcher *createEventDispatcher(QXcbConnection *connection); + +private: + QXcbConnection *m_connection; +}; + +QT_END_NAMESPACE + +#endif // QXCBEVENTDISPATCHER_H diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.cpp b/src/plugins/platforms/xcb/qxcbeventqueue.cpp index e530928ccb..6d8b001faa 100644 --- a/src/plugins/platforms/xcb/qxcbeventqueue.cpp +++ b/src/plugins/platforms/xcb/qxcbeventqueue.cpp @@ -76,7 +76,6 @@ QT_BEGIN_NAMESPACE QXcbEventQueue::QXcbEventQueue(QXcbConnection *connection) : m_connection(connection) { - connect(this, &QXcbEventQueue::eventsPending, m_connection, &QXcbConnection::processXcbEvents, Qt::QueuedConnection); connect(this, &QXcbEventQueue::finished, m_connection, &QXcbConnection::processXcbEvents); // Lets init the list with one node, so we don't have to check for @@ -105,8 +104,7 @@ QXcbEventQueue::~QXcbEventQueue() void QXcbEventQueue::registerEventDispatcher(QAbstractEventDispatcher *dispatcher) { - // Flush the xcb connection before the event dispatcher is going to block. - connect(dispatcher, &QAbstractEventDispatcher::aboutToBlock, m_connection, &QXcbConnection::flush); + connect(this, &QXcbEventQueue::eventsPending, dispatcher, &QAbstractEventDispatcher::wakeUp, Qt::QueuedConnection); } xcb_generic_event_t *QXcbEventQueue::takeFirst() diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index b1a1ed93cd..8f6d35dc5b 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -47,6 +47,7 @@ #include "qxcbnativeinterface.h" #include "qxcbclipboard.h" #include "qxcbeventqueue.h" +#include "qxcbeventdispatcher.h" #if QT_CONFIG(draganddrop) #include "qxcbdrag.h" #endif @@ -58,7 +59,6 @@ #include -#include #include #include @@ -343,7 +343,7 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const QAbstractEventDispatcher *QXcbIntegration::createEventDispatcher() const { - QAbstractEventDispatcher *dispatcher = createUnixEventDispatcher(); + QAbstractEventDispatcher *dispatcher = QXcbEventDispatcher::createEventDispatcher(defaultConnection()); for (int i = 0; i < m_connections.size(); i++) m_connections[i]->eventQueue()->registerEventDispatcher(dispatcher); return dispatcher; diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index 69e49cb7f6..a8dd6402f6 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -53,7 +53,6 @@ QT_BEGIN_NAMESPACE class QXcbConnection; class QAbstractEventDispatcher; class QXcbNativeInterface; -class QXcbScreen; class Q_XCB_EXPORT QXcbIntegration : public QPlatformIntegration { diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index fbda8c39b9..a747b25c88 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -5,7 +5,7 @@ DEFINES += QT_NO_FOREACH QT += \ core-private gui-private \ service_support-private theme_support-private \ - eventdispatcher_support-private fontdatabase_support-private \ + fontdatabase_support-private \ edid_support-private qtHaveModule(linuxaccessibility_support-private): \ @@ -13,6 +13,8 @@ qtHaveModule(linuxaccessibility_support-private): \ qtConfig(vulkan): QT += vulkan_support-private +qtConfig(glib) : QMAKE_USE_PRIVATE += glib + SOURCES = \ qxcbclipboard.cpp \ qxcbconnection.cpp \ @@ -28,7 +30,8 @@ SOURCES = \ qxcbimage.cpp \ qxcbxsettings.cpp \ qxcbsystemtraytracker.cpp \ - qxcbeventqueue.cpp + qxcbeventqueue.cpp \ + qxcbeventdispatcher.cpp HEADERS = \ qxcbclipboard.h \ @@ -47,7 +50,8 @@ HEADERS = \ qxcbxsettings.h \ qxcbsystemtraytracker.h \ qxcbxkbcommon.h \ - qxcbeventqueue.h + qxcbeventqueue.h \ + qxcbeventdispatcher.h qtConfig(draganddrop) { SOURCES += qxcbdrag.cpp -- cgit v1.2.3 From 4aa86d38ef9cf852db987bc4d560746363a705b8 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Wed, 19 Sep 2018 09:50:05 +0200 Subject: xcb: utilize thread-safety of QAbstractEventDispatcher::wakeUp QAbstractEventDispatcher::wakeUp is a thread-safe method, using a queued connection to invoke it is wasteful. This type of connection involves allocating temporary QMetaCallEvent on a heap and locking of destination thread's post-event queue. In most use cases this is ok, and really convenient when target method is not thread-safe. But in this case the existing solution was suboptimal, especially because the events we are reading can be high frequency. The solution that we use here is lock-free. There can be only one time when it might need to wait for the lock, which is upon exiting the application. If we have entered the critical section in QXcbEventReader::run(), then the registered post routine (qAddPostRoutine) will block the QCoreApplication's dtor (this is where dispatcher is set to 0) until we exit the critical section. We also know when not to enter the critical section, in case dtor is already running. With this approach we might need to compete for the lock at most once, instead of whole application lifetime, which was the case with the existing code. Change-Id: If6737329c972347b0050d67658e28dbaa6f552e8 Reviewed-by: Thiago Macieira --- src/plugins/platforms/xcb/qxcbeventqueue.cpp | 27 +++++++++++++++++++++------ src/plugins/platforms/xcb/qxcbeventqueue.h | 4 ---- src/plugins/platforms/xcb/qxcbintegration.cpp | 5 +---- 3 files changed, 22 insertions(+), 14 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.cpp b/src/plugins/platforms/xcb/qxcbeventqueue.cpp index 6d8b001faa..5bd4e7a68a 100644 --- a/src/plugins/platforms/xcb/qxcbeventqueue.cpp +++ b/src/plugins/platforms/xcb/qxcbeventqueue.cpp @@ -40,11 +40,16 @@ #include "qxcbconnection.h" #include +#include #include +#include #include QT_BEGIN_NAMESPACE +static QBasicMutex qAppExiting; +static bool dispatcherOwnerDestructing = false; + /*! \class QXcbEventQueue \internal @@ -78,6 +83,15 @@ QXcbEventQueue::QXcbEventQueue(QXcbConnection *connection) { connect(this, &QXcbEventQueue::finished, m_connection, &QXcbConnection::processXcbEvents); + // When running test cases in auto tests, static variables are preserved + // between test function runs, even if Q*Application object is destroyed. + // Reset to default value to account for this. + dispatcherOwnerDestructing = false; + qAddPostRoutine([]() { + QMutexLocker locker(&qAppExiting); + dispatcherOwnerDestructing = true; + }); + // Lets init the list with one node, so we don't have to check for // this special case in various places. m_head = m_flushedTail = qXcbEventNodeFactory(nullptr); @@ -102,11 +116,6 @@ QXcbEventQueue::~QXcbEventQueue() qCDebug(lcQpaEventReader) << "nodes on heap:" << m_nodesOnHeap; } -void QXcbEventQueue::registerEventDispatcher(QAbstractEventDispatcher *dispatcher) -{ - connect(this, &QXcbEventQueue::eventsPending, dispatcher, &QAbstractEventDispatcher::wakeUp, Qt::QueuedConnection); -} - xcb_generic_event_t *QXcbEventQueue::takeFirst() { if (isEmpty()) @@ -191,7 +200,13 @@ void QXcbEventQueue::run() while (!m_closeConnectionDetected && (event = xcb_poll_for_queued_event(connection))) enqueueEvent(event); - emit eventsPending(); + QMutexLocker locker(&qAppExiting); + if (!dispatcherOwnerDestructing) { + // This thread can run before a dispatcher has been created, + // so check if it is ready. + if (QCoreApplication::eventDispatcher()) + QCoreApplication::eventDispatcher()->wakeUp(); + } } } diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.h b/src/plugins/platforms/xcb/qxcbeventqueue.h index 5b0d8bf3d6..bec2a6a201 100644 --- a/src/plugins/platforms/xcb/qxcbeventqueue.h +++ b/src/plugins/platforms/xcb/qxcbeventqueue.h @@ -80,8 +80,6 @@ public: void run() override; - void registerEventDispatcher(QAbstractEventDispatcher *dispatcher); - bool isEmpty() const { return m_head == m_flushedTail && !m_head->event; } xcb_generic_event_t *takeFirst(); void flushBufferedEvents(); @@ -101,8 +99,6 @@ public: using PeekerCallback = bool (*)(xcb_generic_event_t *event, void *peekerData); bool peekEventQueue(PeekerCallback peeker, void *peekerData = nullptr, PeekOptions option = PeekDefault, qint32 peekerId = -1); -signals: - void eventsPending(); private: QXcbEventNode *qXcbEventNodeFactory(xcb_generic_event_t *event); diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 8f6d35dc5b..d030b22fc8 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -343,10 +343,7 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const QAbstractEventDispatcher *QXcbIntegration::createEventDispatcher() const { - QAbstractEventDispatcher *dispatcher = QXcbEventDispatcher::createEventDispatcher(defaultConnection()); - for (int i = 0; i < m_connections.size(); i++) - m_connections[i]->eventQueue()->registerEventDispatcher(dispatcher); - return dispatcher; + return QXcbEventDispatcher::createEventDispatcher(defaultConnection()); } void QXcbIntegration::initialize() -- cgit v1.2.3 From 03b1380613d581863727a76db62dca974b55682b Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Tue, 7 Aug 2018 18:09:25 +0200 Subject: xcb: cleanup WM_HINTS handling - The only place where window flag Qt::WindowDoesNotAcceptFocus changes is inside QXcbWindow::setWindowFlags and from there we call updateDoesNotAcceptFocus(). The current code was redundantly calling xcb_wm_hints_set_input in various places. - Similar as above: call xcb_wm_hints_set_normal/iconic only where it can change. This hint depends on window state, so update it only from setWindowState(). Removed unnecessary call to setTransparentForMouseEvents(), which is already called few lines above from setWindowFlags(). Change-Id: I8da919b135a4dfda0c8c1dad51d85d3e706153ab Reviewed-by: Allan Sandfeld Jensen --- src/plugins/platforms/xcb/qxcbwindow.cpp | 36 ++++++++++++-------------------- 1 file changed, 13 insertions(+), 23 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 772309c6ae..f36bb5a51e 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -499,12 +499,10 @@ void QXcbWindow::create() clientMachine.size(), clientMachine.constData()); } + // Create WM_HINTS property on the window, so we can xcb_get_wm_hints*() + // from various setter functions for adjusting the hints. xcb_wm_hints_t hints; memset(&hints, 0, sizeof(hints)); - xcb_wm_hints_set_normal(&hints); - - xcb_wm_hints_set_input(&hints, !(window()->flags() & Qt::WindowDoesNotAcceptFocus)); - xcb_set_wm_hints(xcb_connection(), m_window, &hints); xcb_window_t leader = connection()->clientLeader(); @@ -532,9 +530,6 @@ void QXcbWindow::create() setWindowFlags(window()->flags()); setWindowTitle(window()->title()); - if (window()->flags() & Qt::WindowTransparentForInput) - setTransparentForMouseEvents(true); - #if QT_CONFIG(xcb_xlib) // force sync to read outstanding requests - see QTBUG-29106 XSync(static_cast(platformScreen->connection()->xlib_display()), false); @@ -739,20 +734,6 @@ void QXcbWindow::show() { if (window()->isTopLevel()) { - xcb_get_property_cookie_t cookie = xcb_get_wm_hints_unchecked(xcb_connection(), m_window); - - xcb_wm_hints_t hints; - xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, NULL); - - if (window()->windowStates() & Qt::WindowMinimized) - xcb_wm_hints_set_iconic(&hints); - else - xcb_wm_hints_set_normal(&hints); - - xcb_wm_hints_set_input(&hints, !(window()->flags() & Qt::WindowDoesNotAcceptFocus)); - - xcb_set_wm_hints(xcb_connection(), m_window, &hints); - // update WM_NORMAL_HINTS propagateSizeHints(); @@ -1230,6 +1211,16 @@ void QXcbWindow::setWindowState(Qt::WindowStates state) changeNetWmState(state & Qt::WindowFullScreen, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); } + xcb_get_property_cookie_t cookie = xcb_get_wm_hints_unchecked(xcb_connection(), m_window); + xcb_wm_hints_t hints; + if (xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, nullptr)) { + if (state & Qt::WindowMinimized) + xcb_wm_hints_set_iconic(&hints); + else + xcb_wm_hints_set_normal(&hints); + xcb_set_wm_hints(xcb_connection(), m_window, &hints); + } + connection()->sync(); m_windowState = state; } @@ -1402,9 +1393,8 @@ void QXcbWindow::updateDoesNotAcceptFocus(bool doesNotAcceptFocus) xcb_get_property_cookie_t cookie = xcb_get_wm_hints_unchecked(xcb_connection(), m_window); xcb_wm_hints_t hints; - if (!xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, NULL)) { + if (!xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, nullptr)) return; - } xcb_wm_hints_set_input(&hints, !doesNotAcceptFocus); xcb_set_wm_hints(xcb_connection(), m_window, &hints); -- cgit v1.2.3 From dc3dd8c5dbf68ad0497faa57d12540088b661147 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 1 Oct 2018 09:38:46 +0200 Subject: Windows QPA: Add WM_INPUT to the list of input messages for event filtering Amends a0a22037cdacbf51a2db560ff902a5a341561b15. Task-number: QTBUG-67095 Change-Id: I32d2e78f9d9525d56c1d4477d69cf7b9d7f8e7a3 Reviewed-by: Miguel Costa --- src/plugins/platforms/windows/qwindowscontext.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 253aeb9d76..7f1b7077f7 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -960,6 +960,7 @@ static inline bool isInputMessage(UINT m) case WM_IME_STARTCOMPOSITION: case WM_IME_ENDCOMPOSITION: case WM_IME_COMPOSITION: + case WM_INPUT: case WM_TOUCH: case WM_MOUSEHOVER: case WM_MOUSELEAVE: -- cgit v1.2.3 From dd8a66daa497f0547f2fcddc0ee1e722d13ab98b Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Wed, 19 Sep 2018 11:14:10 +0200 Subject: xcb: rework connection error handling This patch reworks 0b1ce5db9e04b4c28713e87306fcea020c3e428b. Just by looking at the source code it was unclear why is this signal-and-slot connection necessary. It doesn't do anything on normal exit - at the time we call dtor of this class, QCoreApplication::instance() already is nullptr, which means that no further event processing happens and we never get this signal. Without digging into git history it may appear that the goal was to process the remaining events on application exit, which would be a questionable code by itself. Change-Id: I202d11584901e3b52254d8e3c347aece17844b72 Reviewed-by: Allan Sandfeld Jensen --- src/plugins/platforms/xcb/qxcbeventqueue.cpp | 27 ++++++++++++++++++--------- src/plugins/platforms/xcb/qxcbeventqueue.h | 1 + 2 files changed, 19 insertions(+), 9 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.cpp b/src/plugins/platforms/xcb/qxcbeventqueue.cpp index 5bd4e7a68a..d7d70536a0 100644 --- a/src/plugins/platforms/xcb/qxcbeventqueue.cpp +++ b/src/plugins/platforms/xcb/qxcbeventqueue.cpp @@ -81,8 +81,6 @@ static bool dispatcherOwnerDestructing = false; QXcbEventQueue::QXcbEventQueue(QXcbConnection *connection) : m_connection(connection) { - connect(this, &QXcbEventQueue::finished, m_connection, &QXcbConnection::processXcbEvents); - // When running test cases in auto tests, static variables are preserved // between test function runs, even if Q*Application object is destroyed. // Reset to default value to account for this. @@ -199,14 +197,25 @@ void QXcbEventQueue::run() enqueueEvent(event); while (!m_closeConnectionDetected && (event = xcb_poll_for_queued_event(connection))) enqueueEvent(event); + wakeUpDispatcher(); + } - QMutexLocker locker(&qAppExiting); - if (!dispatcherOwnerDestructing) { - // This thread can run before a dispatcher has been created, - // so check if it is ready. - if (QCoreApplication::eventDispatcher()) - QCoreApplication::eventDispatcher()->wakeUp(); - } + if (!m_closeConnectionDetected) { + // Connection was terminated not by us. Wake up dispatcher, which will + // call processXcbEvents(), where we handle the connection errors via + // xcb_connection_has_error(). + wakeUpDispatcher(); + } +} + +void QXcbEventQueue::wakeUpDispatcher() +{ + QMutexLocker locker(&qAppExiting); + if (!dispatcherOwnerDestructing) { + // This thread can run before a dispatcher has been created, + // so check if it is ready. + if (QCoreApplication::eventDispatcher()) + QCoreApplication::eventDispatcher()->wakeUp(); } } diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.h b/src/plugins/platforms/xcb/qxcbeventqueue.h index bec2a6a201..0096437dba 100644 --- a/src/plugins/platforms/xcb/qxcbeventqueue.h +++ b/src/plugins/platforms/xcb/qxcbeventqueue.h @@ -83,6 +83,7 @@ public: bool isEmpty() const { return m_head == m_flushedTail && !m_head->event; } xcb_generic_event_t *takeFirst(); void flushBufferedEvents(); + void wakeUpDispatcher(); // ### peek() and peekEventQueue() could be unified. Note that peekEventQueue() // is public API exposed via QX11Extras/QX11Info. -- cgit v1.2.3 From 00ae1e6b7bf6efa5f5e57d37844e44d521604fb6 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Wed, 19 Sep 2018 11:40:31 +0200 Subject: xcb: respect QEventLoop::ExcludeUserInputEvents in native event handlers This was a regression from Qt 4. Before this patch, we supported filtering events only at QWindowSystemInterface level, but to properly support filtering in QAbstractEventDispatcher::filterNativeEvent, we have to filter the events earlier. Now it is possible to enable/disable this feature for platforms that support native event filtering. The mapping of which events are user input events were taken from QWindowSystemInterfacePrivate::EventType. Task-number: QTBUG-69687 Change-Id: I9a5fb9f999451c47abcdc83fdcc129b5eeb55447 Reviewed-by: Paul Wicking Reviewed-by: Allan Sandfeld Jensen --- src/plugins/platforms/xcb/qxcbconnection.cpp | 54 ++++++++++++++++++++--- src/plugins/platforms/xcb/qxcbconnection.h | 4 +- src/plugins/platforms/xcb/qxcbeventdispatcher.cpp | 7 +-- src/plugins/platforms/xcb/qxcbeventqueue.cpp | 29 ++++++++++++ src/plugins/platforms/xcb/qxcbeventqueue.h | 5 +++ src/plugins/platforms/xcb/qxcbintegration.cpp | 2 + 6 files changed, 90 insertions(+), 11 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index c1f0b71414..a4294956c1 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -1020,11 +1020,10 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) printXcbEvent(lcQpaEvents(), "Event", event); long result = 0; // Used only by MS Windows - QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(); - bool handledByNativeEventFilter = dispatcher && dispatcher->filterNativeEvent( - m_nativeInterface->nativeEventType(), event, &result); - if (handledByNativeEventFilter) - return; + if (QAbstractEventDispatcher *dispatcher = QAbstractEventDispatcher::instance()) { + if (dispatcher->filterNativeEvent(m_nativeInterface->nativeEventType(), event, &result)) + return; + } uint response_type = event->response_type & ~0x80; @@ -1451,7 +1450,47 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event) const return false; } -void QXcbConnection::processXcbEvents() +bool QXcbConnection::isUserInputEvent(xcb_generic_event_t *event) const +{ + auto eventType = event->response_type & ~0x80; + bool isInputEvent = eventType == XCB_BUTTON_PRESS || + eventType == XCB_BUTTON_RELEASE || + eventType == XCB_KEY_PRESS || + eventType == XCB_KEY_RELEASE || + eventType == XCB_MOTION_NOTIFY || + eventType == XCB_ENTER_NOTIFY || + eventType == XCB_LEAVE_NOTIFY; + if (isInputEvent) + return true; + +#if QT_CONFIG(xcb_xinput) + if (connection()->hasXInput2()) { + isInputEvent = isXIType(event, m_xiOpCode, XCB_INPUT_BUTTON_PRESS) || + isXIType(event, m_xiOpCode, XCB_INPUT_BUTTON_RELEASE) || + isXIType(event, m_xiOpCode, XCB_INPUT_MOTION) || + isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_BEGIN) || + isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE) || + isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_END) || + isXIType(event, m_xiOpCode, XCB_INPUT_ENTER) || + isXIType(event, m_xiOpCode, XCB_INPUT_LEAVE) || + // wacom driver's way of reporting tool proximity + isXIType(event, m_xiOpCode, XCB_INPUT_PROPERTY); + } + if (isInputEvent) + return true; +#endif + + if (eventType == XCB_CLIENT_MESSAGE) { + auto clientMessage = reinterpret_cast(event); + if (clientMessage->format == 32 && clientMessage->type == atom(QXcbAtom::WM_PROTOCOLS)) + if (clientMessage->data.data32[0] == atom(QXcbAtom::WM_DELETE_WINDOW)) + isInputEvent = true; + } + + return isInputEvent; +} + +void QXcbConnection::processXcbEvents(QEventLoop::ProcessEventsFlags flags) { int connection_error = xcb_connection_has_error(xcb_connection()); if (connection_error) { @@ -1461,13 +1500,14 @@ void QXcbConnection::processXcbEvents() m_eventQueue->flushBufferedEvents(); - while (xcb_generic_event_t *event = m_eventQueue->takeFirst()) { + while (xcb_generic_event_t *event = m_eventQueue->takeFirst(flags)) { QScopedPointer eventGuard(event); if (!(event->response_type & ~0x80)) { handleXcbError(reinterpret_cast(event)); continue; } + if (compressEvent(event)) continue; diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 3fb64f01a4..96591c7994 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -475,6 +475,8 @@ public: Qt::MouseButtons queryMouseButtons() const; Qt::KeyboardModifiers queryKeyboardModifiers() const; + bool isUserInputEvent(xcb_generic_event_t *event) const; + #if QT_CONFIG(xcb_xinput) void xi2SelectStateEvents(); void xi2SelectDeviceEvents(xcb_window_t window); @@ -495,7 +497,7 @@ public: QXcbGlIntegration *glIntegration() const; void flush() { xcb_flush(m_connection); } - void processXcbEvents(); + void processXcbEvents(QEventLoop::ProcessEventsFlags flags); protected: bool event(QEvent *e) override; diff --git a/src/plugins/platforms/xcb/qxcbeventdispatcher.cpp b/src/plugins/platforms/xcb/qxcbeventdispatcher.cpp index 252c1c62e3..3cb2a5b5ef 100644 --- a/src/plugins/platforms/xcb/qxcbeventdispatcher.cpp +++ b/src/plugins/platforms/xcb/qxcbeventdispatcher.cpp @@ -58,7 +58,7 @@ QXcbUnixEventDispatcher::~QXcbUnixEventDispatcher() bool QXcbUnixEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) { const bool didSendEvents = QEventDispatcherUNIX::processEvents(flags); - m_connection->processXcbEvents(); + m_connection->processXcbEvents(flags); // The following line should not be necessary after QTBUG-70095 return QWindowSystemInterface::sendWindowSystemEvents(flags) || didSendEvents; } @@ -99,9 +99,10 @@ static gboolean xcbSourceCheck(GSource *source) static gboolean xcbSourceDispatch(GSource *source, GSourceFunc, gpointer) { auto xcbEventSource = reinterpret_cast(source); - xcbEventSource->connection->processXcbEvents(); + QEventLoop::ProcessEventsFlags flags = xcbEventSource->dispatcher->flags(); + xcbEventSource->connection->processXcbEvents(flags); // The following line should not be necessary after QTBUG-70095 - QWindowSystemInterface::sendWindowSystemEvents(xcbEventSource->dispatcher->flags()); + QWindowSystemInterface::sendWindowSystemEvents(flags); return true; } diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.cpp b/src/plugins/platforms/xcb/qxcbeventqueue.cpp index d7d70536a0..20589fc550 100644 --- a/src/plugins/platforms/xcb/qxcbeventqueue.cpp +++ b/src/plugins/platforms/xcb/qxcbeventqueue.cpp @@ -114,6 +114,35 @@ QXcbEventQueue::~QXcbEventQueue() qCDebug(lcQpaEventReader) << "nodes on heap:" << m_nodesOnHeap; } +xcb_generic_event_t *QXcbEventQueue::takeFirst(QEventLoop::ProcessEventsFlags flags) +{ + // This is the level at which we were moving excluded user input events into + // separate queue in Qt 4 (see qeventdispatcher_x11.cpp). In this case + // QXcbEventQueue represents Xlib's internal event queue. In Qt 4, Xlib's + // event queue peeking APIs would not see these events anymore, the same way + // our peeking functions do not consider m_inputEvents. This design is + // intentional to keep the same behavior. We could do filtering directly on + // QXcbEventQueue, without the m_inputEvents, but it is not clear if it is + // needed by anyone who peeks at the native event queue. + + bool excludeUserInputEvents = flags.testFlag(QEventLoop::ExcludeUserInputEvents); + if (excludeUserInputEvents) { + xcb_generic_event_t *event = nullptr; + while ((event = takeFirst())) { + if (m_connection->isUserInputEvent(event)) { + m_inputEvents << event; + continue; + } + break; + } + return event; + } + + if (!m_inputEvents.isEmpty()) + return m_inputEvents.takeFirst(); + return takeFirst(); +} + xcb_generic_event_t *QXcbEventQueue::takeFirst() { if (isEmpty()) diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.h b/src/plugins/platforms/xcb/qxcbeventqueue.h index 0096437dba..235f2824be 100644 --- a/src/plugins/platforms/xcb/qxcbeventqueue.h +++ b/src/plugins/platforms/xcb/qxcbeventqueue.h @@ -41,6 +41,8 @@ #include #include +#include +#include #include @@ -81,6 +83,7 @@ public: void run() override; bool isEmpty() const { return m_head == m_flushedTail && !m_head->event; } + xcb_generic_event_t *takeFirst(QEventLoop::ProcessEventsFlags flags); xcb_generic_event_t *takeFirst(); void flushBufferedEvents(); void wakeUpDispatcher(); @@ -124,6 +127,8 @@ private: bool m_peekerIndexCacheDirty = false; QHash m_peekerToNode; + QVector m_inputEvents; + // debug stats quint64 m_nodesOnHeap = 0; }; diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index d030b22fc8..9a7d193767 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -137,6 +137,8 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char m_instance = this; qApp->setAttribute(Qt::AA_CompressHighFrequencyEvents, true); + QWindowSystemInterface::setPlatformFiltersEvents(true); + qRegisterMetaType(); #if QT_CONFIG(xcb_xlib) XInitThreads(); -- cgit v1.2.3 From 8ff1ae89bfa32c586e3b44b71dfc49d294a3e043 Mon Sep 17 00:00:00 2001 From: Anton Kudryavtsev Date: Tue, 16 Oct 2018 12:06:29 +0300 Subject: QWindowsContext: proper check resolved function Change-Id: I9a223dc2efa2205dc3ae8d300cf06b12e06ed0f9 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowscontext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 7f1b7077f7..4959ed952d 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -148,7 +148,7 @@ static inline bool sessionManagerInteractionBlocked() { return false; } static inline int windowDpiAwareness(HWND hwnd) { - return QWindowsContext::user32dll.getWindowDpiAwarenessContext && QWindowsContext::user32dll.getWindowDpiAwarenessContext + return QWindowsContext::user32dll.getWindowDpiAwarenessContext && QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext ? QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext(QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd)) : -1; } -- cgit v1.2.3 From d67214302f269242ae3d8d2b962fd91ec42c979e Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Sat, 22 Sep 2018 13:14:23 +0200 Subject: xcb: qxcbconnection_basic A basic base class that creates a connection and initializes extensions. The goal was to reduce the size of qxcbconnection.h/cpp. Made QXcbAtom into a class that handles atom initialization and exposes the relevant APIs. Before this patch, all of that logic was inside of qxcbconnection.h/cpp. Change-Id: Ia893c3b31e2343dfbe62fe2aa6bfd0017abf46ea Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbatom.cpp | 287 +++++++++ src/plugins/platforms/xcb/qxcbatom.h | 267 ++++++++ src/plugins/platforms/xcb/qxcbbackingstore.cpp | 18 +- src/plugins/platforms/xcb/qxcbbackingstore.h | 2 +- src/plugins/platforms/xcb/qxcbconnection.cpp | 711 ++------------------- src/plugins/platforms/xcb/qxcbconnection.h | 329 +--------- src/plugins/platforms/xcb/qxcbconnection_basic.cpp | 437 +++++++++++++ src/plugins/platforms/xcb/qxcbconnection_basic.h | 175 +++++ src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | 61 +- src/plugins/platforms/xcb/qxcbeventqueue.cpp | 2 +- src/plugins/platforms/xcb/qxcbkeyboard.cpp | 39 +- src/plugins/platforms/xcb/qxcbkeyboard.h | 7 + src/plugins/platforms/xcb/xcb-plugin.pro | 1 + src/plugins/platforms/xcb/xcb_qpa_lib.pro | 8 +- 14 files changed, 1317 insertions(+), 1027 deletions(-) create mode 100644 src/plugins/platforms/xcb/qxcbatom.cpp create mode 100644 src/plugins/platforms/xcb/qxcbatom.h create mode 100644 src/plugins/platforms/xcb/qxcbconnection_basic.cpp create mode 100644 src/plugins/platforms/xcb/qxcbconnection_basic.h (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbatom.cpp b/src/plugins/platforms/xcb/qxcbatom.cpp new file mode 100644 index 0000000000..9255a57a4f --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbatom.cpp @@ -0,0 +1,287 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qxcbatom.h" + +#include + +#include + +#include + +static const char *xcb_atomnames = { + // window-manager <-> client protocols + "WM_PROTOCOLS\0" + "WM_DELETE_WINDOW\0" + "WM_TAKE_FOCUS\0" + "_NET_WM_PING\0" + "_NET_WM_CONTEXT_HELP\0" + "_NET_WM_SYNC_REQUEST\0" + "_NET_WM_SYNC_REQUEST_COUNTER\0" + "MANAGER\0" + "_NET_SYSTEM_TRAY_OPCODE\0" + + // ICCCM window state + "WM_STATE\0" + "WM_CHANGE_STATE\0" + "WM_CLASS\0" + "WM_NAME\0" + + // Session management + "WM_CLIENT_LEADER\0" + "WM_WINDOW_ROLE\0" + "SM_CLIENT_ID\0" + "WM_CLIENT_MACHINE\0" + + // Clipboard + "CLIPBOARD\0" + "INCR\0" + "TARGETS\0" + "MULTIPLE\0" + "TIMESTAMP\0" + "SAVE_TARGETS\0" + "CLIP_TEMPORARY\0" + "_QT_SELECTION\0" + "_QT_CLIPBOARD_SENTINEL\0" + "_QT_SELECTION_SENTINEL\0" + "CLIPBOARD_MANAGER\0" + + "RESOURCE_MANAGER\0" + + "_XSETROOT_ID\0" + + "_QT_SCROLL_DONE\0" + "_QT_INPUT_ENCODING\0" + + "_QT_CLOSE_CONNECTION\0" + + "_MOTIF_WM_HINTS\0" + + "DTWM_IS_RUNNING\0" + "ENLIGHTENMENT_DESKTOP\0" + "_DT_SAVE_MODE\0" + "_SGI_DESKS_MANAGER\0" + + // EWMH (aka NETWM) + "_NET_SUPPORTED\0" + "_NET_VIRTUAL_ROOTS\0" + "_NET_WORKAREA\0" + + "_NET_MOVERESIZE_WINDOW\0" + "_NET_WM_MOVERESIZE\0" + + "_NET_WM_NAME\0" + "_NET_WM_ICON_NAME\0" + "_NET_WM_ICON\0" + + "_NET_WM_PID\0" + + "_NET_WM_WINDOW_OPACITY\0" + + "_NET_WM_STATE\0" + "_NET_WM_STATE_ABOVE\0" + "_NET_WM_STATE_BELOW\0" + "_NET_WM_STATE_FULLSCREEN\0" + "_NET_WM_STATE_MAXIMIZED_HORZ\0" + "_NET_WM_STATE_MAXIMIZED_VERT\0" + "_NET_WM_STATE_MODAL\0" + "_NET_WM_STATE_STAYS_ON_TOP\0" + "_NET_WM_STATE_DEMANDS_ATTENTION\0" + + "_NET_WM_USER_TIME\0" + "_NET_WM_USER_TIME_WINDOW\0" + "_NET_WM_FULL_PLACEMENT\0" + + "_NET_WM_WINDOW_TYPE\0" + "_NET_WM_WINDOW_TYPE_DESKTOP\0" + "_NET_WM_WINDOW_TYPE_DOCK\0" + "_NET_WM_WINDOW_TYPE_TOOLBAR\0" + "_NET_WM_WINDOW_TYPE_MENU\0" + "_NET_WM_WINDOW_TYPE_UTILITY\0" + "_NET_WM_WINDOW_TYPE_SPLASH\0" + "_NET_WM_WINDOW_TYPE_DIALOG\0" + "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU\0" + "_NET_WM_WINDOW_TYPE_POPUP_MENU\0" + "_NET_WM_WINDOW_TYPE_TOOLTIP\0" + "_NET_WM_WINDOW_TYPE_NOTIFICATION\0" + "_NET_WM_WINDOW_TYPE_COMBO\0" + "_NET_WM_WINDOW_TYPE_DND\0" + "_NET_WM_WINDOW_TYPE_NORMAL\0" + "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE\0" + + "_KDE_NET_WM_FRAME_STRUT\0" + "_NET_FRAME_EXTENTS\0" + + "_NET_STARTUP_INFO\0" + "_NET_STARTUP_INFO_BEGIN\0" + + "_NET_SUPPORTING_WM_CHECK\0" + + "_NET_WM_CM_S0\0" + + "_NET_SYSTEM_TRAY_VISUAL\0" + + "_NET_ACTIVE_WINDOW\0" + + // Property formats + "TEXT\0" + "UTF8_STRING\0" + "CARDINAL\0" + + // xdnd + "XdndEnter\0" + "XdndPosition\0" + "XdndStatus\0" + "XdndLeave\0" + "XdndDrop\0" + "XdndFinished\0" + "XdndTypeList\0" + "XdndActionList\0" + + "XdndSelection\0" + + "XdndAware\0" + "XdndProxy\0" + + "XdndActionCopy\0" + "XdndActionLink\0" + "XdndActionMove\0" + "XdndActionPrivate\0" + + // Motif DND + "_MOTIF_DRAG_AND_DROP_MESSAGE\0" + "_MOTIF_DRAG_INITIATOR_INFO\0" + "_MOTIF_DRAG_RECEIVER_INFO\0" + "_MOTIF_DRAG_WINDOW\0" + "_MOTIF_DRAG_TARGETS\0" + + "XmTRANSFER_SUCCESS\0" + "XmTRANSFER_FAILURE\0" + + // Xkb + "_XKB_RULES_NAMES\0" + + // XEMBED + "_XEMBED\0" + "_XEMBED_INFO\0" + + // XInput2 + "Button Left\0" + "Button Middle\0" + "Button Right\0" + "Button Wheel Up\0" + "Button Wheel Down\0" + "Button Horiz Wheel Left\0" + "Button Horiz Wheel Right\0" + "Abs MT Position X\0" + "Abs MT Position Y\0" + "Abs MT Touch Major\0" + "Abs MT Touch Minor\0" + "Abs MT Orientation\0" + "Abs MT Pressure\0" + "Abs MT Tracking ID\0" + "Max Contacts\0" + "Rel X\0" + "Rel Y\0" + // XInput2 tablet + "Abs X\0" + "Abs Y\0" + "Abs Pressure\0" + "Abs Tilt X\0" + "Abs Tilt Y\0" + "Abs Wheel\0" + "Abs Distance\0" + "Wacom Serial IDs\0" + "INTEGER\0" + "Rel Horiz Wheel\0" + "Rel Vert Wheel\0" + "Rel Horiz Scroll\0" + "Rel Vert Scroll\0" + "_XSETTINGS_SETTINGS\0" + "_COMPIZ_DECOR_PENDING\0" + "_COMPIZ_DECOR_REQUEST\0" + "_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. +}; + +QXcbAtom::QXcbAtom() +{ +} + +void QXcbAtom::initialize(xcb_connection_t *connection) +{ + initializeAllAtoms(connection); +} + +void QXcbAtom::initializeAllAtoms(xcb_connection_t *connection) { + const char *names[QXcbAtom::NAtoms]; + const char *ptr = xcb_atomnames; + + int i = 0; + while (*ptr) { + names[i++] = ptr; + while (*ptr) + ++ptr; + ++ptr; + } + + Q_ASSERT(i == QXcbAtom::NAtoms); + + xcb_intern_atom_cookie_t cookies[QXcbAtom::NAtoms]; + + Q_ASSERT(i == QXcbAtom::NAtoms); + for (i = 0; i < QXcbAtom::NAtoms; ++i) + cookies[i] = xcb_intern_atom(connection, false, strlen(names[i]), names[i]); + + for (i = 0; i < QXcbAtom::NAtoms; ++i) { + xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, cookies[i], 0); + m_allAtoms[i] = reply->atom; + free(reply); + } +} + +QXcbAtom::Atom QXcbAtom::qatom(xcb_atom_t xatom) const +{ + return static_cast(std::find(m_allAtoms, m_allAtoms + QXcbAtom::NAtoms, xatom) - m_allAtoms); +} diff --git a/src/plugins/platforms/xcb/qxcbatom.h b/src/plugins/platforms/xcb/qxcbatom.h new file mode 100644 index 0000000000..b6cc159035 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbatom.h @@ -0,0 +1,267 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QXCBATOM_H +#define QXCBATOM_H + +#include + +class QXcbAtom +{ +public: + enum Atom { + // window-manager <-> client protocols + WM_PROTOCOLS, + WM_DELETE_WINDOW, + WM_TAKE_FOCUS, + _NET_WM_PING, + _NET_WM_CONTEXT_HELP, + _NET_WM_SYNC_REQUEST, + _NET_WM_SYNC_REQUEST_COUNTER, + MANAGER, // System tray notification + _NET_SYSTEM_TRAY_OPCODE, // System tray operation + + // ICCCM window state + WM_STATE, + WM_CHANGE_STATE, + WM_CLASS, + WM_NAME, + + // Session management + WM_CLIENT_LEADER, + WM_WINDOW_ROLE, + SM_CLIENT_ID, + WM_CLIENT_MACHINE, + + // Clipboard + CLIPBOARD, + INCR, + TARGETS, + MULTIPLE, + TIMESTAMP, + SAVE_TARGETS, + CLIP_TEMPORARY, + _QT_SELECTION, + _QT_CLIPBOARD_SENTINEL, + _QT_SELECTION_SENTINEL, + CLIPBOARD_MANAGER, + + RESOURCE_MANAGER, + + _XSETROOT_ID, + + _QT_SCROLL_DONE, + _QT_INPUT_ENCODING, + + // Qt/XCB specific + _QT_CLOSE_CONNECTION, + + _MOTIF_WM_HINTS, + + DTWM_IS_RUNNING, + ENLIGHTENMENT_DESKTOP, + _DT_SAVE_MODE, + _SGI_DESKS_MANAGER, + + // EWMH (aka NETWM) + _NET_SUPPORTED, + _NET_VIRTUAL_ROOTS, + _NET_WORKAREA, + + _NET_MOVERESIZE_WINDOW, + _NET_WM_MOVERESIZE, + + _NET_WM_NAME, + _NET_WM_ICON_NAME, + _NET_WM_ICON, + + _NET_WM_PID, + + _NET_WM_WINDOW_OPACITY, + + _NET_WM_STATE, + _NET_WM_STATE_ABOVE, + _NET_WM_STATE_BELOW, + _NET_WM_STATE_FULLSCREEN, + _NET_WM_STATE_MAXIMIZED_HORZ, + _NET_WM_STATE_MAXIMIZED_VERT, + _NET_WM_STATE_MODAL, + _NET_WM_STATE_STAYS_ON_TOP, + _NET_WM_STATE_DEMANDS_ATTENTION, + + _NET_WM_USER_TIME, + _NET_WM_USER_TIME_WINDOW, + _NET_WM_FULL_PLACEMENT, + + _NET_WM_WINDOW_TYPE, + _NET_WM_WINDOW_TYPE_DESKTOP, + _NET_WM_WINDOW_TYPE_DOCK, + _NET_WM_WINDOW_TYPE_TOOLBAR, + _NET_WM_WINDOW_TYPE_MENU, + _NET_WM_WINDOW_TYPE_UTILITY, + _NET_WM_WINDOW_TYPE_SPLASH, + _NET_WM_WINDOW_TYPE_DIALOG, + _NET_WM_WINDOW_TYPE_DROPDOWN_MENU, + _NET_WM_WINDOW_TYPE_POPUP_MENU, + _NET_WM_WINDOW_TYPE_TOOLTIP, + _NET_WM_WINDOW_TYPE_NOTIFICATION, + _NET_WM_WINDOW_TYPE_COMBO, + _NET_WM_WINDOW_TYPE_DND, + _NET_WM_WINDOW_TYPE_NORMAL, + _KDE_NET_WM_WINDOW_TYPE_OVERRIDE, + + _KDE_NET_WM_FRAME_STRUT, + _NET_FRAME_EXTENTS, + + _NET_STARTUP_INFO, + _NET_STARTUP_INFO_BEGIN, + + _NET_SUPPORTING_WM_CHECK, + + _NET_WM_CM_S0, + + _NET_SYSTEM_TRAY_VISUAL, + + _NET_ACTIVE_WINDOW, + + // Property formats + TEXT, + UTF8_STRING, + CARDINAL, + + // Xdnd + XdndEnter, + XdndPosition, + XdndStatus, + XdndLeave, + XdndDrop, + XdndFinished, + XdndTypelist, + XdndActionList, + + XdndSelection, + + XdndAware, + XdndProxy, + + XdndActionCopy, + XdndActionLink, + XdndActionMove, + XdndActionPrivate, + + // Motif DND + _MOTIF_DRAG_AND_DROP_MESSAGE, + _MOTIF_DRAG_INITIATOR_INFO, + _MOTIF_DRAG_RECEIVER_INFO, + _MOTIF_DRAG_WINDOW, + _MOTIF_DRAG_TARGETS, + + XmTRANSFER_SUCCESS, + XmTRANSFER_FAILURE, + + // Xkb + _XKB_RULES_NAMES, + + // XEMBED + _XEMBED, + _XEMBED_INFO, + + // XInput2 + ButtonLeft, + ButtonMiddle, + ButtonRight, + ButtonWheelUp, + ButtonWheelDown, + ButtonHorizWheelLeft, + ButtonHorizWheelRight, + AbsMTPositionX, + AbsMTPositionY, + AbsMTTouchMajor, + AbsMTTouchMinor, + AbsMTOrientation, + AbsMTPressure, + AbsMTTrackingID, + MaxContacts, + RelX, + RelY, + // XInput2 tablet + AbsX, + AbsY, + AbsPressure, + AbsTiltX, + AbsTiltY, + AbsWheel, + AbsDistance, + WacomSerialIDs, + INTEGER, + RelHorizWheel, + RelVertWheel, + RelHorizScroll, + RelVertScroll, + + _XSETTINGS_SETTINGS, + + _COMPIZ_DECOR_PENDING, + _COMPIZ_DECOR_REQUEST, + _COMPIZ_DECOR_DELETE_PIXMAP, + _COMPIZ_TOOLKIT_ACTION, + _GTK_LOAD_ICONTHEMES, + + AT_SPI_BUS, + + EDID, + EDID_DATA, + XFree86_DDC_EDID1_RAWDATA, + + NAtoms + }; + + QXcbAtom(); + void initialize(xcb_connection_t *connection); + + inline xcb_atom_t atom(QXcbAtom::Atom atom) const { return m_allAtoms[atom]; } + QXcbAtom::Atom qatom(xcb_atom_t atom) const; + +protected: + void initializeAllAtoms(xcb_connection_t *connection); + +private: + xcb_atom_t m_allAtoms[QXcbAtom::NAtoms]; +}; + +#endif // QXCBATOM_H diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index c29eb29b7e..c8c806749f 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -106,7 +106,7 @@ public: void put(xcb_drawable_t dst, const QRegion ®ion, const QPoint &offset); void preparePaint(const QRegion ®ion); - static bool createSystemVShmSegment(QXcbConnection *c, size_t segmentSize = 1, + static bool createSystemVShmSegment(xcb_connection_t *c, size_t segmentSize = 1, xcb_shm_segment_info_t *shm_info = nullptr); private: @@ -406,12 +406,12 @@ void QXcbBackingStoreImage::createShmSegment(size_t segmentSize) } else #endif { - if (createSystemVShmSegment(connection(), segmentSize, &m_shm_info)) + if (createSystemVShmSegment(xcb_connection(), segmentSize, &m_shm_info)) m_segmentSize = segmentSize; } } -bool QXcbBackingStoreImage::createSystemVShmSegment(QXcbConnection *c, size_t segmentSize, +bool QXcbBackingStoreImage::createSystemVShmSegment(xcb_connection_t *c, size_t segmentSize, xcb_shm_segment_info_t *shmInfo) { const int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0600); @@ -429,17 +429,17 @@ bool QXcbBackingStoreImage::createSystemVShmSegment(QXcbConnection *c, size_t se if (shmctl(id, IPC_RMID, 0) == -1) qCWarning(lcQpaXcb, "Error while marking the shared memory segment to be destroyed"); - const auto seg = xcb_generate_id(c->xcb_connection()); - auto cookie = xcb_shm_attach_checked(c->xcb_connection(), seg, id, false); - auto *error = xcb_request_check(c->xcb_connection(), cookie); + const auto seg = xcb_generate_id(c); + auto cookie = xcb_shm_attach_checked(c, seg, id, false); + auto *error = xcb_request_check(c, cookie); if (error) { - c->printXcbError("xcb_shm_attach() failed with error", error); + qCWarning(lcQpaXcb(), "xcb_shm_attach() failed"); free(error); if (shmdt(addr) == -1) qCWarning(lcQpaXcb, "shmdt() failed (%d: %s) for %p", errno, strerror(errno), addr); return false; } else if (!shmInfo) { // this was a test run, free the allocated test segment - xcb_shm_detach(c->xcb_connection(), seg); + xcb_shm_detach(c, seg); auto shmaddr = static_cast(addr); if (shmdt(shmaddr) == -1) qCWarning(lcQpaXcb, "shmdt() failed (%d: %s) for %p", errno, strerror(errno), shmaddr); @@ -766,7 +766,7 @@ void QXcbBackingStoreImage::preparePaint(const QRegion ®ion) m_pendingFlush |= region; } -bool QXcbBackingStore::createSystemVShmSegment(QXcbConnection *c, size_t segmentSize, void *shmInfo) +bool QXcbBackingStore::createSystemVShmSegment(xcb_connection_t *c, size_t segmentSize, void *shmInfo) { auto info = reinterpret_cast(shmInfo); return QXcbBackingStoreImage::createSystemVShmSegment(c, segmentSize, info); diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.h b/src/plugins/platforms/xcb/qxcbbackingstore.h index 39d023cb9d..b91e5c7dc2 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.h +++ b/src/plugins/platforms/xcb/qxcbbackingstore.h @@ -74,7 +74,7 @@ public: void beginPaint(const QRegion &) override; void endPaint() override; - static bool createSystemVShmSegment(QXcbConnection *c, size_t segmentSize = 1, + static bool createSystemVShmSegment(xcb_connection_t *c, size_t segmentSize = 1, void *shmInfo = nullptr); protected: diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index a4294956c1..10d07c37bb 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -59,38 +59,24 @@ #include "qxcbbackingstore.h" #include "qxcbeventqueue.h" -#include #include -#include #include #include -#include - #include #include -#include -#include + #include #include - -#if QT_CONFIG(xcb_xlib) -#define register /* C++17 deprecated register */ -#include -#include -#include -#include -#undef register +#if QT_CONFIG(xkb) +#define explicit dont_use_cxx_explicit +#include +#undef explicit #endif - #if QT_CONFIG(xcb_xinput) #include #endif -#if QT_CONFIG(xcb_render) -#include -#endif - QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcQpaXInput, "qt.qpa.input") @@ -99,7 +85,6 @@ Q_LOGGING_CATEGORY(lcQpaXInputEvents, "qt.qpa.input.events") Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen") Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events") Q_LOGGING_CATEGORY(lcQpaEventReader, "qt.qpa.events.reader") -Q_LOGGING_CATEGORY(lcQpaXcb, "qt.qpa.xcb") // for general (uncategorized) XCB logging Q_LOGGING_CATEGORY(lcQpaPeeker, "qt.qpa.peeker") Q_LOGGING_CATEGORY(lcQpaKeyboard, "qt.qpa.xkeyboard") Q_LOGGING_CATEGORY(lcQpaXDnd, "qt.qpa.xdnd") @@ -110,69 +95,19 @@ Q_LOGGING_CATEGORY(lcQpaXDnd, "qt.qpa.xdnd") #define XCB_GE_GENERIC 35 #endif -#if QT_CONFIG(xcb_xinput) -// Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed: -// - "pad0" became "extension" -// - "pad1" and "pad" became "pad0" -// New and old version of this struct share the following fields: -typedef struct qt_xcb_ge_event_t { - uint8_t response_type; - uint8_t extension; - uint16_t sequence; - uint32_t length; - uint16_t event_type; -} qt_xcb_ge_event_t; - -static inline bool isXIEvent(xcb_generic_event_t *event, int opCode) -{ - qt_xcb_ge_event_t *e = reinterpret_cast(event); - return e->extension == opCode; -} -#endif // QT_CONFIG(xcb_xinput) - -#if QT_CONFIG(xcb_xlib) -static const char * const xcbConnectionErrors[] = { - "No error", /* Error 0 */ - "I/O error", /* XCB_CONN_ERROR */ - "Unsupported extension used", /* XCB_CONN_CLOSED_EXT_NOTSUPPORTED */ - "Out of memory", /* XCB_CONN_CLOSED_MEM_INSUFFICIENT */ - "Maximum allowed requested length exceeded", /* XCB_CONN_CLOSED_REQ_LEN_EXCEED */ - "Failed to parse display string", /* XCB_CONN_CLOSED_PARSE_ERR */ - "No such screen on display", /* XCB_CONN_CLOSED_INVALID_SCREEN */ - "Error during FD passing" /* XCB_CONN_CLOSED_FDPASSING_FAILED */ -}; - -static int nullErrorHandler(Display *dpy, XErrorEvent *err) -{ -#ifndef Q_XCB_DEBUG - Q_UNUSED(dpy); - Q_UNUSED(err); -#else - const int buflen = 1024; - char buf[buflen]; - - XGetErrorText(dpy, err->error_code, buf, buflen); - fprintf(stderr, "X Error: serial %lu error %d %s\n", err->serial, (int) err->error_code, buf); -#endif - return 0; -} - -static int ioErrorHandler(Display *dpy) +void QXcbConnection::selectXRandrEvents() { - xcb_connection_t *conn = XGetXCBConnection(dpy); - if (conn != NULL) { - /* Print a message with a textual description of the error */ - int code = xcb_connection_has_error(conn); - const char *str = "Unknown error"; - int arrayLength = sizeof(xcbConnectionErrors) / sizeof(xcbConnectionErrors[0]); - if (code >= 0 && code < arrayLength) - str = xcbConnectionErrors[code]; - - qWarning("The X11 connection broke: %s (code %d)", str, code); + xcb_screen_iterator_t rootIter = xcb_setup_roots_iterator(setup()); + for (; rootIter.rem; xcb_screen_next(&rootIter)) { + xcb_randr_select_input(xcb_connection(), + rootIter.data->root, + XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE | + XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE | + XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE | + XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY + ); } - return _XDefaultIOError(dpy); } -#endif QXcbScreen* QXcbConnection::findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc) const { @@ -314,7 +249,7 @@ void QXcbConnection::updateScreen(QXcbScreen *screen, const xcb_randr_output_cha if (screen->mode() != outputChange.mode) screen->updateRefreshRate(outputChange.mode); // Only screen which belongs to the primary virtual desktop can be a primary screen - if (screen->screenNumber() == m_primaryScreenNumber) { + if (screen->screenNumber() == primaryScreenNumber()) { if (!screen->isPrimary() && checkOutputIsPrimary(outputChange.window, outputChange.output)) { screen->setPrimary(true); @@ -336,7 +271,7 @@ QXcbScreen *QXcbConnection::createScreen(QXcbVirtualDesktop *virtualDesktop, { QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, outputChange.output, outputInfo); // Only screen which belongs to the primary virtual desktop can be a primary screen - if (screen->screenNumber() == m_primaryScreenNumber) + if (screen->screenNumber() == primaryScreenNumber()) screen->setPrimary(checkOutputIsPrimary(outputChange.window, outputChange.output)); if (screen->isPrimary()) { @@ -384,7 +319,7 @@ void QXcbConnection::destroyScreen(QXcbScreen *screen) void QXcbConnection::initializeScreens() { - xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup); + xcb_screen_iterator_t it = xcb_setup_roots_iterator(setup()); int xcbScreenNumber = 0; // screen number in the xcb sense QXcbScreen *primaryScreen = nullptr; while (it.rem) { @@ -396,7 +331,7 @@ void QXcbConnection::initializeScreens() QXcbVirtualDesktop *virtualDesktop = new QXcbVirtualDesktop(this, xcbScreen, xcbScreenNumber); m_virtualDesktops.append(virtualDesktop); QList siblings; - if (has_randr_extension) { + if (hasXRender()) { // RRGetScreenResourcesCurrent is fast but it may return nothing if the // configuration is not initialized wrt to the hardware. We should call // RRGetScreenResources in this case. @@ -457,7 +392,7 @@ void QXcbConnection::initializeScreens() // the first or an exact match. An exact match isn't // always available if primary->output is XCB_NONE // or currently disconnected output. - if (m_primaryScreenNumber == xcbScreenNumber) { + if (primaryScreenNumber() == xcbScreenNumber) { if (!primaryScreen || (primary && outputs[i] == primary->output)) { if (primaryScreen) primaryScreen->setPrimary(false); @@ -470,9 +405,9 @@ void QXcbConnection::initializeScreens() } } } - } else if (has_xinerama_extension) { + } else if (hasXinerama()) { // Xinerama is available - auto screens = Q_XCB_REPLY(xcb_xinerama_query_screens, m_connection); + auto screens = Q_XCB_REPLY(xcb_xinerama_query_screens, xcb_connection()); if (screens) { xcb_xinerama_screen_info_iterator_t it = xcb_xinerama_query_screens_screen_info_iterator(screens.get()); while (it.rem) { @@ -492,7 +427,7 @@ void QXcbConnection::initializeScreens() QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, XCB_NONE, nullptr); qCDebug(lcQpaScreen) << "created fake screen" << screen; m_screens << screen; - if (m_primaryScreenNumber == xcbScreenNumber) { + if (primaryScreenNumber() == xcbScreenNumber) { primaryScreen = screen; primaryScreen->setPrimary(true); } @@ -528,72 +463,28 @@ void QXcbConnection::initializeScreens() } QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, xcb_visualid_t defaultVisualId, const char *displayName) - : m_canGrabServer(canGrabServer) + : QXcbBasicConnection(displayName) + , m_canGrabServer(canGrabServer) , m_defaultVisualId(defaultVisualId) - , m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY")) , m_nativeInterface(nativeInterface) { -#if QT_CONFIG(xcb_xlib) - Display *dpy = XOpenDisplay(m_displayName.constData()); - if (dpy) { - m_primaryScreenNumber = DefaultScreen(dpy); - m_connection = XGetXCBConnection(dpy); - XSetEventQueueOwner(dpy, XCBOwnsEventQueue); - XSetErrorHandler(nullErrorHandler); - XSetIOErrorHandler(ioErrorHandler); - m_xlib_display = dpy; - } -#else - m_connection = xcb_connect(m_displayName.constData(), &m_primaryScreenNumber); -#endif // QT_CONFIG(xcb_xlib) - - if (Q_UNLIKELY(!m_connection || xcb_connection_has_error(m_connection))) { - qCWarning(lcQpaScreen, "QXcbConnection: Could not connect to display %s", m_displayName.constData()); + if (!isConnected()) return; - } m_eventQueue = new QXcbEventQueue(this); - xcb_extension_t *extensions[] = { - &xcb_shm_id, &xcb_xfixes_id, &xcb_randr_id, &xcb_shape_id, &xcb_sync_id, -#if QT_CONFIG(xkb) - &xcb_xkb_id, -#endif -#if QT_CONFIG(xcb_render) - &xcb_render_id, -#endif -#if QT_CONFIG(xcb_xinput) - &xcb_input_id, -#endif - 0 - }; - - for (xcb_extension_t **ext_it = extensions; *ext_it; ++ext_it) - xcb_prefetch_extension_data (m_connection, *ext_it); - - m_setup = xcb_get_setup(xcb_connection()); - m_xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP").toLower(); - initializeAllAtoms(); + selectXRandrEvents(); - initializeXSync(); - if (!qEnvironmentVariableIsSet("QT_XCB_NO_MITSHM")) - initializeShm(); - if (!qEnvironmentVariableIsSet("QT_XCB_NO_XRANDR")) - initializeXRandr(); - if (!has_randr_extension) - initializeXinerama(); - initializeXFixes(); initializeScreens(); - initializeXRender(); #if QT_CONFIG(xcb_xinput) - if (!qEnvironmentVariableIsSet("QT_XCB_NO_XI2")) - initializeXInput2(); + if (hasXInput2()) { + xi2SetupDevices(); + xi2SelectStateEvents(); + } #endif - initializeXShape(); - initializeXKB(); m_wmSupport.reset(new QXcbWMSupport(this)); m_keyboard = new QXcbKeyboard(this); @@ -632,22 +523,9 @@ QXcbConnection::~QXcbConnection() delete m_glIntegration; - if (isConnected()) { -#if QT_CONFIG(xcb_xlib) - XCloseDisplay(static_cast(m_xlib_display)); -#else - xcb_disconnect(xcb_connection()); -#endif - } - delete m_keyboard; } -bool QXcbConnection::isConnected() const -{ - return m_connection && !xcb_connection_has_error(m_connection); -} - QXcbScreen *QXcbConnection::primaryScreen() const { if (!m_screens.isEmpty()) { @@ -752,17 +630,17 @@ void QXcbConnection::printXcbEvent(const QLoggingCategory &log, const char *mess CASE_PRINT_AND_RETURN( XCB_GE_GENERIC ); } // XFixes - if (has_xfixes && response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) + if (isXFixesType(response_type, XCB_XFIXES_SELECTION_NOTIFY)) PRINT_AND_RETURN("XCB_XFIXES_SELECTION_NOTIFY"); + // XRandR - if (has_randr_extension) { - if (response_type == xrandr_first_event + XCB_RANDR_NOTIFY) - PRINT_AND_RETURN("XCB_RANDR_NOTIFY"); - if (response_type == xrandr_first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) - PRINT_AND_RETURN("XCB_RANDR_SCREEN_CHANGE_NOTIFY"); - } + if (isXRandrType(response_type, XCB_RANDR_NOTIFY)) + PRINT_AND_RETURN("XCB_RANDR_NOTIFY"); + if (isXRandrType(response_type, XCB_RANDR_SCREEN_CHANGE_NOTIFY)) + PRINT_AND_RETURN("XCB_RANDR_SCREEN_CHANGE_NOTIFY"); + // XKB - if (response_type == xkb_first_event) + if (isXkbType(response_type)) PRINT_AND_RETURN("XCB_XKB_* event"); // UNKNOWN @@ -1155,7 +1033,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) #if QT_CONFIG(xcb_xinput) case XCB_GE_GENERIC: // Here the windowEventListener is invoked from xi2HandleEvent() - if (hasXInput2() && isXIEvent(event, m_xiOpCode)) + if (hasXInput2() && isXIEvent(event)) xi2HandleEvent(reinterpret_cast(event)); break; #endif @@ -1168,7 +1046,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) return; handled = true; - if (has_xfixes && response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) { + if (isXFixesType(response_type, XCB_XFIXES_SELECTION_NOTIFY)) { auto notify_event = reinterpret_cast(event); setTime(notify_event->timestamp); #ifndef QT_NO_CLIPBOARD @@ -1176,14 +1054,14 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) #endif for (QXcbVirtualDesktop *virtualDesktop : qAsConst(m_virtualDesktops)) virtualDesktop->handleXFixesSelectionNotify(notify_event); - } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_NOTIFY) { + } else if (isXRandrType(response_type, XCB_RANDR_NOTIFY)) { updateScreens(reinterpret_cast(event)); - } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) { + } else if (isXRandrType(response_type, XCB_RANDR_SCREEN_CHANGE_NOTIFY)) { auto change_event = reinterpret_cast(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 + } else if (isXkbType(response_type)) { auto xkb_event = reinterpret_cast<_xkb_event *>(event); if (xkb_event->any.deviceID == m_keyboard->coreDeviceId()) { switch (xkb_event->any.xkbType) { @@ -1239,13 +1117,13 @@ void QXcbConnection::setMousePressWindow(QXcbWindow *w) void QXcbConnection::grabServer() { if (m_canGrabServer) - xcb_grab_server(m_connection); + xcb_grab_server(xcb_connection()); } void QXcbConnection::ungrabServer() { if (m_canGrabServer) - xcb_ungrab_server(m_connection); + xcb_ungrab_server(xcb_connection()); } xcb_timestamp_t QXcbConnection::getTimestamp() @@ -1360,17 +1238,6 @@ xcb_window_t QXcbConnection::clientLeader() return m_clientLeader; } -#if QT_CONFIG(xcb_xinput) -static inline bool isXIType(xcb_generic_event_t *event, int opCode, uint16_t type) -{ - if (!isXIEvent(event, opCode)) - return false; - - auto *e = reinterpret_cast(event); - return e->event_type == type; -} -#endif - /*! \internal Compresses events of the same type to avoid swamping the event queue. @@ -1405,7 +1272,7 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event) const return false; // compress XI_Motion - if (isXIType(event, m_xiOpCode, XCB_INPUT_MOTION)) { + if (isXIType(event, XCB_INPUT_MOTION)) { #if QT_CONFIG(tabletevent) auto xdev = reinterpret_cast(event); if (!QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents) && @@ -1414,17 +1281,18 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event) const #endif // QT_CONFIG(tabletevent) return m_eventQueue->peek(QXcbEventQueue::PeekRetainMatch, [this](xcb_generic_event_t *next, int) { - return isXIType(next, m_xiOpCode, XCB_INPUT_MOTION); + return isXIType(next, XCB_INPUT_MOTION); }); } // compress XI_TouchUpdate for the same touch point id - if (isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE)) { + if (isXIType(event, XCB_INPUT_TOUCH_UPDATE)) { auto touchUpdateEvent = reinterpret_cast(event); uint32_t id = touchUpdateEvent->detail % INT_MAX; + return m_eventQueue->peek(QXcbEventQueue::PeekRetainMatch, [this, &id](xcb_generic_event_t *next, int) { - if (!isXIType(next, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE)) + if (!isXIType(next, XCB_INPUT_TOUCH_UPDATE)) return false; auto touchUpdateNextEvent = reinterpret_cast(next); return id == touchUpdateNextEvent->detail % INT_MAX; @@ -1465,16 +1333,16 @@ bool QXcbConnection::isUserInputEvent(xcb_generic_event_t *event) const #if QT_CONFIG(xcb_xinput) if (connection()->hasXInput2()) { - isInputEvent = isXIType(event, m_xiOpCode, XCB_INPUT_BUTTON_PRESS) || - isXIType(event, m_xiOpCode, XCB_INPUT_BUTTON_RELEASE) || - isXIType(event, m_xiOpCode, XCB_INPUT_MOTION) || - isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_BEGIN) || - isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE) || - isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_END) || - isXIType(event, m_xiOpCode, XCB_INPUT_ENTER) || - isXIType(event, m_xiOpCode, XCB_INPUT_LEAVE) || + isInputEvent = isXIType(event, XCB_INPUT_BUTTON_PRESS) || + isXIType(event, XCB_INPUT_BUTTON_RELEASE) || + isXIType(event, XCB_INPUT_MOTION) || + isXIType(event, XCB_INPUT_TOUCH_BEGIN) || + isXIType(event, XCB_INPUT_TOUCH_UPDATE) || + isXIType(event, XCB_INPUT_TOUCH_END) || + isXIType(event, XCB_INPUT_ENTER) || + isXIType(event, XCB_INPUT_LEAVE) || // wacom driver's way of reporting tool proximity - isXIType(event, m_xiOpCode, XCB_INPUT_PROPERTY); + isXIType(event, XCB_INPUT_PROPERTY); } if (isInputEvent) return true; @@ -1545,265 +1413,10 @@ void QXcbConnection::processXcbEvents(QEventLoop::ProcessEventsFlags flags) xcb_flush(xcb_connection()); } -static const char * xcb_atomnames = { - // window-manager <-> client protocols - "WM_PROTOCOLS\0" - "WM_DELETE_WINDOW\0" - "WM_TAKE_FOCUS\0" - "_NET_WM_PING\0" - "_NET_WM_CONTEXT_HELP\0" - "_NET_WM_SYNC_REQUEST\0" - "_NET_WM_SYNC_REQUEST_COUNTER\0" - "MANAGER\0" - "_NET_SYSTEM_TRAY_OPCODE\0" - - // ICCCM window state - "WM_STATE\0" - "WM_CHANGE_STATE\0" - "WM_CLASS\0" - "WM_NAME\0" - - // Session management - "WM_CLIENT_LEADER\0" - "WM_WINDOW_ROLE\0" - "SM_CLIENT_ID\0" - "WM_CLIENT_MACHINE\0" - - // Clipboard - "CLIPBOARD\0" - "INCR\0" - "TARGETS\0" - "MULTIPLE\0" - "TIMESTAMP\0" - "SAVE_TARGETS\0" - "CLIP_TEMPORARY\0" - "_QT_SELECTION\0" - "_QT_CLIPBOARD_SENTINEL\0" - "_QT_SELECTION_SENTINEL\0" - "CLIPBOARD_MANAGER\0" - - "RESOURCE_MANAGER\0" - - "_XSETROOT_ID\0" - - "_QT_SCROLL_DONE\0" - "_QT_INPUT_ENCODING\0" - - "_QT_CLOSE_CONNECTION\0" - - "_MOTIF_WM_HINTS\0" - - "DTWM_IS_RUNNING\0" - "ENLIGHTENMENT_DESKTOP\0" - "_DT_SAVE_MODE\0" - "_SGI_DESKS_MANAGER\0" - - // EWMH (aka NETWM) - "_NET_SUPPORTED\0" - "_NET_VIRTUAL_ROOTS\0" - "_NET_WORKAREA\0" - - "_NET_MOVERESIZE_WINDOW\0" - "_NET_WM_MOVERESIZE\0" - - "_NET_WM_NAME\0" - "_NET_WM_ICON_NAME\0" - "_NET_WM_ICON\0" - - "_NET_WM_PID\0" - - "_NET_WM_WINDOW_OPACITY\0" - - "_NET_WM_STATE\0" - "_NET_WM_STATE_ABOVE\0" - "_NET_WM_STATE_BELOW\0" - "_NET_WM_STATE_FULLSCREEN\0" - "_NET_WM_STATE_MAXIMIZED_HORZ\0" - "_NET_WM_STATE_MAXIMIZED_VERT\0" - "_NET_WM_STATE_MODAL\0" - "_NET_WM_STATE_STAYS_ON_TOP\0" - "_NET_WM_STATE_DEMANDS_ATTENTION\0" - - "_NET_WM_USER_TIME\0" - "_NET_WM_USER_TIME_WINDOW\0" - "_NET_WM_FULL_PLACEMENT\0" - - "_NET_WM_WINDOW_TYPE\0" - "_NET_WM_WINDOW_TYPE_DESKTOP\0" - "_NET_WM_WINDOW_TYPE_DOCK\0" - "_NET_WM_WINDOW_TYPE_TOOLBAR\0" - "_NET_WM_WINDOW_TYPE_MENU\0" - "_NET_WM_WINDOW_TYPE_UTILITY\0" - "_NET_WM_WINDOW_TYPE_SPLASH\0" - "_NET_WM_WINDOW_TYPE_DIALOG\0" - "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU\0" - "_NET_WM_WINDOW_TYPE_POPUP_MENU\0" - "_NET_WM_WINDOW_TYPE_TOOLTIP\0" - "_NET_WM_WINDOW_TYPE_NOTIFICATION\0" - "_NET_WM_WINDOW_TYPE_COMBO\0" - "_NET_WM_WINDOW_TYPE_DND\0" - "_NET_WM_WINDOW_TYPE_NORMAL\0" - "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE\0" - - "_KDE_NET_WM_FRAME_STRUT\0" - "_NET_FRAME_EXTENTS\0" - - "_NET_STARTUP_INFO\0" - "_NET_STARTUP_INFO_BEGIN\0" - - "_NET_SUPPORTING_WM_CHECK\0" - - "_NET_WM_CM_S0\0" - - "_NET_SYSTEM_TRAY_VISUAL\0" - - "_NET_ACTIVE_WINDOW\0" - - // Property formats - "TEXT\0" - "UTF8_STRING\0" - "CARDINAL\0" - - // xdnd - "XdndEnter\0" - "XdndPosition\0" - "XdndStatus\0" - "XdndLeave\0" - "XdndDrop\0" - "XdndFinished\0" - "XdndTypeList\0" - "XdndActionList\0" - - "XdndSelection\0" - - "XdndAware\0" - "XdndProxy\0" - - "XdndActionCopy\0" - "XdndActionLink\0" - "XdndActionMove\0" - "XdndActionPrivate\0" - - // Motif DND - "_MOTIF_DRAG_AND_DROP_MESSAGE\0" - "_MOTIF_DRAG_INITIATOR_INFO\0" - "_MOTIF_DRAG_RECEIVER_INFO\0" - "_MOTIF_DRAG_WINDOW\0" - "_MOTIF_DRAG_TARGETS\0" - - "XmTRANSFER_SUCCESS\0" - "XmTRANSFER_FAILURE\0" - - // Xkb - "_XKB_RULES_NAMES\0" - - // XEMBED - "_XEMBED\0" - "_XEMBED_INFO\0" - - // XInput2 - "Button Left\0" - "Button Middle\0" - "Button Right\0" - "Button Wheel Up\0" - "Button Wheel Down\0" - "Button Horiz Wheel Left\0" - "Button Horiz Wheel Right\0" - "Abs MT Position X\0" - "Abs MT Position Y\0" - "Abs MT Touch Major\0" - "Abs MT Touch Minor\0" - "Abs MT Orientation\0" - "Abs MT Pressure\0" - "Abs MT Tracking ID\0" - "Max Contacts\0" - "Rel X\0" - "Rel Y\0" - // XInput2 tablet - "Abs X\0" - "Abs Y\0" - "Abs Pressure\0" - "Abs Tilt X\0" - "Abs Tilt Y\0" - "Abs Wheel\0" - "Abs Distance\0" - "Wacom Serial IDs\0" - "INTEGER\0" - "Rel Horiz Wheel\0" - "Rel Vert Wheel\0" - "Rel Horiz Scroll\0" - "Rel Vert Scroll\0" - "_XSETTINGS_SETTINGS\0" - "_COMPIZ_DECOR_PENDING\0" - "_COMPIZ_DECOR_REQUEST\0" - "_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. -}; - -QXcbAtom::Atom QXcbConnection::qatom(xcb_atom_t xatom) const -{ - return static_cast(std::find(m_allAtoms, m_allAtoms + QXcbAtom::NAtoms, xatom) - m_allAtoms); -} - -void QXcbConnection::initializeAllAtoms() { - const char *names[QXcbAtom::NAtoms]; - const char *ptr = xcb_atomnames; - - int i = 0; - while (*ptr) { - names[i++] = ptr; - while (*ptr) - ++ptr; - ++ptr; - } - - Q_ASSERT(i == QXcbAtom::NAtoms); - - xcb_intern_atom_cookie_t cookies[QXcbAtom::NAtoms]; - - Q_ASSERT(i == QXcbAtom::NAtoms); - for (i = 0; i < QXcbAtom::NAtoms; ++i) - cookies[i] = xcb_intern_atom(xcb_connection(), false, strlen(names[i]), names[i]); - - for (i = 0; i < QXcbAtom::NAtoms; ++i) { - xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcb_connection(), cookies[i], 0); - m_allAtoms[i] = reply->atom; - free(reply); - } -} - -xcb_atom_t QXcbConnection::internAtom(const char *name) -{ - if (!name || *name == 0) - return XCB_NONE; - - return Q_XCB_REPLY(xcb_intern_atom, xcb_connection(), false, strlen(name), name)->atom; -} - -QByteArray QXcbConnection::atomName(xcb_atom_t atom) -{ - if (!atom) - return QByteArray(); - - auto reply = Q_XCB_REPLY(xcb_get_atom_name, xcb_connection(), atom); - if (!reply) - qWarning() << "QXcbConnection::atomName: bad Atom" << atom; - else - return QByteArray(xcb_get_atom_name_name(reply.get()), xcb_get_atom_name_name_length(reply.get())); - - return QByteArray(); -} - const xcb_format_t *QXcbConnection::formatForDepth(uint8_t depth) const { xcb_format_iterator_t iterator = - xcb_setup_pixmap_formats_iterator(m_setup); + xcb_setup_pixmap_formats_iterator(setup()); while (iterator.rem) { xcb_format_t *format = iterator.data; @@ -1823,208 +1436,6 @@ void QXcbConnection::sync() free(xcb_get_input_focus_reply(xcb_connection(), cookie, 0)); } -void QXcbConnection::initializeShm() -{ - const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_shm_id); - if (!reply || !reply->present) { - qCDebug(lcQpaXcb, "MIT-SHM extension is not present on the X server"); - return; - } - has_shm = true; - - auto shm_query = Q_XCB_REPLY(xcb_shm_query_version, m_connection); - if (shm_query) { - has_shm_fd = (shm_query->major_version == 1 && shm_query->minor_version >= 2) || - shm_query->major_version > 1; - } else { - qCWarning(lcQpaXcb, "QXcbConnection: Failed to request MIT-SHM version"); - } - - qCDebug(lcQpaXcb) << "Has MIT-SHM :" << has_shm; - qCDebug(lcQpaXcb) << "Has MIT-SHM FD :" << has_shm_fd; - - // Temporary disable warnings (unless running in debug mode). - auto logging = const_cast(&lcQpaXcb()); - bool wasEnabled = logging->isEnabled(QtMsgType::QtWarningMsg); - if (!logging->isEnabled(QtMsgType::QtDebugMsg)) - logging->setEnabled(QtMsgType::QtWarningMsg, false); - if (!QXcbBackingStore::createSystemVShmSegment(this)) { - qCDebug(lcQpaXcb, "failed to create System V shared memory segment (remote " - "X11 connection?), disabling SHM"); - has_shm = has_shm_fd = false; - } - if (wasEnabled) - logging->setEnabled(QtMsgType::QtWarningMsg, true); -} - -void QXcbConnection::initializeXFixes() -{ - const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xfixes_id); - if (!reply || !reply->present) - return; - - auto xfixes_query = Q_XCB_REPLY(xcb_xfixes_query_version, m_connection, - XCB_XFIXES_MAJOR_VERSION, - XCB_XFIXES_MINOR_VERSION); - if (!xfixes_query || xfixes_query->major_version < 2) { - qWarning("QXcbConnection: Failed to initialize XFixes"); - return; - } - xfixes_first_event = reply->first_event; - has_xfixes = true; -} - -void QXcbConnection::initializeXRender() -{ -#if QT_CONFIG(xcb_render) - const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_render_id); - if (!reply || !reply->present) { - qCDebug(lcQpaXcb, "XRender extension not present on the X server"); - return; - } - - auto xrender_query = Q_XCB_REPLY(xcb_render_query_version, m_connection, - XCB_RENDER_MAJOR_VERSION, - XCB_RENDER_MINOR_VERSION); - if (!xrender_query) { - qCWarning(lcQpaXcb, "xcb_render_query_version failed"); - return; - } - - has_render_extension = true; - m_xrenderVersion.first = xrender_query->major_version; - m_xrenderVersion.second = xrender_query->minor_version; -#endif -} - -void QXcbConnection::initializeXRandr() -{ - const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_randr_id); - if (!reply || !reply->present) - return; - - xrandr_first_event = reply->first_event; - - auto xrandr_query = Q_XCB_REPLY(xcb_randr_query_version, m_connection, - XCB_RANDR_MAJOR_VERSION, - XCB_RANDR_MINOR_VERSION); - - has_randr_extension = true; - - if (!xrandr_query || (xrandr_query->major_version < 1 || (xrandr_query->major_version == 1 && xrandr_query->minor_version < 2))) { - qWarning("QXcbConnection: Failed to initialize XRandr"); - has_randr_extension = false; - } - - xcb_screen_iterator_t rootIter = xcb_setup_roots_iterator(m_setup); - for (; rootIter.rem; xcb_screen_next(&rootIter)) { - xcb_randr_select_input(xcb_connection(), - rootIter.data->root, - XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE | - XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE | - XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE | - XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY - ); - } -} - -void QXcbConnection::initializeXinerama() -{ - const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xinerama_id); - if (!reply || !reply->present) - return; - - auto xinerama_is_active = Q_XCB_REPLY(xcb_xinerama_is_active, m_connection); - has_xinerama_extension = xinerama_is_active && xinerama_is_active->state; -} - -void QXcbConnection::initializeXShape() -{ - const xcb_query_extension_reply_t *xshape_reply = xcb_get_extension_data(m_connection, &xcb_shape_id); - if (!xshape_reply || !xshape_reply->present) - return; - - has_shape_extension = true; - auto shape_query = Q_XCB_REPLY(xcb_shape_query_version, m_connection); - if (!shape_query) { - qWarning("QXcbConnection: Failed to initialize SHAPE extension"); - } else if (shape_query->major_version > 1 || (shape_query->major_version == 1 && shape_query->minor_version >= 1)) { - // The input shape is the only thing added in SHAPE 1.1 - has_input_shape = true; - } -} - -void QXcbConnection::initializeXKB() -{ -#if QT_CONFIG(xkb) - const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xkb_id); - if (!reply || !reply->present) { - qWarning("Qt: XKEYBOARD extension not present on the X server."); - xkb_first_event = 0; - return; - } - xkb_first_event = reply->first_event; - - xcb_connection_t *c = connection()->xcb_connection(); - - auto xkb_query = Q_XCB_REPLY(xcb_xkb_use_extension, c, - XKB_X11_MIN_MAJOR_XKB_VERSION, - XKB_X11_MIN_MINOR_XKB_VERSION); - - if (!xkb_query) { - qWarning("Qt: Failed to initialize XKB extension"); - return; - } else if (!xkb_query->supported) { - qWarning("Qt: Unsupported XKB version (We want %d %d, but X server has %d %d)", - XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION, - xkb_query->serverMajor, xkb_query->serverMinor); - return; - } - - has_xkb = true; - - const uint16_t required_map_parts = (XCB_XKB_MAP_PART_KEY_TYPES | - XCB_XKB_MAP_PART_KEY_SYMS | - XCB_XKB_MAP_PART_MODIFIER_MAP | - XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS | - XCB_XKB_MAP_PART_KEY_ACTIONS | - XCB_XKB_MAP_PART_KEY_BEHAVIORS | - XCB_XKB_MAP_PART_VIRTUAL_MODS | - XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP); - - const uint16_t required_events = (XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY | - XCB_XKB_EVENT_TYPE_MAP_NOTIFY | - XCB_XKB_EVENT_TYPE_STATE_NOTIFY); - - // XKB events are reported to all interested clients without regard - // to the current keyboard input focus or grab state - xcb_void_cookie_t select = xcb_xkb_select_events_checked(c, - XCB_XKB_ID_USE_CORE_KBD, - required_events, - 0, - required_events, - required_map_parts, - required_map_parts, - 0); - - xcb_generic_error_t *error = xcb_request_check(c, select); - if (error) { - free(error); - qWarning("Qt: failed to select notify events from xcb-xkb"); - return; - } -#endif -} - -void QXcbConnection::initializeXSync() -{ - const xcb_query_extension_reply_t *reply = xcb_get_extension_data(xcb_connection(), &xcb_sync_id); - if (!reply || !reply->present) - return; - - has_sync_extension = true; -} - QXcbSystemTrayTracker *QXcbConnection::systemTrayTracker() const { if (!m_systemTrayTracker) { diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 96591c7994..fcc1309afe 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -47,31 +47,18 @@ #include "qxcbexport.h" #include #include -#include #include #include #include #include #include "qxcbeventqueue.h" - -#include -#include - -// This is needed to make Qt compile together with XKB. xkb.h is using a variable -// which is called 'explicit', this is a reserved keyword in c++ -#if QT_CONFIG(xkb) -#define explicit dont_use_cxx_explicit -#include -#undef explicit -#endif +#include "qxcbconnection_basic.h" #if QT_CONFIG(tabletevent) #include #endif -struct xcb_randr_get_output_info_reply_t; - QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(lcQpaXInput) @@ -79,7 +66,6 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaXInputDevices) Q_DECLARE_LOGGING_CATEGORY(lcQpaXInputEvents) Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen) Q_DECLARE_LOGGING_CATEGORY(lcQpaEvents) -Q_DECLARE_LOGGING_CATEGORY(lcQpaXcb) Q_DECLARE_LOGGING_CATEGORY(lcQpaPeeker) Q_DECLARE_LOGGING_CATEGORY(lcQpaKeyboard) Q_DECLARE_LOGGING_CATEGORY(lcQpaXDnd) @@ -96,215 +82,6 @@ class QXcbNativeInterface; class QXcbSystemTrayTracker; class QXcbGlIntegration; -namespace QXcbAtom { - enum Atom { - // window-manager <-> client protocols - WM_PROTOCOLS, - WM_DELETE_WINDOW, - WM_TAKE_FOCUS, - _NET_WM_PING, - _NET_WM_CONTEXT_HELP, - _NET_WM_SYNC_REQUEST, - _NET_WM_SYNC_REQUEST_COUNTER, - MANAGER, // System tray notification - _NET_SYSTEM_TRAY_OPCODE, // System tray operation - - // ICCCM window state - WM_STATE, - WM_CHANGE_STATE, - WM_CLASS, - WM_NAME, - - // Session management - WM_CLIENT_LEADER, - WM_WINDOW_ROLE, - SM_CLIENT_ID, - WM_CLIENT_MACHINE, - - // Clipboard - CLIPBOARD, - INCR, - TARGETS, - MULTIPLE, - TIMESTAMP, - SAVE_TARGETS, - CLIP_TEMPORARY, - _QT_SELECTION, - _QT_CLIPBOARD_SENTINEL, - _QT_SELECTION_SENTINEL, - CLIPBOARD_MANAGER, - - RESOURCE_MANAGER, - - _XSETROOT_ID, - - _QT_SCROLL_DONE, - _QT_INPUT_ENCODING, - - // Qt/XCB specific - _QT_CLOSE_CONNECTION, - - _MOTIF_WM_HINTS, - - DTWM_IS_RUNNING, - ENLIGHTENMENT_DESKTOP, - _DT_SAVE_MODE, - _SGI_DESKS_MANAGER, - - // EWMH (aka NETWM) - _NET_SUPPORTED, - _NET_VIRTUAL_ROOTS, - _NET_WORKAREA, - - _NET_MOVERESIZE_WINDOW, - _NET_WM_MOVERESIZE, - - _NET_WM_NAME, - _NET_WM_ICON_NAME, - _NET_WM_ICON, - - _NET_WM_PID, - - _NET_WM_WINDOW_OPACITY, - - _NET_WM_STATE, - _NET_WM_STATE_ABOVE, - _NET_WM_STATE_BELOW, - _NET_WM_STATE_FULLSCREEN, - _NET_WM_STATE_MAXIMIZED_HORZ, - _NET_WM_STATE_MAXIMIZED_VERT, - _NET_WM_STATE_MODAL, - _NET_WM_STATE_STAYS_ON_TOP, - _NET_WM_STATE_DEMANDS_ATTENTION, - - _NET_WM_USER_TIME, - _NET_WM_USER_TIME_WINDOW, - _NET_WM_FULL_PLACEMENT, - - _NET_WM_WINDOW_TYPE, - _NET_WM_WINDOW_TYPE_DESKTOP, - _NET_WM_WINDOW_TYPE_DOCK, - _NET_WM_WINDOW_TYPE_TOOLBAR, - _NET_WM_WINDOW_TYPE_MENU, - _NET_WM_WINDOW_TYPE_UTILITY, - _NET_WM_WINDOW_TYPE_SPLASH, - _NET_WM_WINDOW_TYPE_DIALOG, - _NET_WM_WINDOW_TYPE_DROPDOWN_MENU, - _NET_WM_WINDOW_TYPE_POPUP_MENU, - _NET_WM_WINDOW_TYPE_TOOLTIP, - _NET_WM_WINDOW_TYPE_NOTIFICATION, - _NET_WM_WINDOW_TYPE_COMBO, - _NET_WM_WINDOW_TYPE_DND, - _NET_WM_WINDOW_TYPE_NORMAL, - _KDE_NET_WM_WINDOW_TYPE_OVERRIDE, - - _KDE_NET_WM_FRAME_STRUT, - _NET_FRAME_EXTENTS, - - _NET_STARTUP_INFO, - _NET_STARTUP_INFO_BEGIN, - - _NET_SUPPORTING_WM_CHECK, - - _NET_WM_CM_S0, - - _NET_SYSTEM_TRAY_VISUAL, - - _NET_ACTIVE_WINDOW, - - // Property formats - TEXT, - UTF8_STRING, - CARDINAL, - - // Xdnd - XdndEnter, - XdndPosition, - XdndStatus, - XdndLeave, - XdndDrop, - XdndFinished, - XdndTypelist, - XdndActionList, - - XdndSelection, - - XdndAware, - XdndProxy, - - XdndActionCopy, - XdndActionLink, - XdndActionMove, - XdndActionPrivate, - - // Motif DND - _MOTIF_DRAG_AND_DROP_MESSAGE, - _MOTIF_DRAG_INITIATOR_INFO, - _MOTIF_DRAG_RECEIVER_INFO, - _MOTIF_DRAG_WINDOW, - _MOTIF_DRAG_TARGETS, - - XmTRANSFER_SUCCESS, - XmTRANSFER_FAILURE, - - // Xkb - _XKB_RULES_NAMES, - - // XEMBED - _XEMBED, - _XEMBED_INFO, - - // XInput2 - ButtonLeft, - ButtonMiddle, - ButtonRight, - ButtonWheelUp, - ButtonWheelDown, - ButtonHorizWheelLeft, - ButtonHorizWheelRight, - AbsMTPositionX, - AbsMTPositionY, - AbsMTTouchMajor, - AbsMTTouchMinor, - AbsMTOrientation, - AbsMTPressure, - AbsMTTrackingID, - MaxContacts, - RelX, - RelY, - // XInput2 tablet - AbsX, - AbsY, - AbsPressure, - AbsTiltX, - AbsTiltY, - AbsWheel, - AbsDistance, - WacomSerialIDs, - INTEGER, - RelHorizWheel, - RelVertWheel, - RelHorizScroll, - RelVertScroll, - - _XSETTINGS_SETTINGS, - - _COMPIZ_DECOR_PENDING, - _COMPIZ_DECOR_REQUEST, - _COMPIZ_DECOR_DELETE_PIXMAP, - _COMPIZ_TOOLKIT_ACTION, - _GTK_LOAD_ICONTHEMES, - - AT_SPI_BUS, - - EDID, - EDID_DATA, - XFree86_DDC_EDID1_RAWDATA, - - NAtoms - }; -} - class QXcbWindowEventListener { public: @@ -346,7 +123,7 @@ private: QXcbWindow *m_window; }; -class Q_XCB_EXPORT QXcbConnection : public QObject +class Q_XCB_EXPORT QXcbConnection : public QXcbBasicConnection { Q_OBJECT public: @@ -354,23 +131,15 @@ public: ~QXcbConnection(); QXcbConnection *connection() const { return const_cast(this); } - bool isConnected() const; QXcbEventQueue *eventQueue() const { return m_eventQueue; } const QList &virtualDesktops() const { return m_virtualDesktops; } const QList &screens() const { return m_screens; } - int primaryScreenNumber() const { return m_primaryScreenNumber; } - QXcbVirtualDesktop *primaryVirtualDesktop() const { return m_virtualDesktops.value(m_primaryScreenNumber); } + QXcbVirtualDesktop *primaryVirtualDesktop() const { + return m_virtualDesktops.value(primaryScreenNumber()); + } QXcbScreen *primaryScreen() const; - inline xcb_atom_t atom(QXcbAtom::Atom atom) const { return m_allAtoms[atom]; } - QXcbAtom::Atom qatom(xcb_atom_t atom) const; - xcb_atom_t internAtom(const char *name); - QByteArray atomName(xcb_atom_t atom); - - const char *displayName() const { return m_displayName.constData(); } - xcb_connection_t *xcb_connection() const { return m_connection; } - const xcb_setup_t *setup() const { return m_setup; } const xcb_format_t *formatForDepth(uint8_t depth) const; bool imageNeedsEndianSwap() const @@ -378,9 +147,9 @@ public: if (!hasShm()) return false; // The non-Shm path does its own swapping #if Q_BYTE_ORDER == Q_BIG_ENDIAN - return m_setup->image_byte_order != XCB_IMAGE_ORDER_MSB_FIRST; + return setup()->image_byte_order != XCB_IMAGE_ORDER_MSB_FIRST; #else - return m_setup->image_byte_order != XCB_IMAGE_ORDER_LSB_FIRST; + return setup()->image_byte_order != XCB_IMAGE_ORDER_LSB_FIRST; #endif } @@ -400,9 +169,6 @@ public: bool hasDefaultVisualId() const { return m_defaultVisualId != UINT_MAX; } xcb_visualid_t defaultVisualId() const { return m_defaultVisualId; } -#if QT_CONFIG(xcb_xlib) - void *xlib_display() const { return m_xlib_display; } -#endif void sync(); void handleXcbError(xcb_generic_error_t *error); @@ -425,23 +191,6 @@ public: inline xcb_timestamp_t netWmUserTime() const { return m_netWmUserTime; } inline void setNetWmUserTime(xcb_timestamp_t t) { if (t > m_netWmUserTime) m_netWmUserTime = t; } - bool hasXFixes() const { return has_xfixes; } - bool hasXShape() const { return has_shape_extension; } - bool hasXRandr() const { return has_randr_extension; } - bool hasInputShape() const { return has_input_shape; } - bool hasXKB() const { return has_xkb; } - bool hasXRender(int major = -1, int minor = -1) const - { - if (has_render_extension && major != -1 && minor != -1) - return m_xrenderVersion >= qMakePair(major, minor); - - return has_render_extension; - } - bool hasXInput2() const { return m_xi2Enabled; } - bool hasShm() const { return has_shm; } - bool hasShmFd() const { return has_shm_fd; } - bool hasXSync() const { return has_sync_extension; } - xcb_timestamp_t getTimestamp(); xcb_window_t getSelectionOwner(xcb_atom_t atom) const; xcb_window_t getQtSelectionOwner(); @@ -483,8 +232,6 @@ public: void xi2SelectDeviceEventsCompatibility(xcb_window_t window); bool xi2SetMouseGrabEnabled(xcb_window_t w, bool grab); bool xi2MouseEventsDisabled() const; - bool isAtLeastXI21() const { return m_xi2Enabled && m_xi2Minor >= 1; } - bool isAtLeastXI22() const { return m_xi2Enabled && m_xi2Minor >= 2; } Qt::MouseButton xiToQtMouseButton(uint32_t b); void xi2UpdateScrollingDevices(); bool startSystemMoveResizeForTouchBegin(xcb_window_t window, const QPoint &point, int corner); @@ -496,22 +243,14 @@ public: QXcbGlIntegration *glIntegration() const; - void flush() { xcb_flush(m_connection); } + void flush() { xcb_flush(xcb_connection()); } void processXcbEvents(QEventLoop::ProcessEventsFlags flags); protected: bool event(QEvent *e) override; private: - void initializeAllAtoms(); - void initializeShm(); - void initializeXFixes(); - void initializeXRender(); - void initializeXRandr(); - void initializeXinerama(); - void initializeXShape(); - void initializeXKB(); - void initializeXSync(); + void selectXRandrEvents(); 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; @@ -525,10 +264,7 @@ private: void initializeScreens(); bool compressEvent(xcb_generic_event_t *event) const; - bool m_xi2Enabled = false; #if QT_CONFIG(xcb_xinput) - int m_xi2Minor = -1; - void initializeXInput2(); void xi2SetupDevice(void *info, bool removeExisting = true); void xi2SetupDevices(); struct TouchDeviceData { @@ -554,7 +290,6 @@ private: void xi2HandleEvent(xcb_ge_event_t *event); void xi2HandleHierarchyEvent(void *event); void xi2HandleDeviceChangedEvent(void *event); - int m_xiOpCode; void xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindow); #if QT_CONFIG(tabletevent) struct TabletData { @@ -597,22 +332,15 @@ private: static bool xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value); #endif - xcb_connection_t *m_connection = nullptr; - const xcb_setup_t *m_setup = nullptr; const bool m_canGrabServer; const xcb_visualid_t m_defaultVisualId; QList m_virtualDesktops; QList m_screens; - int m_primaryScreenNumber = 0; - - xcb_atom_t m_allAtoms[QXcbAtom::NAtoms]; xcb_timestamp_t m_time = XCB_CURRENT_TIME; xcb_timestamp_t m_netWmUserTime = XCB_CURRENT_TIME; - QByteArray m_displayName; - QXcbKeyboard *m_keyboard = nullptr; #ifndef QT_NO_CLIPBOARD QXcbClipboard *m_clipboard = nullptr; @@ -623,9 +351,6 @@ private: QScopedPointer m_wmSupport; QXcbNativeInterface *m_nativeInterface = nullptr; -#if QT_CONFIG(xcb_xlib) - void *m_xlib_display = nullptr; -#endif QXcbEventQueue *m_eventQueue = nullptr; #if QT_CONFIG(xcb_xinput) @@ -641,26 +366,6 @@ private: QVector m_peekFuncs; - uint32_t xfixes_first_event = 0; - uint32_t xrandr_first_event = 0; - uint32_t xkb_first_event = 0; -#if QT_CONFIG(xcb_xinput) - uint32_t xinput_first_event = 0; -#endif - - bool has_xfixes = false; - bool has_xinerama_extension = false; - bool has_shape_extension = false; - bool has_randr_extension = false; - bool has_input_shape; - bool has_xkb = false; - bool has_render_extension = false; - bool has_shm = false; - bool has_shm_fd = false; - bool has_sync_extension = false; - - QPair m_xrenderVersion; - Qt::MouseButtons m_buttonState = 0; Qt::MouseButton m_button = Qt::NoButton; @@ -699,22 +404,6 @@ private: QXcbConnection *m_connection; }; -#define Q_XCB_REPLY_CONNECTION_ARG(connection, ...) connection - -struct QStdFreeDeleter { - void operator()(void *p) const Q_DECL_NOTHROW { return std::free(p); } -}; - -#define Q_XCB_REPLY(call, ...) \ - std::unique_ptr( \ - call##_reply(Q_XCB_REPLY_CONNECTION_ARG(__VA_ARGS__), call(__VA_ARGS__), nullptr) \ - ) - -#define Q_XCB_REPLY_UNCHECKED(call, ...) \ - std::unique_ptr( \ - call##_reply(Q_XCB_REPLY_CONNECTION_ARG(__VA_ARGS__), call##_unchecked(__VA_ARGS__), nullptr) \ - ) - // The xcb_send_event() requires all events to have 32 bytes. It calls memcpy() on the // passed in event. If the passed in event is less than 32 bytes, memcpy() reaches into // unrelated memory. diff --git a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp new file mode 100644 index 0000000000..7bed3c8937 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp @@ -0,0 +1,437 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qxcbconnection_basic.h" +#include "qxcbbackingstore.h" // for createSystemVShmSegment() + +#include +#include +#include +#include +#include +#if QT_CONFIG(xcb_xinput) +#include +#endif +#if QT_CONFIG(xcb_render) +#include +#endif +#if QT_CONFIG(xkb) +#define explicit dont_use_cxx_explicit +#include +#undef explicit +#endif + +#if QT_CONFIG(xcb_xlib) +#define register /* C++17 deprecated register */ +#include +#include +#include +#include +#undef register +#endif + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcQpaXcb, "qt.qpa.xcb") + +#if QT_CONFIG(xcb_xlib) +static const char * const xcbConnectionErrors[] = { + "No error", /* Error 0 */ + "I/O error", /* XCB_CONN_ERROR */ + "Unsupported extension used", /* XCB_CONN_CLOSED_EXT_NOTSUPPORTED */ + "Out of memory", /* XCB_CONN_CLOSED_MEM_INSUFFICIENT */ + "Maximum allowed requested length exceeded", /* XCB_CONN_CLOSED_REQ_LEN_EXCEED */ + "Failed to parse display string", /* XCB_CONN_CLOSED_PARSE_ERR */ + "No such screen on display", /* XCB_CONN_CLOSED_INVALID_SCREEN */ + "Error during FD passing" /* XCB_CONN_CLOSED_FDPASSING_FAILED */ +}; + +static int nullErrorHandler(Display *dpy, XErrorEvent *err) +{ +#ifndef Q_XCB_DEBUG + Q_UNUSED(dpy); + Q_UNUSED(err); +#else + const int buflen = 1024; + char buf[buflen]; + + XGetErrorText(dpy, err->error_code, buf, buflen); + fprintf(stderr, "X Error: serial %lu error %d %s\n", err->serial, (int) err->error_code, buf); +#endif + return 0; +} + +static int ioErrorHandler(Display *dpy) +{ + xcb_connection_t *conn = XGetXCBConnection(dpy); + if (conn != NULL) { + /* Print a message with a textual description of the error */ + int code = xcb_connection_has_error(conn); + const char *str = "Unknown error"; + int arrayLength = sizeof(xcbConnectionErrors) / sizeof(xcbConnectionErrors[0]); + if (code >= 0 && code < arrayLength) + str = xcbConnectionErrors[code]; + + qWarning("The X11 connection broke: %s (code %d)", str, code); + } + return _XDefaultIOError(dpy); +} +#endif + +QXcbBasicConnection::QXcbBasicConnection(const char *displayName) + : m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY")) +{ +#if QT_CONFIG(xcb_xlib) + Display *dpy = XOpenDisplay(m_displayName.constData()); + if (dpy) { + m_primaryScreenNumber = DefaultScreen(dpy); + m_xcbConnection = XGetXCBConnection(dpy); + XSetEventQueueOwner(dpy, XCBOwnsEventQueue); + XSetErrorHandler(nullErrorHandler); + XSetIOErrorHandler(ioErrorHandler); + m_xlibDisplay = dpy; + } +#else + m_xcbConnection = xcb_connect(m_displayName.constData(), &m_primaryScreenNumber); +#endif + if (Q_UNLIKELY(!isConnected())) { + qCWarning(lcQpaXcb, "could not connect to display %s", m_displayName.constData()); + return; + } + + m_setup = xcb_get_setup(m_xcbConnection); + m_xcbAtom.initialize(m_xcbConnection); + + xcb_extension_t *extensions[] = { + &xcb_shm_id, &xcb_xfixes_id, &xcb_randr_id, &xcb_shape_id, &xcb_sync_id, +#if QT_CONFIG(xkb) + &xcb_xkb_id, +#endif +#if QT_CONFIG(xcb_render) + &xcb_render_id, +#endif +#if QT_CONFIG(xcb_xinput) + &xcb_input_id, +#endif + 0 + }; + + for (xcb_extension_t **ext_it = extensions; *ext_it; ++ext_it) + xcb_prefetch_extension_data (m_xcbConnection, *ext_it); + + initializeXSync(); + if (!qEnvironmentVariableIsSet("QT_XCB_NO_MITSHM")) + initializeShm(); + if (!qEnvironmentVariableIsSet("QT_XCB_NO_XRANDR")) + initializeXRandr(); + if (!m_hasXRandr) + initializeXinerama(); + initializeXFixes(); + initializeXRender(); +#if QT_CONFIG(xcb_xinput) + if (!qEnvironmentVariableIsSet("QT_XCB_NO_XI2")) + initializeXInput2(); +#endif + initializeXShape(); + initializeXKB(); +} + +QXcbBasicConnection::~QXcbBasicConnection() +{ + if (isConnected()) { +#if QT_CONFIG(xcb_xlib) + XCloseDisplay(static_cast(m_xlibDisplay)); +#else + xcb_disconnect(m_xcbConnection); +#endif + } +} + +xcb_atom_t QXcbBasicConnection::internAtom(const char *name) +{ + if (!name || *name == 0) + return XCB_NONE; + + return Q_XCB_REPLY(xcb_intern_atom, m_xcbConnection, false, strlen(name), name)->atom; +} + +QByteArray QXcbBasicConnection::atomName(xcb_atom_t atom) +{ + if (!atom) + return QByteArray(); + + auto reply = Q_XCB_REPLY(xcb_get_atom_name, m_xcbConnection, atom); + if (reply) + return QByteArray(xcb_get_atom_name_name(reply.get()), xcb_get_atom_name_name_length(reply.get())); + + qCWarning(lcQpaXcb) << "atomName: bad atom" << atom; + return QByteArray(); +} + +#if QT_CONFIG(xcb_xinput) +// Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed: +// - "pad0" became "extension" +// - "pad1" and "pad" became "pad0" +// New and old version of this struct share the following fields: +typedef struct qt_xcb_ge_event_t { + uint8_t response_type; + uint8_t extension; + uint16_t sequence; + uint32_t length; + uint16_t event_type; +} qt_xcb_ge_event_t; + +bool QXcbBasicConnection::isXIEvent(xcb_generic_event_t *event) const +{ + qt_xcb_ge_event_t *e = reinterpret_cast(event); + return e->extension == m_xiOpCode; +} + +bool QXcbBasicConnection::isXIType(xcb_generic_event_t *event, uint16_t type) const +{ + if (!isXIEvent(event)) + return false; + + auto *e = reinterpret_cast(event); + return e->event_type == type; +} +#endif // QT_CONFIG(xcb_xinput) + +bool QXcbBasicConnection::isXFixesType(uint responseType, int eventType) const +{ + return m_hasXFixes && responseType == m_xfixesFirstEvent + eventType; +} + +bool QXcbBasicConnection::isXRandrType(uint responseType, int eventType) const +{ + return m_hasXRandr && responseType == m_xrandrFirstEvent + eventType; +} + +bool QXcbBasicConnection::isXkbType(uint responseType) const +{ + return m_hasXkb && responseType == m_xkbFirstEvent; +} + +void QXcbBasicConnection::initializeXSync() +{ + const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_xcbConnection, &xcb_sync_id); + if (!reply || !reply->present) + return; + + m_hasXSync = true; +} + +void QXcbBasicConnection::initializeShm() +{ + const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_xcbConnection, &xcb_shm_id); + if (!reply || !reply->present) { + qCDebug(lcQpaXcb, "MIT-SHM extension is not present on the X server"); + return; + } + + auto shmQuery = Q_XCB_REPLY(xcb_shm_query_version, m_xcbConnection); + if (!shmQuery) { + qCWarning(lcQpaXcb, "failed to request MIT-SHM version"); + return; + } + + m_hasShm = true; + m_hasShmFd = (shmQuery->major_version == 1 && shmQuery->minor_version >= 2) || + shmQuery->major_version > 1; + + qCDebug(lcQpaXcb) << "Has MIT-SHM :" << m_hasShm; + qCDebug(lcQpaXcb) << "Has MIT-SHM FD :" << m_hasShmFd; + + // Temporary disable warnings (unless running in debug mode). + auto logging = const_cast(&lcQpaXcb()); + bool wasEnabled = logging->isEnabled(QtMsgType::QtWarningMsg); + if (!logging->isEnabled(QtMsgType::QtDebugMsg)) + logging->setEnabled(QtMsgType::QtWarningMsg, false); + if (!QXcbBackingStore::createSystemVShmSegment(m_xcbConnection)) { + qCDebug(lcQpaXcb, "failed to create System V shared memory segment (remote " + "X11 connection?), disabling SHM"); + m_hasShm = m_hasShmFd = false; + } + if (wasEnabled) + logging->setEnabled(QtMsgType::QtWarningMsg, true); +} + +void QXcbBasicConnection::initializeXRandr() +{ +#if QT_CONFIG(xcb_render) + const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_xcbConnection, &xcb_render_id); + if (!reply || !reply->present) { + qCDebug(lcQpaXcb, "XRender extension not present on the X server"); + return; + } + + auto xrenderQuery = Q_XCB_REPLY(xcb_render_query_version, m_xcbConnection, + XCB_RENDER_MAJOR_VERSION, + XCB_RENDER_MINOR_VERSION); + if (!xrenderQuery) { + qCWarning(lcQpaXcb, "xcb_render_query_version failed"); + return; + } + + m_hasXRender = true; + m_xrenderVersion.first = xrenderQuery->major_version; + m_xrenderVersion.second = xrenderQuery->minor_version; +#endif +} + +void QXcbBasicConnection::initializeXinerama() +{ + const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_xcbConnection, &xcb_xinerama_id); + if (!reply || !reply->present) + return; + + auto xineramaActive = Q_XCB_REPLY(xcb_xinerama_is_active, m_xcbConnection); + if (xineramaActive && xineramaActive->state) + m_hasXinerama = true; +} + +void QXcbBasicConnection::initializeXFixes() +{ + const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_xcbConnection, &xcb_xfixes_id); + if (!reply || !reply->present) + return; + + auto xfixesQuery = Q_XCB_REPLY(xcb_xfixes_query_version, m_xcbConnection, + XCB_XFIXES_MAJOR_VERSION, + XCB_XFIXES_MINOR_VERSION); + if (!xfixesQuery || xfixesQuery->major_version < 2) { + qCWarning(lcQpaXcb, "failed to initialize XFixes"); + return; + } + + m_hasXFixes = true; + m_xfixesFirstEvent = reply->first_event; +} + +void QXcbBasicConnection::initializeXRender() +{ + const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_xcbConnection, &xcb_randr_id); + if (!reply || !reply->present) + return; + + auto xrandrQuery = Q_XCB_REPLY(xcb_randr_query_version, m_xcbConnection, + XCB_RANDR_MAJOR_VERSION, + XCB_RANDR_MINOR_VERSION); + if (!xrandrQuery || (xrandrQuery->major_version < 1 || + (xrandrQuery->major_version == 1 && xrandrQuery->minor_version < 2))) { + qCWarning(lcQpaXcb, "failed to initialize XRandr"); + return; + } + + m_hasXRandr = true; + m_xrandrFirstEvent = reply->first_event; +} + +#if QT_CONFIG(xcb_xinput) +void QXcbBasicConnection::initializeXInput2() +{ + const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_xcbConnection, &xcb_input_id); + if (!reply || !reply->present) { + qCDebug(lcQpaXcb, "XInput extension is not present on the X server"); + return; + } + + auto xinputQuery = Q_XCB_REPLY(xcb_input_xi_query_version, m_xcbConnection, 2, 2); + if (!xinputQuery || xinputQuery->major_version != 2) { + qCWarning(lcQpaXcb, "X server does not support XInput 2"); + return; + } + + qCDebug(lcQpaXcb, "Using XInput version %d.%d", + xinputQuery->major_version, xinputQuery->minor_version); + + m_xi2Enabled = true; + m_xiOpCode = reply->major_opcode; + m_xinputFirstEvent = reply->first_event; + m_xi2Minor = xinputQuery->minor_version; +} +#endif + +void QXcbBasicConnection::initializeXShape() +{ + const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_xcbConnection, &xcb_shape_id); + if (!reply || !reply->present) + return; + + m_hasXhape = true; + + auto shapeQuery = Q_XCB_REPLY(xcb_shape_query_version, m_xcbConnection); + if (!shapeQuery) { + qCWarning(lcQpaXcb, "failed to initialize XShape extension"); + return; + } + + if (shapeQuery->major_version > 1 || (shapeQuery->major_version == 1 && shapeQuery->minor_version >= 1)) { + // The input shape is the only thing added in SHAPE 1.1 + m_hasInputShape = true; + } +} + +void QXcbBasicConnection::initializeXKB() +{ +#if QT_CONFIG(xkb) + const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_xcbConnection, &xcb_xkb_id); + if (!reply || !reply->present) { + qCWarning(lcQpaXcb, "XKeyboard extension not present on the X server"); + return; + } + + int wantMajor = 1; + int wantMinor = 0; + auto xkbQuery = Q_XCB_REPLY(xcb_xkb_use_extension, m_xcbConnection, wantMajor, wantMinor); + if (!xkbQuery) { + qCWarning(lcQpaXcb, "failed to initialize XKeyboard extension"); + return; + } + if (!xkbQuery->supported) { + qCWarning(lcQpaXcb, "unsupported XKB version (we want %d.%d, but X server has %d.%d)", + wantMajor, wantMinor, xkbQuery->serverMajor, xkbQuery->serverMinor); + return; + } + + m_hasXkb = true; + m_xkbFirstEvent = reply->first_event; +#endif +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbconnection_basic.h b/src/plugins/platforms/xcb/qxcbconnection_basic.h new file mode 100644 index 0000000000..ca91f7fa45 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbconnection_basic.h @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QXCBBASICCONNECTION_H +#define QXCBBASICCONNECTION_H + +#include "qxcbatom.h" + +#include +#include +#include +#include +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(lcQpaXcb) + +class QXcbBasicConnection : public QObject +{ + Q_OBJECT +public: + QXcbBasicConnection(const char *displayName); + ~QXcbBasicConnection(); + +#if QT_CONFIG(xcb_xlib) + void *xlib_display() const { return m_xlibDisplay; } +#endif + const char *displayName() const { return m_displayName.constData(); } + int primaryScreenNumber() const { return m_primaryScreenNumber; } + xcb_connection_t *xcb_connection() const { return m_xcbConnection; } + bool isConnected() const { + return m_xcbConnection && !xcb_connection_has_error(m_xcbConnection); + } + const xcb_setup_t *setup() const { return m_setup; } + + inline xcb_atom_t atom(QXcbAtom::Atom qatom) const { return m_xcbAtom.atom(qatom); } + QXcbAtom::Atom qatom(xcb_atom_t atom) const { return m_xcbAtom.qatom(atom); } + xcb_atom_t internAtom(const char *name); + QByteArray atomName(xcb_atom_t atom); + + bool hasXFixes() const { return m_hasXFixes; } + bool hasXShape() const { return m_hasXhape; } + bool hasXRandr() const { return m_hasXRandr; } + bool hasInputShape() const { return m_hasInputShape; } + bool hasXKB() const { return m_hasXkb; } + bool hasXRender(int major = -1, int minor = -1) const { + if (m_hasXRender && major != -1 && minor != -1) + return m_xrenderVersion >= qMakePair(major, minor); + + return m_hasXRender; + } + bool hasXInput2() const { return m_xi2Enabled; } + bool hasShm() const { return m_hasShm; } + bool hasShmFd() const { return m_hasShmFd; } + bool hasXSync() const { return m_hasXSync; } + bool hasXinerama() const { return m_hasXinerama; } + +#if QT_CONFIG(xcb_xinput) + bool isAtLeastXI21() const { return m_xi2Enabled && m_xi2Minor >= 1; } + bool isAtLeastXI22() const { return m_xi2Enabled && m_xi2Minor >= 2; } + bool isXIEvent(xcb_generic_event_t *event) const; + bool isXIType(xcb_generic_event_t *event, uint16_t type) const; +#endif + + bool isXFixesType(uint responseType, int eventType) const; + bool isXRandrType(uint responseType, int eventType) const; + bool isXkbType(uint responseType) const; // https://bugs.freedesktop.org/show_bug.cgi?id=51295 + +protected: + void initializeShm(); + void initializeXFixes(); + void initializeXRender(); + void initializeXRandr(); + void initializeXinerama(); + void initializeXShape(); + void initializeXKB(); + void initializeXSync(); +#if QT_CONFIG(xcb_xinput) + void initializeXInput2(); +#endif + +private: +#if QT_CONFIG(xcb_xlib) + void *m_xlibDisplay = nullptr; +#endif + QByteArray m_displayName; + xcb_connection_t *m_xcbConnection = nullptr; + int m_primaryScreenNumber = 0; + const xcb_setup_t *m_setup = nullptr; + QXcbAtom m_xcbAtom; + + bool m_hasXFixes = false; + bool m_hasXinerama = false; + bool m_hasXhape = false; + bool m_hasInputShape; + bool m_hasXRandr = false; + bool m_hasXkb = false; + bool m_hasXRender = false; + bool m_hasShm = false; + bool m_hasShmFd = false; + bool m_hasXSync = false; + + QPair m_xrenderVersion; + + bool m_xi2Enabled = false; +#if QT_CONFIG(xcb_xinput) + int m_xi2Minor = -1; + int m_xiOpCode = -1; + uint32_t m_xinputFirstEvent = 0; +#endif + + uint32_t m_xfixesFirstEvent = 0; + uint32_t m_xrandrFirstEvent = 0; + uint32_t m_xkbFirstEvent = 0; +}; + +#define Q_XCB_REPLY_CONNECTION_ARG(connection, ...) connection + +struct QStdFreeDeleter { + void operator()(void *p) const Q_DECL_NOTHROW { return std::free(p); } +}; + +#define Q_XCB_REPLY(call, ...) \ + std::unique_ptr( \ + call##_reply(Q_XCB_REPLY_CONNECTION_ARG(__VA_ARGS__), call(__VA_ARGS__), nullptr) \ + ) + +#define Q_XCB_REPLY_UNCHECKED(call, ...) \ + std::unique_ptr( \ + call##_reply(Q_XCB_REPLY_CONNECTION_ARG(__VA_ARGS__), call##_unchecked(__VA_ARGS__), nullptr) \ + ) + +QT_END_NAMESPACE + +#endif // QXCBBASICCONNECTION_H diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index a3befc7384..04ddd3c98c 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -51,31 +51,6 @@ using qt_xcb_input_device_event_t = xcb_input_button_press_event_t; -void QXcbConnection::initializeXInput2() -{ - const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_input_id); - if (!reply || !reply->present) { - qCDebug(lcQpaXInput, "XInput extension is not present on the X server"); - return; - } - - m_xiOpCode = reply->major_opcode; - xinput_first_event = reply->first_event; - - auto xinput_query = Q_XCB_REPLY(xcb_input_xi_query_version, m_connection, 2, 2); - - if (!xinput_query || xinput_query->major_version != 2) { - qCWarning(lcQpaXInput, "X server does not support XInput 2"); - } else { - qCDebug(lcQpaXInput, "Using XInput version %d.%d", - xinput_query->major_version, xinput_query->minor_version); - m_xi2Minor = xinput_query->minor_version; - m_xi2Enabled = true; - xi2SetupDevices(); - xi2SelectStateEvents(); - } -} - struct qt_xcb_input_event_mask_t { xcb_input_event_mask_t header; uint32_t mask; @@ -91,7 +66,7 @@ void QXcbConnection::xi2SelectStateEvents() xiEventMask.mask = XCB_INPUT_XI_EVENT_MASK_HIERARCHY; xiEventMask.mask |= XCB_INPUT_XI_EVENT_MASK_DEVICE_CHANGED; xiEventMask.mask |= XCB_INPUT_XI_EVENT_MASK_PROPERTY; - xcb_input_xi_select_events(m_connection, rootWindow(), 1, &xiEventMask.header); + xcb_input_xi_select_events(xcb_connection(), rootWindow(), 1, &xiEventMask.header); } void QXcbConnection::xi2SelectDeviceEvents(xcb_window_t window) @@ -117,8 +92,8 @@ void QXcbConnection::xi2SelectDeviceEvents(xcb_window_t window) mask.header.mask_len = 1; mask.mask = bitMask; xcb_void_cookie_t cookie = - xcb_input_xi_select_events_checked(m_connection, window, 1, &mask.header); - xcb_generic_error_t *error = xcb_request_check(m_connection, cookie); + xcb_input_xi_select_events_checked(xcb_connection(), window, 1, &mask.header); + xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie); if (error) { qCDebug(lcQpaXInput, "failed to select events, window %x, error code %d", window, error->error_code); free(error); @@ -310,7 +285,7 @@ void QXcbConnection::xi2SetupDevices() m_touchDevices.clear(); m_xiMasterPointerIds.clear(); - auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, m_connection, XCB_INPUT_DEVICE_ALL); + auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), XCB_INPUT_DEVICE_ALL); if (!reply) { qCDebug(lcQpaXInputDevices) << "failed to query devices"; return; @@ -387,8 +362,8 @@ void QXcbConnection::xi2SelectDeviceEventsCompatibility(xcb_window_t window) xiMask.mask = mask; xcb_void_cookie_t cookie = - xcb_input_xi_select_events_checked(m_connection, window, 1, &xiMask.header); - xcb_generic_error_t *error = xcb_request_check(m_connection, cookie); + xcb_input_xi_select_events_checked(xcb_connection(), window, 1, &xiMask.header); + xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie); if (error) { qCDebug(lcQpaXInput, "failed to select events, window %x, error code %d", window, error->error_code); free(error); @@ -413,7 +388,7 @@ void QXcbConnection::xi2SelectDeviceEventsCompatibility(xcb_window_t window) xiEventMask[i].header.mask_len = 1; xiEventMask[i].mask = mask; } - xcb_input_xi_select_events(m_connection, window, nrTablets, &(xiEventMask.data()->header)); + xcb_input_xi_select_events(xcb_connection(), window, nrTablets, &(xiEventMask.data()->header)); } #endif @@ -430,7 +405,7 @@ void QXcbConnection::xi2SelectDeviceEventsCompatibility(xcb_window_t window) xiEventMask[i].mask = mask; i++; } - xcb_input_xi_select_events(m_connection, window, i, &(xiEventMask.data()->header)); + xcb_input_xi_select_events(xcb_connection(), window, i, &(xiEventMask.data()->header)); } } @@ -633,7 +608,7 @@ bool QXcbConnection::xi2MouseEventsDisabled() const static bool xi2MouseDisabled = qEnvironmentVariableIsSet("QT_XCB_NO_XI2_MOUSE"); // FIXME: Don't use XInput2 mouse events when Xinerama extension // is enabled, because it causes problems with multi-monitor setup. - return xi2MouseDisabled || has_xinerama_extension; + return xi2MouseDisabled || hasXinerama(); } bool QXcbConnection::isTouchScreen(int id) @@ -745,7 +720,7 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo // Touches must be accepted when we are grabbing touch events. Otherwise the entire sequence // will get replayed when the grab ends. if (m_xiGrab) { - xcb_input_xi_allow_events(m_connection, XCB_CURRENT_TIME, xiDeviceEvent->deviceid, + xcb_input_xi_allow_events(xcb_connection(), XCB_CURRENT_TIME, xiDeviceEvent->deviceid, XCB_INPUT_EVENT_MODE_ACCEPT_TOUCH, xiDeviceEvent->detail, xiDeviceEvent->event); } @@ -771,7 +746,7 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo xiDeviceEvent->detail == m_startSystemMoveResizeInfo.pointid) { QXcbWindow *window = platformWindowFromId(m_startSystemMoveResizeInfo.window); if (window) { - xcb_input_xi_allow_events(m_connection, XCB_CURRENT_TIME, xiDeviceEvent->deviceid, + xcb_input_xi_allow_events(xcb_connection(), XCB_CURRENT_TIME, xiDeviceEvent->deviceid, XCB_INPUT_EVENT_MODE_REJECT_TOUCH, xiDeviceEvent->detail, xiDeviceEvent->event); window->doStartSystemMoveResize(QPoint(x, y), m_startSystemMoveResizeInfo.corner); @@ -850,10 +825,10 @@ bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab) for (int id : m_xiMasterPointerIds) { xcb_generic_error_t *error = nullptr; - auto cookie = xcb_input_xi_grab_device(m_connection, w, XCB_CURRENT_TIME, XCB_CURSOR_NONE, id, + auto cookie = xcb_input_xi_grab_device(xcb_connection(), w, XCB_CURRENT_TIME, XCB_CURSOR_NONE, id, XCB_INPUT_GRAB_MODE_22_ASYNC, XCB_INPUT_GRAB_MODE_22_ASYNC, false, 1, &mask); - auto *reply = xcb_input_xi_grab_device_reply(m_connection, cookie, &error); + auto *reply = xcb_input_xi_grab_device_reply(xcb_connection(), cookie, &error); if (error) { qCDebug(lcQpaXInput, "failed to grab events for device %d on window %x" "(error code %d)", id, w, error->error_code); @@ -867,8 +842,8 @@ bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab) } } else { // ungrab for (int id : m_xiMasterPointerIds) { - auto cookie = xcb_input_xi_ungrab_device_checked(m_connection, XCB_CURRENT_TIME, id); - xcb_generic_error_t *error = xcb_request_check(m_connection, cookie); + auto cookie = xcb_input_xi_ungrab_device_checked(xcb_connection(), XCB_CURRENT_TIME, id); + xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie); if (error) { qCDebug(lcQpaXInput, "XIUngrabDevice failed - id: %d (error code %d)", id, error->error_code); free(error); @@ -911,7 +886,7 @@ void QXcbConnection::xi2HandleDeviceChangedEvent(void *event) auto *xiEvent = reinterpret_cast(event); switch (xiEvent->reason) { case XCB_INPUT_CHANGE_REASON_DEVICE_CHANGE: { - auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, m_connection, xiEvent->sourceid); + auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), xiEvent->sourceid); if (!reply || reply->num_infos <= 0) return; auto it = xcb_input_xi_query_device_infos_iterator(reply.get()); @@ -931,7 +906,7 @@ void QXcbConnection::xi2HandleDeviceChangedEvent(void *event) void QXcbConnection::xi2UpdateScrollingDevice(ScrollingDevice &scrollingDevice) { - auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, m_connection, scrollingDevice.deviceId); + auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), scrollingDevice.deviceId); if (!reply || reply->num_infos <= 0) { qCDebug(lcQpaXInputDevices, "scrolling device %d no longer present", scrollingDevice.deviceId); return; @@ -1184,7 +1159,7 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD _WACSER_COUNT }; - auto reply = Q_XCB_REPLY(xcb_input_xi_get_property, m_connection, tabletData->deviceId, 0, + auto reply = Q_XCB_REPLY(xcb_input_xi_get_property, xcb_connection(), tabletData->deviceId, 0, ev->property, XCB_GET_PROPERTY_TYPE_ANY, 0, 100); if (reply) { if (reply->type == atom(QXcbAtom::INTEGER) && reply->format == 32 && reply->num_items == _WACSER_COUNT) { diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.cpp b/src/plugins/platforms/xcb/qxcbeventqueue.cpp index 20589fc550..862f68764b 100644 --- a/src/plugins/platforms/xcb/qxcbeventqueue.cpp +++ b/src/plugins/platforms/xcb/qxcbeventqueue.cpp @@ -351,7 +351,7 @@ void QXcbEventQueue::sendCloseConnectionEvent() const xcb_connection_t *c = m_connection->xcb_connection(); const xcb_window_t window = xcb_generate_id(c); - xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_connection->m_setup); + xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_connection->setup()); xcb_screen_t *screen = it.data; xcb_create_window(c, XCB_COPY_FROM_PARENT, window, screen->root, diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index ad06f24c14..c5dc7b21ad 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -1190,9 +1190,10 @@ QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection) #if QT_CONFIG(xkb) core_device_id = 0; if (connection->hasXKB()) { + selectEvents(); core_device_id = xkb_x11_get_core_keyboard_device_id(xcb_connection()); if (core_device_id == -1) { - qWarning("Qt: couldn't get core keyboard device info"); + qCWarning(lcQpaXcb, "failed to get core keyboard device info"); return; } } else { @@ -1210,6 +1211,42 @@ QXcbKeyboard::~QXcbKeyboard() xcb_key_symbols_free(m_key_symbols); } +void QXcbKeyboard::selectEvents() +{ +#if QT_CONFIG(xkb) + const uint16_t required_map_parts = (XCB_XKB_MAP_PART_KEY_TYPES | + XCB_XKB_MAP_PART_KEY_SYMS | + XCB_XKB_MAP_PART_MODIFIER_MAP | + XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS | + XCB_XKB_MAP_PART_KEY_ACTIONS | + XCB_XKB_MAP_PART_KEY_BEHAVIORS | + XCB_XKB_MAP_PART_VIRTUAL_MODS | + XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP); + + const uint16_t required_events = (XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY | + XCB_XKB_EVENT_TYPE_MAP_NOTIFY | + XCB_XKB_EVENT_TYPE_STATE_NOTIFY); + + // XKB events are reported to all interested clients without regard + // to the current keyboard input focus or grab state + xcb_void_cookie_t select = xcb_xkb_select_events_checked( + xcb_connection(), + XCB_XKB_ID_USE_CORE_KBD, + required_events, + 0, + required_events, + required_map_parts, + required_map_parts, + 0); + + xcb_generic_error_t *error = xcb_request_check(xcb_connection(), select); + if (error) { + free(error); + qCWarning(lcQpaXcb, "failed to select notify events from XKB"); + } +#endif +} + void QXcbKeyboard::updateVModMapping() { #if QT_CONFIG(xkb) diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h index 95915fb2e6..f8490592b7 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.h +++ b/src/plugins/platforms/xcb/qxcbkeyboard.h @@ -43,6 +43,11 @@ #include "qxcbobject.h" #include +#if QT_CONFIG(xkb) +#define explicit dont_use_cxx_explicit +#include +#undef explicit +#endif #include #if QT_CONFIG(xkb) @@ -62,6 +67,8 @@ public: ~QXcbKeyboard(); + void selectEvents(); + void handleKeyPressEvent(const xcb_key_press_event_t *event); void handleKeyReleaseEvent(const xcb_key_release_event_t *event); diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro index a2c56a3dcf..4c646d42c6 100644 --- a/src/plugins/platforms/xcb/xcb-plugin.pro +++ b/src/plugins/platforms/xcb/xcb-plugin.pro @@ -8,6 +8,7 @@ macos: CONFIG += no_app_extension_api_only SOURCES = \ qxcbmain.cpp + OTHER_FILES += xcb.json README PLUGIN_TYPE = platforms diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index a747b25c88..c0704e4c18 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -31,7 +31,9 @@ SOURCES = \ qxcbxsettings.cpp \ qxcbsystemtraytracker.cpp \ qxcbeventqueue.cpp \ - qxcbeventdispatcher.cpp + qxcbeventdispatcher.cpp \ + qxcbconnection_basic.cpp \ + qxcbatom.cpp HEADERS = \ qxcbclipboard.h \ @@ -51,7 +53,9 @@ HEADERS = \ qxcbsystemtraytracker.h \ qxcbxkbcommon.h \ qxcbeventqueue.h \ - qxcbeventdispatcher.h + qxcbeventdispatcher.h \ + qxcbconnection_basic.h \ + qxcbatom.h qtConfig(draganddrop) { SOURCES += qxcbdrag.cpp -- cgit v1.2.3 From 67c3c0f240241340994898d46df7429d3eda4b69 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Sat, 22 Sep 2018 18:52:54 +0200 Subject: xcb: qxcbconnection_screens Moved all screen handling method implementations into qxcbconnection_screens, the same way we are doing with xinput2 code in qxcbconnection_xi.cpp. The goal was to reduce the size of qxcbconnection.h/cpp. Change-Id: I9bad55ca4b0874171b7313d923b13c66034c3b3e Reviewed-by: Allan Sandfeld Jensen --- src/plugins/platforms/xcb/qxcbconnection.cpp | 372 ------------------ src/plugins/platforms/xcb/qxcbconnection.h | 19 +- .../platforms/xcb/qxcbconnection_screens.cpp | 416 +++++++++++++++++++++ src/plugins/platforms/xcb/xcb_qpa_lib.pro | 1 + 4 files changed, 426 insertions(+), 382 deletions(-) create mode 100644 src/plugins/platforms/xcb/qxcbconnection_screens.cpp (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 10d07c37bb..9e857ea2ff 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -38,12 +38,10 @@ ****************************************************************************/ #include -#include #include #include "qxcbconnection.h" #include "qxcbkeyboard.h" -#include "qxcbscreen.h" #include "qxcbwindow.h" #include "qxcbclipboard.h" #if QT_CONFIG(draganddrop) @@ -67,7 +65,6 @@ #include #include -#include #if QT_CONFIG(xkb) #define explicit dont_use_cxx_explicit #include @@ -95,373 +92,6 @@ Q_LOGGING_CATEGORY(lcQpaXDnd, "qt.qpa.xdnd") #define XCB_GE_GENERIC 35 #endif -void QXcbConnection::selectXRandrEvents() -{ - xcb_screen_iterator_t rootIter = xcb_setup_roots_iterator(setup()); - for (; rootIter.rem; xcb_screen_next(&rootIter)) { - xcb_randr_select_input(xcb_connection(), - rootIter.data->root, - XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE | - XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE | - XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE | - XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY - ); - } -} - -QXcbScreen* QXcbConnection::findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc) const -{ - for (QXcbScreen *screen : m_screens) { - if (screen->root() == rootWindow && screen->crtc() == crtc) - return screen; - } - - return 0; -} - -QXcbScreen* QXcbConnection::findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output) const -{ - for (QXcbScreen *screen : m_screens) { - if (screen->root() == rootWindow && screen->output() == output) - return screen; - } - - return 0; -} - -QXcbVirtualDesktop* QXcbConnection::virtualDesktopForRootWindow(xcb_window_t rootWindow) const -{ - for (QXcbVirtualDesktop *virtualDesktop : m_virtualDesktops) { - if (virtualDesktop->screen()->root == rootWindow) - return virtualDesktop; - } - - return 0; -} - -/*! - \brief Synchronizes the screen list, adds new screens, removes deleted ones -*/ -void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event) -{ - if (event->subCode == XCB_RANDR_NOTIFY_CRTC_CHANGE) { - xcb_randr_crtc_change_t crtc = event->u.cc; - QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(crtc.window); - if (!virtualDesktop) - // Not for us - return; - - QXcbScreen *screen = findScreenForCrtc(crtc.window, crtc.crtc); - qCDebug(lcQpaScreen) << "QXcbConnection: XCB_RANDR_NOTIFY_CRTC_CHANGE:" << crtc.crtc - << "mode" << crtc.mode << "relevant screen" << screen; - // Only update geometry when there's a valid mode on the CRTC - // CRTC with node mode could mean that output has been disabled, and we'll - // get RRNotifyOutputChange notification for that. - if (screen && crtc.mode) { - if (crtc.rotation == XCB_RANDR_ROTATION_ROTATE_90 || - crtc.rotation == XCB_RANDR_ROTATION_ROTATE_270) - std::swap(crtc.width, crtc.height); - screen->updateGeometry(QRect(crtc.x, crtc.y, crtc.width, crtc.height), crtc.rotation); - if (screen->mode() != crtc.mode) - screen->updateRefreshRate(crtc.mode); - } - - } else if (event->subCode == XCB_RANDR_NOTIFY_OUTPUT_CHANGE) { - xcb_randr_output_change_t output = event->u.oc; - QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(output.window); - if (!virtualDesktop) - // Not for us - return; - - QXcbScreen *screen = findScreenForOutput(output.window, output.output); - qCDebug(lcQpaScreen) << "QXcbConnection: XCB_RANDR_NOTIFY_OUTPUT_CHANGE:" << output.output; - - if (screen && output.connection == XCB_RANDR_CONNECTION_DISCONNECTED) { - qCDebug(lcQpaScreen) << "screen" << screen->name() << "has been disconnected"; - destroyScreen(screen); - } else if (!screen && output.connection == XCB_RANDR_CONNECTION_CONNECTED) { - // New XRandR output is available and it's enabled - if (output.crtc != XCB_NONE && output.mode != XCB_NONE) { - auto outputInfo = Q_XCB_REPLY(xcb_randr_get_output_info, xcb_connection(), - output.output, output.config_timestamp); - // Find a fake screen - const auto scrs = virtualDesktop->screens(); - for (QPlatformScreen *scr : scrs) { - QXcbScreen *xcbScreen = static_cast(scr); - if (xcbScreen->output() == XCB_NONE) { - screen = xcbScreen; - break; - } - } - - if (screen) { - QString nameWas = screen->name(); - // Transform the fake screen into a physical screen - screen->setOutput(output.output, outputInfo.get()); - updateScreen(screen, output); - qCDebug(lcQpaScreen) << "output" << screen->name() - << "is connected and enabled; was fake:" << nameWas; - } else { - screen = createScreen(virtualDesktop, output, outputInfo.get()); - qCDebug(lcQpaScreen) << "output" << screen->name() << "is connected and enabled"; - } - QHighDpiScaling::updateHighDpiScaling(); - } - } else if (screen) { - if (output.crtc == XCB_NONE && output.mode == XCB_NONE) { - // Screen has been disabled - auto outputInfo = Q_XCB_REPLY(xcb_randr_get_output_info, xcb_connection(), - output.output, output.config_timestamp); - if (outputInfo->crtc == XCB_NONE) { - qCDebug(lcQpaScreen) << "output" << screen->name() << "has been disabled"; - destroyScreen(screen); - } else { - qCDebug(lcQpaScreen) << "output" << screen->name() << "has been temporarily disabled for the mode switch"; - // Reset crtc to skip RRCrtcChangeNotify events, - // because they may be invalid in the middle of the mode switch - screen->setCrtc(XCB_NONE); - } - } else { - updateScreen(screen, output); - qCDebug(lcQpaScreen) << "output has changed" << screen; - } - } - - qCDebug(lcQpaScreen) << "primary output is" << qAsConst(m_screens).first()->name(); - } -} - -bool QXcbConnection::checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output) -{ - auto primary = Q_XCB_REPLY(xcb_randr_get_output_primary, xcb_connection(), rootWindow); - if (!primary) - qWarning("failed to get the primary output of the screen"); - - const bool isPrimary = primary ? (primary->output == output) : false; - - return isPrimary; -} - -void QXcbConnection::updateScreen(QXcbScreen *screen, const xcb_randr_output_change_t &outputChange) -{ - screen->setCrtc(outputChange.crtc); // Set the new crtc, because it can be invalid - screen->updateGeometry(outputChange.config_timestamp); - if (screen->mode() != outputChange.mode) - screen->updateRefreshRate(outputChange.mode); - // Only screen which belongs to the primary virtual desktop can be a primary screen - if (screen->screenNumber() == primaryScreenNumber()) { - if (!screen->isPrimary() && checkOutputIsPrimary(outputChange.window, outputChange.output)) { - screen->setPrimary(true); - - // If the screen became primary, reshuffle the order in QGuiApplicationPrivate - const int idx = m_screens.indexOf(screen); - if (idx > 0) { - qAsConst(m_screens).first()->setPrimary(false); - m_screens.swap(0, idx); - } - screen->virtualDesktop()->setPrimaryScreen(screen); - QXcbIntegration::instance()->setPrimaryScreen(screen); - } - } -} - -QXcbScreen *QXcbConnection::createScreen(QXcbVirtualDesktop *virtualDesktop, - const xcb_randr_output_change_t &outputChange, - xcb_randr_get_output_info_reply_t *outputInfo) -{ - QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, outputChange.output, outputInfo); - // Only screen which belongs to the primary virtual desktop can be a primary screen - if (screen->screenNumber() == primaryScreenNumber()) - screen->setPrimary(checkOutputIsPrimary(outputChange.window, outputChange.output)); - - if (screen->isPrimary()) { - if (!m_screens.isEmpty()) - qAsConst(m_screens).first()->setPrimary(false); - - m_screens.prepend(screen); - } else { - m_screens.append(screen); - } - virtualDesktop->addScreen(screen); - QXcbIntegration::instance()->screenAdded(screen, screen->isPrimary()); - - return screen; -} - -void QXcbConnection::destroyScreen(QXcbScreen *screen) -{ - QXcbVirtualDesktop *virtualDesktop = screen->virtualDesktop(); - if (virtualDesktop->screens().count() == 1) { - // If there are no other screens on the same virtual desktop, - // then transform the physical screen into a fake screen. - const QString nameWas = screen->name(); - screen->setOutput(XCB_NONE, nullptr); - qCDebug(lcQpaScreen) << "transformed" << nameWas << "to fake" << screen; - } else { - // There is more than one screen on the same virtual desktop, remove the screen - m_screens.removeOne(screen); - virtualDesktop->removeScreen(screen); - - // When primary screen is removed, set the new primary screen - // which belongs to the primary virtual desktop. - if (screen->isPrimary()) { - QXcbScreen *newPrimary = static_cast(virtualDesktop->screens().at(0)); - newPrimary->setPrimary(true); - const int idx = m_screens.indexOf(newPrimary); - if (idx > 0) - m_screens.swap(0, idx); - QXcbIntegration::instance()->setPrimaryScreen(newPrimary); - } - - QXcbIntegration::instance()->destroyScreen(screen); - } -} - -void QXcbConnection::initializeScreens() -{ - xcb_screen_iterator_t it = xcb_setup_roots_iterator(setup()); - int xcbScreenNumber = 0; // screen number in the xcb sense - QXcbScreen *primaryScreen = nullptr; - while (it.rem) { - // Each "screen" in xcb terminology is a virtual desktop, - // potentially a collection of separate juxtaposed monitors. - // But we want a separate QScreen for each output (e.g. DVI-I-1, VGA-1, etc.) - // which will become virtual siblings. - xcb_screen_t *xcbScreen = it.data; - QXcbVirtualDesktop *virtualDesktop = new QXcbVirtualDesktop(this, xcbScreen, xcbScreenNumber); - m_virtualDesktops.append(virtualDesktop); - QList siblings; - if (hasXRender()) { - // RRGetScreenResourcesCurrent is fast but it may return nothing if the - // configuration is not initialized wrt to the hardware. We should call - // RRGetScreenResources in this case. - auto resources_current = Q_XCB_REPLY(xcb_randr_get_screen_resources_current, - xcb_connection(), xcbScreen->root); - if (!resources_current) { - qWarning("failed to get the current screen resources"); - } else { - xcb_timestamp_t timestamp = 0; - xcb_randr_output_t *outputs = nullptr; - int outputCount = xcb_randr_get_screen_resources_current_outputs_length(resources_current.get()); - if (outputCount) { - timestamp = resources_current->config_timestamp; - outputs = xcb_randr_get_screen_resources_current_outputs(resources_current.get()); - } else { - auto resources = Q_XCB_REPLY(xcb_randr_get_screen_resources, - xcb_connection(), xcbScreen->root); - if (!resources) { - qWarning("failed to get the screen resources"); - } else { - timestamp = resources->config_timestamp; - outputCount = xcb_randr_get_screen_resources_outputs_length(resources.get()); - outputs = xcb_randr_get_screen_resources_outputs(resources.get()); - } - } - - if (outputCount) { - auto primary = Q_XCB_REPLY(xcb_randr_get_output_primary, xcb_connection(), xcbScreen->root); - if (!primary) { - qWarning("failed to get the primary output of the screen"); - } else { - for (int i = 0; i < outputCount; i++) { - auto output = Q_XCB_REPLY_UNCHECKED(xcb_randr_get_output_info, - xcb_connection(), outputs[i], timestamp); - // Invalid, disconnected or disabled output - if (!output) - continue; - - if (output->connection != XCB_RANDR_CONNECTION_CONNECTED) { - qCDebug(lcQpaScreen, "Output %s is not connected", qPrintable( - QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output.get()), - xcb_randr_get_output_info_name_length(output.get())))); - continue; - } - - if (output->crtc == XCB_NONE) { - qCDebug(lcQpaScreen, "Output %s is not enabled", qPrintable( - QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output.get()), - xcb_randr_get_output_info_name_length(output.get())))); - continue; - } - - QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, outputs[i], output.get()); - siblings << screen; - m_screens << screen; - - // There can be multiple outputs per screen, use either - // the first or an exact match. An exact match isn't - // always available if primary->output is XCB_NONE - // or currently disconnected output. - if (primaryScreenNumber() == xcbScreenNumber) { - if (!primaryScreen || (primary && outputs[i] == primary->output)) { - if (primaryScreen) - primaryScreen->setPrimary(false); - primaryScreen = screen; - primaryScreen->setPrimary(true); - siblings.prepend(siblings.takeLast()); - } - } - } - } - } - } - } else if (hasXinerama()) { - // Xinerama is available - auto screens = Q_XCB_REPLY(xcb_xinerama_query_screens, xcb_connection()); - if (screens) { - xcb_xinerama_screen_info_iterator_t it = xcb_xinerama_query_screens_screen_info_iterator(screens.get()); - while (it.rem) { - xcb_xinerama_screen_info_t *screen_info = it.data; - QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, - XCB_NONE, nullptr, - screen_info, it.index); - siblings << screen; - m_screens << screen; - xcb_xinerama_screen_info_next(&it); - } - } - } - if (siblings.isEmpty()) { - // If there are no XRandR outputs or XRandR extension is missing, - // then create a fake/legacy screen. - QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, XCB_NONE, nullptr); - qCDebug(lcQpaScreen) << "created fake screen" << screen; - m_screens << screen; - if (primaryScreenNumber() == xcbScreenNumber) { - primaryScreen = screen; - primaryScreen->setPrimary(true); - } - siblings << screen; - } - virtualDesktop->setScreens(siblings); - xcb_screen_next(&it); - ++xcbScreenNumber; - } // for each xcb screen - - for (QXcbVirtualDesktop *virtualDesktop : qAsConst(m_virtualDesktops)) - virtualDesktop->subscribeToXFixesSelectionNotify(); - - if (m_virtualDesktops.isEmpty()) { - qFatal("QXcbConnection: no screens available"); - } else { - // Ensure the primary screen is first on the list - if (primaryScreen) { - if (qAsConst(m_screens).first() != primaryScreen) { - m_screens.removeOne(primaryScreen); - m_screens.prepend(primaryScreen); - } - } - - // Push the screens to QGuiApplication - for (QXcbScreen *screen : qAsConst(m_screens)) { - qCDebug(lcQpaScreen) << "adding" << screen << "(Primary:" << screen->isPrimary() << ")"; - QXcbIntegration::instance()->screenAdded(screen, screen->isPrimary()); - } - - qCDebug(lcQpaScreen) << "primary output is" << qAsConst(m_screens).first()->name(); - } -} - QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, xcb_visualid_t defaultVisualId, const char *displayName) : QXcbBasicConnection(displayName) , m_canGrabServer(canGrabServer) @@ -475,8 +105,6 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra m_xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP").toLower(); - selectXRandrEvents(); - initializeScreens(); #if QT_CONFIG(xcb_xinput) diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index fcc1309afe..49e79ec3fd 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -330,7 +330,15 @@ private: ScrollingDevice *scrollingDeviceForId(int id); static bool xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value); -#endif + + QHash m_touchDevices; + struct StartSystemMoveResizeInfo { + xcb_window_t window = XCB_NONE; + uint16_t deviceid; + uint32_t pointid; + int corner; + } m_startSystemMoveResizeInfo; +#endif // QT_CONFIG(xcb_xinput) const bool m_canGrabServer; const xcb_visualid_t m_defaultVisualId; @@ -353,15 +361,6 @@ private: QXcbEventQueue *m_eventQueue = nullptr; -#if QT_CONFIG(xcb_xinput) - QHash m_touchDevices; - struct StartSystemMoveResizeInfo { - xcb_window_t window = XCB_NONE; - uint16_t deviceid; - uint32_t pointid; - int corner; - } m_startSystemMoveResizeInfo; -#endif WindowMapper m_mapper; QVector m_peekFuncs; diff --git a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp new file mode 100644 index 0000000000..4c380bf39f --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp @@ -0,0 +1,416 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qxcbconnection.h" +#include "qxcbscreen.h" +#include "qxcbintegration.h" + +#include +#include +#include + +#include + +void QXcbConnection::selectXRandrEvents() +{ + xcb_screen_iterator_t rootIter = xcb_setup_roots_iterator(setup()); + for (; rootIter.rem; xcb_screen_next(&rootIter)) { + xcb_randr_select_input(xcb_connection(), + rootIter.data->root, + XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE | + XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE | + XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE | + XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY + ); + } +} + +QXcbScreen* QXcbConnection::findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc) const +{ + for (QXcbScreen *screen : m_screens) { + if (screen->root() == rootWindow && screen->crtc() == crtc) + return screen; + } + + return nullptr; +} + +QXcbScreen* QXcbConnection::findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output) const +{ + for (QXcbScreen *screen : m_screens) { + if (screen->root() == rootWindow && screen->output() == output) + return screen; + } + + return nullptr; +} + +QXcbVirtualDesktop* QXcbConnection::virtualDesktopForRootWindow(xcb_window_t rootWindow) const +{ + for (QXcbVirtualDesktop *virtualDesktop : m_virtualDesktops) { + if (virtualDesktop->screen()->root == rootWindow) + return virtualDesktop; + } + + return nullptr; +} + +/*! + \brief Synchronizes the screen list, adds new screens, removes deleted ones +*/ +void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event) +{ + if (event->subCode == XCB_RANDR_NOTIFY_CRTC_CHANGE) { + xcb_randr_crtc_change_t crtc = event->u.cc; + QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(crtc.window); + if (!virtualDesktop) + // Not for us + return; + + QXcbScreen *screen = findScreenForCrtc(crtc.window, crtc.crtc); + qCDebug(lcQpaScreen) << "QXcbConnection: XCB_RANDR_NOTIFY_CRTC_CHANGE:" << crtc.crtc + << "mode" << crtc.mode << "relevant screen" << screen; + // Only update geometry when there's a valid mode on the CRTC + // CRTC with node mode could mean that output has been disabled, and we'll + // get RRNotifyOutputChange notification for that. + if (screen && crtc.mode) { + if (crtc.rotation == XCB_RANDR_ROTATION_ROTATE_90 || + crtc.rotation == XCB_RANDR_ROTATION_ROTATE_270) + std::swap(crtc.width, crtc.height); + screen->updateGeometry(QRect(crtc.x, crtc.y, crtc.width, crtc.height), crtc.rotation); + if (screen->mode() != crtc.mode) + screen->updateRefreshRate(crtc.mode); + } + + } else if (event->subCode == XCB_RANDR_NOTIFY_OUTPUT_CHANGE) { + xcb_randr_output_change_t output = event->u.oc; + QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(output.window); + if (!virtualDesktop) + // Not for us + return; + + QXcbScreen *screen = findScreenForOutput(output.window, output.output); + qCDebug(lcQpaScreen) << "QXcbConnection: XCB_RANDR_NOTIFY_OUTPUT_CHANGE:" << output.output; + + if (screen && output.connection == XCB_RANDR_CONNECTION_DISCONNECTED) { + qCDebug(lcQpaScreen) << "screen" << screen->name() << "has been disconnected"; + destroyScreen(screen); + } else if (!screen && output.connection == XCB_RANDR_CONNECTION_CONNECTED) { + // New XRandR output is available and it's enabled + if (output.crtc != XCB_NONE && output.mode != XCB_NONE) { + auto outputInfo = Q_XCB_REPLY(xcb_randr_get_output_info, xcb_connection(), + output.output, output.config_timestamp); + // Find a fake screen + const auto scrs = virtualDesktop->screens(); + for (QPlatformScreen *scr : scrs) { + QXcbScreen *xcbScreen = static_cast(scr); + if (xcbScreen->output() == XCB_NONE) { + screen = xcbScreen; + break; + } + } + + if (screen) { + QString nameWas = screen->name(); + // Transform the fake screen into a physical screen + screen->setOutput(output.output, outputInfo.get()); + updateScreen(screen, output); + qCDebug(lcQpaScreen) << "output" << screen->name() + << "is connected and enabled; was fake:" << nameWas; + } else { + screen = createScreen(virtualDesktop, output, outputInfo.get()); + qCDebug(lcQpaScreen) << "output" << screen->name() << "is connected and enabled"; + } + QHighDpiScaling::updateHighDpiScaling(); + } + } else if (screen) { + if (output.crtc == XCB_NONE && output.mode == XCB_NONE) { + // Screen has been disabled + auto outputInfo = Q_XCB_REPLY(xcb_randr_get_output_info, xcb_connection(), + output.output, output.config_timestamp); + if (outputInfo->crtc == XCB_NONE) { + qCDebug(lcQpaScreen) << "output" << screen->name() << "has been disabled"; + destroyScreen(screen); + } else { + qCDebug(lcQpaScreen) << "output" << screen->name() << "has been temporarily disabled for the mode switch"; + // Reset crtc to skip RRCrtcChangeNotify events, + // because they may be invalid in the middle of the mode switch + screen->setCrtc(XCB_NONE); + } + } else { + updateScreen(screen, output); + qCDebug(lcQpaScreen) << "output has changed" << screen; + } + } + + qCDebug(lcQpaScreen) << "primary output is" << qAsConst(m_screens).first()->name(); + } +} + +bool QXcbConnection::checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output) +{ + auto primary = Q_XCB_REPLY(xcb_randr_get_output_primary, xcb_connection(), rootWindow); + if (!primary) + qWarning("failed to get the primary output of the screen"); + + const bool isPrimary = primary ? (primary->output == output) : false; + + return isPrimary; +} + +void QXcbConnection::updateScreen(QXcbScreen *screen, const xcb_randr_output_change_t &outputChange) +{ + screen->setCrtc(outputChange.crtc); // Set the new crtc, because it can be invalid + screen->updateGeometry(outputChange.config_timestamp); + if (screen->mode() != outputChange.mode) + screen->updateRefreshRate(outputChange.mode); + // Only screen which belongs to the primary virtual desktop can be a primary screen + if (screen->screenNumber() == primaryScreenNumber()) { + if (!screen->isPrimary() && checkOutputIsPrimary(outputChange.window, outputChange.output)) { + screen->setPrimary(true); + + // If the screen became primary, reshuffle the order in QGuiApplicationPrivate + const int idx = m_screens.indexOf(screen); + if (idx > 0) { + qAsConst(m_screens).first()->setPrimary(false); + m_screens.swap(0, idx); + } + screen->virtualDesktop()->setPrimaryScreen(screen); + QXcbIntegration::instance()->setPrimaryScreen(screen); + } + } +} + +QXcbScreen *QXcbConnection::createScreen(QXcbVirtualDesktop *virtualDesktop, + const xcb_randr_output_change_t &outputChange, + xcb_randr_get_output_info_reply_t *outputInfo) +{ + QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, outputChange.output, outputInfo); + // Only screen which belongs to the primary virtual desktop can be a primary screen + if (screen->screenNumber() == primaryScreenNumber()) + screen->setPrimary(checkOutputIsPrimary(outputChange.window, outputChange.output)); + + if (screen->isPrimary()) { + if (!m_screens.isEmpty()) + qAsConst(m_screens).first()->setPrimary(false); + + m_screens.prepend(screen); + } else { + m_screens.append(screen); + } + virtualDesktop->addScreen(screen); + QXcbIntegration::instance()->screenAdded(screen, screen->isPrimary()); + + return screen; +} + +void QXcbConnection::destroyScreen(QXcbScreen *screen) +{ + QXcbVirtualDesktop *virtualDesktop = screen->virtualDesktop(); + if (virtualDesktop->screens().count() == 1) { + // If there are no other screens on the same virtual desktop, + // then transform the physical screen into a fake screen. + const QString nameWas = screen->name(); + screen->setOutput(XCB_NONE, nullptr); + qCDebug(lcQpaScreen) << "transformed" << nameWas << "to fake" << screen; + } else { + // There is more than one screen on the same virtual desktop, remove the screen + m_screens.removeOne(screen); + virtualDesktop->removeScreen(screen); + + // When primary screen is removed, set the new primary screen + // which belongs to the primary virtual desktop. + if (screen->isPrimary()) { + QXcbScreen *newPrimary = static_cast(virtualDesktop->screens().at(0)); + newPrimary->setPrimary(true); + const int idx = m_screens.indexOf(newPrimary); + if (idx > 0) + m_screens.swap(0, idx); + QXcbIntegration::instance()->setPrimaryScreen(newPrimary); + } + + QXcbIntegration::instance()->destroyScreen(screen); + } +} + +void QXcbConnection::initializeScreens() +{ + selectXRandrEvents(); + + xcb_screen_iterator_t it = xcb_setup_roots_iterator(setup()); + int xcbScreenNumber = 0; // screen number in the xcb sense + QXcbScreen *primaryScreen = nullptr; + while (it.rem) { + // Each "screen" in xcb terminology is a virtual desktop, + // potentially a collection of separate juxtaposed monitors. + // But we want a separate QScreen for each output (e.g. DVI-I-1, VGA-1, etc.) + // which will become virtual siblings. + xcb_screen_t *xcbScreen = it.data; + QXcbVirtualDesktop *virtualDesktop = new QXcbVirtualDesktop(this, xcbScreen, xcbScreenNumber); + m_virtualDesktops.append(virtualDesktop); + QList siblings; + if (hasXRender()) { + // RRGetScreenResourcesCurrent is fast but it may return nothing if the + // configuration is not initialized wrt to the hardware. We should call + // RRGetScreenResources in this case. + auto resources_current = Q_XCB_REPLY(xcb_randr_get_screen_resources_current, + xcb_connection(), xcbScreen->root); + if (!resources_current) { + qWarning("failed to get the current screen resources"); + } else { + xcb_timestamp_t timestamp = 0; + xcb_randr_output_t *outputs = nullptr; + int outputCount = xcb_randr_get_screen_resources_current_outputs_length(resources_current.get()); + if (outputCount) { + timestamp = resources_current->config_timestamp; + outputs = xcb_randr_get_screen_resources_current_outputs(resources_current.get()); + } else { + auto resources = Q_XCB_REPLY(xcb_randr_get_screen_resources, + xcb_connection(), xcbScreen->root); + if (!resources) { + qWarning("failed to get the screen resources"); + } else { + timestamp = resources->config_timestamp; + outputCount = xcb_randr_get_screen_resources_outputs_length(resources.get()); + outputs = xcb_randr_get_screen_resources_outputs(resources.get()); + } + } + + if (outputCount) { + auto primary = Q_XCB_REPLY(xcb_randr_get_output_primary, xcb_connection(), xcbScreen->root); + if (!primary) { + qWarning("failed to get the primary output of the screen"); + } else { + for (int i = 0; i < outputCount; i++) { + auto output = Q_XCB_REPLY_UNCHECKED(xcb_randr_get_output_info, + xcb_connection(), outputs[i], timestamp); + // Invalid, disconnected or disabled output + if (!output) + continue; + + if (output->connection != XCB_RANDR_CONNECTION_CONNECTED) { + qCDebug(lcQpaScreen, "Output %s is not connected", qPrintable( + QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output.get()), + xcb_randr_get_output_info_name_length(output.get())))); + continue; + } + + if (output->crtc == XCB_NONE) { + qCDebug(lcQpaScreen, "Output %s is not enabled", qPrintable( + QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output.get()), + xcb_randr_get_output_info_name_length(output.get())))); + continue; + } + + QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, outputs[i], output.get()); + siblings << screen; + m_screens << screen; + + // There can be multiple outputs per screen, use either + // the first or an exact match. An exact match isn't + // always available if primary->output is XCB_NONE + // or currently disconnected output. + if (primaryScreenNumber() == xcbScreenNumber) { + if (!primaryScreen || (primary && outputs[i] == primary->output)) { + if (primaryScreen) + primaryScreen->setPrimary(false); + primaryScreen = screen; + primaryScreen->setPrimary(true); + siblings.prepend(siblings.takeLast()); + } + } + } + } + } + } + } else if (hasXinerama()) { + // Xinerama is available + auto screens = Q_XCB_REPLY(xcb_xinerama_query_screens, xcb_connection()); + if (screens) { + xcb_xinerama_screen_info_iterator_t it = xcb_xinerama_query_screens_screen_info_iterator(screens.get()); + while (it.rem) { + xcb_xinerama_screen_info_t *screen_info = it.data; + QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, + XCB_NONE, nullptr, + screen_info, it.index); + siblings << screen; + m_screens << screen; + xcb_xinerama_screen_info_next(&it); + } + } + } + if (siblings.isEmpty()) { + // If there are no XRandR outputs or XRandR extension is missing, + // then create a fake/legacy screen. + QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, XCB_NONE, nullptr); + qCDebug(lcQpaScreen) << "created fake screen" << screen; + m_screens << screen; + if (primaryScreenNumber() == xcbScreenNumber) { + primaryScreen = screen; + primaryScreen->setPrimary(true); + } + siblings << screen; + } + virtualDesktop->setScreens(siblings); + xcb_screen_next(&it); + ++xcbScreenNumber; + } // for each xcb screen + + for (QXcbVirtualDesktop *virtualDesktop : qAsConst(m_virtualDesktops)) + virtualDesktop->subscribeToXFixesSelectionNotify(); + + if (m_virtualDesktops.isEmpty()) { + qFatal("QXcbConnection: no screens available"); + } else { + // Ensure the primary screen is first on the list + if (primaryScreen) { + if (qAsConst(m_screens).first() != primaryScreen) { + m_screens.removeOne(primaryScreen); + m_screens.prepend(primaryScreen); + } + } + + // Push the screens to QGuiApplication + for (QXcbScreen *screen : qAsConst(m_screens)) { + qCDebug(lcQpaScreen) << "adding" << screen << "(Primary:" << screen->isPrimary() << ")"; + QXcbIntegration::instance()->screenAdded(screen, screen->isPrimary()); + } + + qCDebug(lcQpaScreen) << "primary output is" << qAsConst(m_screens).first()->name(); + } +} diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index c0704e4c18..c65b145fb6 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -33,6 +33,7 @@ SOURCES = \ qxcbeventqueue.cpp \ qxcbeventdispatcher.cpp \ qxcbconnection_basic.cpp \ + qxcbconnection_screens.cpp \ qxcbatom.cpp HEADERS = \ -- cgit v1.2.3 From b4bd5f9df3e69da707513ba544537c80a8564fb4 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Wed, 8 Aug 2018 14:15:06 +0200 Subject: xcb: cleanup _MOTIF_WM_HINTS handling The existing code was difficult to follow, it contained some code duplication, inconsistencies and legacy code (mwm/dtwm support). Most of this code was copied over from Qt 4 as is, with some unexplainable (accidental?) modifications. Most of Motif code was never ported over to Qt5. In addition to the properties and protocols described in ICCCM, Motif uses properties and protocols of its own. In Qt4 we had an implementation of Motif DnD protocol. This was never ported over and mentions of this support was removed on Oct 2012, 4c41cb48d0356a28190c300fd4cc5e03f824b870. Nobody has complained for all these years, so it is safe to remove the remaining leftovers. Motif style support also was removed around the same time 4c41cb48d0356a28190c300fd4cc5e03f824b870. Keeping only those Motif hints that do not have any replacement in modern window manager specifications - decorations hints. MWM_INPUT_*MODEL* in modern specs was replaced by _NET_WM_STATE_MODAL The existing code was setting _MOTIF_WM_HINTS from 2 places - from QWindow setter (::setWindowFlags) and again before mapping the window (::show). We don't need the logic from updateMotifWmHintsBeforeMap(). That function read the current value of _MOTIF_WM_HINTS and merged in few additional hints, hints that are not relevant based on all the reasons from above. Change-Id: I9cb10bcad9bfac8762e3909895c2e9de613e622c Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/qxcbatom.cpp | 10 --- src/plugins/platforms/xcb/qxcbatom.h | 10 --- src/plugins/platforms/xcb/qxcbwindow.cpp | 132 ++++--------------------------- src/plugins/platforms/xcb/qxcbwindow.h | 5 +- 4 files changed, 18 insertions(+), 139 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbatom.cpp b/src/plugins/platforms/xcb/qxcbatom.cpp index 9255a57a4f..ecb73cb90b 100644 --- a/src/plugins/platforms/xcb/qxcbatom.cpp +++ b/src/plugins/platforms/xcb/qxcbatom.cpp @@ -183,16 +183,6 @@ static const char *xcb_atomnames = { "XdndActionMove\0" "XdndActionPrivate\0" - // Motif DND - "_MOTIF_DRAG_AND_DROP_MESSAGE\0" - "_MOTIF_DRAG_INITIATOR_INFO\0" - "_MOTIF_DRAG_RECEIVER_INFO\0" - "_MOTIF_DRAG_WINDOW\0" - "_MOTIF_DRAG_TARGETS\0" - - "XmTRANSFER_SUCCESS\0" - "XmTRANSFER_FAILURE\0" - // Xkb "_XKB_RULES_NAMES\0" diff --git a/src/plugins/platforms/xcb/qxcbatom.h b/src/plugins/platforms/xcb/qxcbatom.h index b6cc159035..233d2eadb7 100644 --- a/src/plugins/platforms/xcb/qxcbatom.h +++ b/src/plugins/platforms/xcb/qxcbatom.h @@ -184,16 +184,6 @@ public: XdndActionMove, XdndActionPrivate, - // Motif DND - _MOTIF_DRAG_AND_DROP_MESSAGE, - _MOTIF_DRAG_INITIATOR_INFO, - _MOTIF_DRAG_RECEIVER_INFO, - _MOTIF_DRAG_WINDOW, - _MOTIF_DRAG_TARGETS, - - XmTRANSFER_SUCCESS, - XmTRANSFER_FAILURE, - // Xkb _XKB_RULES_NAMES, diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index f36bb5a51e..e56f6b13d8 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -118,8 +118,6 @@ enum { defaultWindowHeight = 160 }; -//#ifdef NET_WM_STATE_DEBUG - QT_BEGIN_NAMESPACE Q_DECLARE_TYPEINFO(xcb_rectangle_t, Q_PRIMITIVE_TYPE); @@ -756,9 +754,6 @@ void QXcbWindow::show() if (!transientXcbParent) xcb_delete_property(xcb_connection(), m_window, XCB_ATOM_WM_TRANSIENT_FOR); - // update _MOTIF_WM_HINTS - updateMotifWmHintsBeforeMap(); - // update _NET_WM_STATE updateNetWmStateBeforeMap(); } @@ -909,8 +904,6 @@ void QXcbWindow::doFocusOut() struct QtMotifWmHints { quint32 flags, functions, decorations; - qint32 input_mode; - quint32 status; }; enum { @@ -932,50 +925,8 @@ enum { MWM_DECOR_MENU = (1L << 4), MWM_DECOR_MINIMIZE = (1L << 5), MWM_DECOR_MAXIMIZE = (1L << 6), - - MWM_HINTS_INPUT_MODE = (1L << 2), - - MWM_INPUT_MODELESS = 0L, - MWM_INPUT_PRIMARY_APPLICATION_MODAL = 1L, - MWM_INPUT_FULL_APPLICATION_MODAL = 3L }; -static QtMotifWmHints getMotifWmHints(QXcbConnection *c, xcb_window_t window) -{ - QtMotifWmHints hints; - - auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, c->xcb_connection(), 0, window, - c->atom(QXcbAtom::_MOTIF_WM_HINTS), c->atom(QXcbAtom::_MOTIF_WM_HINTS), 0, 20); - - if (reply && reply->format == 32 && reply->type == c->atom(QXcbAtom::_MOTIF_WM_HINTS)) { - hints = *((QtMotifWmHints *)xcb_get_property_value(reply.get())); - } else { - hints.flags = 0L; - hints.functions = MWM_FUNC_ALL; - hints.decorations = MWM_DECOR_ALL; - hints.input_mode = 0L; - hints.status = 0L; - } - - return hints; -} - -static void setMotifWmHints(QXcbConnection *c, xcb_window_t window, const QtMotifWmHints &hints) -{ - if (hints.flags != 0l) { - xcb_change_property(c->xcb_connection(), - XCB_PROP_MODE_REPLACE, - window, - c->atom(QXcbAtom::_MOTIF_WM_HINTS), - c->atom(QXcbAtom::_MOTIF_WM_HINTS), - 32, - 5, - &hints); - } else { - xcb_delete_property(c->xcb_connection(), window, c->atom(QXcbAtom::_MOTIF_WM_HINTS)); - } -} - QXcbWindow::NetWmStates QXcbWindow::netWmStates() { NetWmStates result(0); @@ -1004,9 +955,7 @@ QXcbWindow::NetWmStates QXcbWindow::netWmStates() if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION))) result |= NetWmStateDemandsAttention; } else { -#ifdef NET_WM_STATE_DEBUG - printf("getting net wm state (%x), empty\n", m_window); -#endif + qCDebug(lcQpaXcb, "getting net wm state (%x), empty\n", m_window); } return result; @@ -1079,22 +1028,18 @@ void QXcbWindow::setWindowFlags(Qt::WindowFlags flags) setWmWindowType(wmWindowTypes, flags); setNetWmStateWindowFlags(flags); - setMotifWindowFlags(flags); + setMotifWmHints(flags); setTransparentForMouseEvents(flags & Qt::WindowTransparentForInput); updateDoesNotAcceptFocus(flags & Qt::WindowDoesNotAcceptFocus); } -void QXcbWindow::setMotifWindowFlags(Qt::WindowFlags flags) +void QXcbWindow::setMotifWmHints(Qt::WindowFlags flags) { Qt::WindowType type = static_cast(int(flags & Qt::WindowType_Mask)); QtMotifWmHints mwmhints; - mwmhints.flags = 0L; - mwmhints.functions = 0L; - mwmhints.decorations = 0; - mwmhints.input_mode = 0L; - mwmhints.status = 0L; + memset(&mwmhints, 0, sizeof(mwmhints)); if (type != Qt::SplashScreen) { mwmhints.flags |= MWM_HINTS_DECORATIONS; @@ -1152,7 +1097,18 @@ void QXcbWindow::setMotifWindowFlags(Qt::WindowFlags flags) mwmhints.decorations = 0; } - setMotifWmHints(connection(), m_window, mwmhints); + if (mwmhints.flags) { + xcb_change_property(xcb_connection(), + XCB_PROP_MODE_REPLACE, + m_window, + atom(QXcbAtom::_MOTIF_WM_HINTS), + atom(QXcbAtom::_MOTIF_WM_HINTS), + 32, + 5, + &mwmhints); + } else { + xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_MOTIF_WM_HINTS)); + } } void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two) @@ -1225,62 +1181,6 @@ void QXcbWindow::setWindowState(Qt::WindowStates state) m_windowState = state; } -void QXcbWindow::updateMotifWmHintsBeforeMap() -{ - QtMotifWmHints mwmhints = getMotifWmHints(connection(), m_window); - - if (window()->modality() != Qt::NonModal) { - switch (window()->modality()) { - case Qt::WindowModal: - mwmhints.input_mode = MWM_INPUT_PRIMARY_APPLICATION_MODAL; - break; - case Qt::ApplicationModal: - default: - mwmhints.input_mode = MWM_INPUT_FULL_APPLICATION_MODAL; - break; - } - mwmhints.flags |= MWM_HINTS_INPUT_MODE; - } else { - mwmhints.input_mode = MWM_INPUT_MODELESS; - mwmhints.flags &= ~MWM_HINTS_INPUT_MODE; - } - - if (windowMinimumSize() == windowMaximumSize()) { - // fixed size, remove the resize handle (since mwm/dtwm - // isn't smart enough to do it itself) - mwmhints.flags |= MWM_HINTS_FUNCTIONS; - if (mwmhints.functions == MWM_FUNC_ALL) { - mwmhints.functions = MWM_FUNC_MOVE; - } else { - mwmhints.functions &= ~MWM_FUNC_RESIZE; - } - - if (mwmhints.decorations == MWM_DECOR_ALL) { - mwmhints.flags |= MWM_HINTS_DECORATIONS; - mwmhints.decorations = (MWM_DECOR_BORDER - | MWM_DECOR_TITLE - | MWM_DECOR_MENU); - } else { - mwmhints.decorations &= ~MWM_DECOR_RESIZEH; - } - } - - if (window()->flags() & Qt::WindowMinimizeButtonHint) { - mwmhints.flags |= MWM_HINTS_DECORATIONS; - mwmhints.decorations |= MWM_DECOR_MINIMIZE; - mwmhints.functions |= MWM_FUNC_MINIMIZE; - } - if (window()->flags() & Qt::WindowMaximizeButtonHint) { - mwmhints.flags |= MWM_HINTS_DECORATIONS; - mwmhints.decorations |= MWM_DECOR_MAXIMIZE; - mwmhints.functions |= MWM_FUNC_MAXIMIZE; - } - if (window()->flags() & Qt::WindowCloseButtonHint) - mwmhints.functions |= MWM_FUNC_CLOSE; - - setMotifWmHints(connection(), m_window, mwmhints); -} - void QXcbWindow::updateNetWmStateBeforeMap() { NetWmStates states(0); diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index f7d76ed3b2..6667f45343 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -199,10 +199,9 @@ protected: NetWmStates netWmStates(); void setNetWmStates(NetWmStates); - void setMotifWindowFlags(Qt::WindowFlags flags); - void setNetWmStateWindowFlags(Qt::WindowFlags flags); + void setMotifWmHints(Qt::WindowFlags flags); - void updateMotifWmHintsBeforeMap(); + void setNetWmStateWindowFlags(Qt::WindowFlags flags); void updateNetWmStateBeforeMap(); void setTransparentForMouseEvents(bool transparent); -- cgit v1.2.3 From 5e6bbbc1b86905c4c64aba34632b668ef44dc8f4 Mon Sep 17 00:00:00 2001 From: Mathieu Velten Date: Wed, 6 Jun 2018 18:07:03 +0200 Subject: xcb: use 128 as a reference DPI for small screens This is a better version of 23b139038a1dc9a769a358ab112453abcdd39290 which was reverted. Task-number: QTBUG-68620 Task-number: QTBUG-53022 Task-number: QTBUG-57211 Change-Id: I0b37fc261945c542bbfb30cecfe4b0a97c655e3c Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/qxcbscreen.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 8c0ce8dd7e..35e90e4206 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -747,7 +747,11 @@ void QXcbScreen::updateGeometry(const QRect &geometry, uint8_t rotation) m_sizeMillimeters = sizeInMillimeters(geometry.size(), m_virtualDesktop->dpi()); qreal dpi = geometry.width() / physicalSize().width() * qreal(25.4); - m_pixelDensity = qMax(1, qRound(dpi/96)); + + // Use 128 as a reference DPI on small screens. This favors "small UI" over "large UI". + qreal referenceDpi = physicalSize().width() <= 320 ? 128 : 96; + + m_pixelDensity = qMax(1, qRound(dpi/referenceDpi)); m_geometry = geometry; m_availableGeometry = geometry & m_virtualDesktop->workArea(); QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry); -- cgit v1.2.3 From 0aa27af8014f5344d604b3f4eaa5f0a2fb2b44e5 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 16 Oct 2018 13:19:24 +0200 Subject: Windows QPA: Add helper function to obtain DPI-dependent metrics on Windows 10 Use newly introduced SystemParametersInfoForDpi() API with some convenience overloads. Task-number: QTBUG-4362 Change-Id: I4c41c700007bf7cc4fd5868356e3145c136704c0 Reviewed-by: Oliver Wolff --- src/plugins/platforms/windows/qwindowscontext.cpp | 40 +++++++++++++++++++++++ src/plugins/platforms/windows/qwindowscontext.h | 14 ++++++++ src/plugins/platforms/windows/qwindowstheme.cpp | 4 +-- 3 files changed, 55 insertions(+), 3 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 4959ed952d..1f80ac5872 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -213,6 +213,7 @@ void QWindowsUser32DLL::init() enableNonClientDpiScaling = (EnableNonClientDpiScaling)library.resolve("EnableNonClientDpiScaling"); getWindowDpiAwarenessContext = (GetWindowDpiAwarenessContext)library.resolve("GetWindowDpiAwarenessContext"); getAwarenessFromDpiAwarenessContext = (GetAwarenessFromDpiAwarenessContext)library.resolve("GetAwarenessFromDpiAwarenessContext"); + systemParametersInfoForDpi = (SystemParametersInfoForDpi)library.resolve("SystemParametersInfoForDpi"); } } @@ -916,6 +917,45 @@ QByteArray QWindowsContext::comErrorString(HRESULT hr) return result; } +bool QWindowsContext::systemParametersInfo(unsigned action, unsigned param, void *out, + unsigned dpi) +{ + const BOOL result = QWindowsContext::user32dll.systemParametersInfoForDpi != nullptr && dpi != 0 + ? QWindowsContext::user32dll.systemParametersInfoForDpi(action, param, out, 0, dpi) + : SystemParametersInfo(action, param, out, 0); + return result == TRUE; +} + +bool QWindowsContext::systemParametersInfoForScreen(unsigned action, unsigned param, void *out, + const QPlatformScreen *screen) +{ + return systemParametersInfo(action, param, out, screen ? screen->logicalDpi().first : 0); +} + +bool QWindowsContext::systemParametersInfoForWindow(unsigned action, unsigned param, void *out, + const QPlatformWindow *win) +{ + return systemParametersInfoForScreen(action, param, out, win ? win->screen() : nullptr); +} + +bool QWindowsContext::nonClientMetrics(NONCLIENTMETRICS *ncm, unsigned dpi) +{ + memset(ncm, 0, sizeof(NONCLIENTMETRICS)); + ncm->cbSize = sizeof(NONCLIENTMETRICS); + return systemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm->cbSize, ncm, dpi); +} + +bool QWindowsContext::nonClientMetricsForScreen(NONCLIENTMETRICS *ncm, + const QPlatformScreen *screen) +{ + return nonClientMetrics(ncm, screen ? screen->logicalDpi().first : 0); +} + +bool QWindowsContext::nonClientMetricsForWindow(NONCLIENTMETRICS *ncm, const QPlatformWindow *win) +{ + return nonClientMetricsForScreen(ncm, win ? win->screen() : nullptr); +} + static inline QWindowsInputContext *windowsInputContext() { return qobject_cast(QWindowsIntegration::instance()->inputContext()); diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index 19e9c26130..fd6c72668c 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -70,6 +70,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaTrayIcon) class QWindow; class QPlatformScreen; +class QPlatformWindow; class QWindowsMenuBar; class QWindowsScreenManager; class QWindowsTabletSupport; @@ -104,6 +105,7 @@ struct QWindowsUser32DLL typedef BOOL (WINAPI *EnableNonClientDpiScaling)(HWND); typedef int (WINAPI *GetWindowDpiAwarenessContext)(HWND); typedef int (WINAPI *GetAwarenessFromDpiAwarenessContext)(int); + typedef BOOL (WINAPI *SystemParametersInfoForDpi)(UINT, UINT, PVOID, UINT, UINT); // Windows pointer functions (Windows 8 or later). EnableMouseInPointer enableMouseInPointer = nullptr; @@ -132,6 +134,7 @@ struct QWindowsUser32DLL EnableNonClientDpiScaling enableNonClientDpiScaling = nullptr; GetWindowDpiAwarenessContext getWindowDpiAwarenessContext = nullptr; GetAwarenessFromDpiAwarenessContext getAwarenessFromDpiAwarenessContext = nullptr; + SystemParametersInfoForDpi systemParametersInfoForDpi = nullptr; }; // Shell scaling library (Windows 8.1 onwards) @@ -237,6 +240,17 @@ public: bool asyncExpose() const; void setAsyncExpose(bool value); + static bool systemParametersInfo(unsigned action, unsigned param, void *out, unsigned dpi = 0); + static bool systemParametersInfoForScreen(unsigned action, unsigned param, void *out, + const QPlatformScreen *screen = nullptr); + static bool systemParametersInfoForWindow(unsigned action, unsigned param, void *out, + const QPlatformWindow *win = nullptr); + static bool nonClientMetrics(NONCLIENTMETRICS *ncm, unsigned dpi = 0); + static bool nonClientMetricsForScreen(NONCLIENTMETRICS *ncm, + const QPlatformScreen *screen = nullptr); + static bool nonClientMetricsForWindow(NONCLIENTMETRICS *ncm, + const QPlatformWindow *win = nullptr); + static DWORD readAdvancedExplorerSettings(const wchar_t *subKey, DWORD defaultValue); QTouchDevice *touchDevice() const; diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index d01a7b0a8a..4b70e915a8 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -507,9 +507,7 @@ void QWindowsTheme::refreshFonts() if (!QGuiApplication::desktopSettingsAware()) return; NONCLIENTMETRICS ncm; - ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT); - SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0); - + QWindowsContext::nonClientMetrics(&ncm); const QFont menuFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMenuFont); const QFont messageBoxFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont); const QFont statusFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfStatusFont); -- cgit v1.2.3 From 5ac2b9ef5904d8130f6de1ad758b5140784045d4 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 15 Oct 2018 14:52:47 +0200 Subject: Windows QPA: Fix maximizing windows without title bar Extends the code from qtbase/0d6612af65161f6e659af6985bb2c0b76accb856 to cover the case of windows without title bar, too. Fixes: QTBUG-4362 Task-number: QTBUG-8361 Change-Id: I5cff8814174069922936f3fcfbb3aef154c7a7e7 Reviewed-by: Oliver Wolff --- src/plugins/platforms/windows/qwindowswindow.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 9c31409644..f340f16679 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -2416,6 +2416,13 @@ void QWindowsWindow::setFrameStrutEventsEnabled(bool enabled) } } +static int getBorderWidth(const QPlatformScreen *screen) +{ + NONCLIENTMETRICS ncm; + QWindowsContext::nonClientMetricsForScreen(&ncm, screen); + return ncm.iBorderWidth + ncm.iPaddedBorderWidth + 2; +} + void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const { // We don't apply the min/max size hint as we change the dpi, because we did not adjust the @@ -2425,10 +2432,11 @@ void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const hint.applyToMinMaxInfo(m_data.hwnd, mmi); } - if ((testFlag(WithinMaximize) || (window()->windowStates() & Qt::WindowMinimized)) - && (m_data.flags & Qt::FramelessWindowHint)) { - // This block fixes QTBUG-8361: Frameless windows shouldn't cover the - // taskbar when maximized + // This block fixes QTBUG-8361, QTBUG-4362: Frameless/title-less windows shouldn't cover the + // taskbar when maximized + if ((testFlag(WithinMaximize) || window()->windowStates().testFlag(Qt::WindowMinimized)) + && (m_data.flags.testFlag(Qt::FramelessWindowHint) + || (m_data.flags.testFlag(Qt::CustomizeWindowHint) && !m_data.flags.testFlag(Qt::WindowTitleHint)))) { const QScreen *screen = window()->screen(); // Documentation of MINMAXINFO states that it will only work for the primary screen @@ -2442,6 +2450,14 @@ void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const // If you have the taskbar on top, or on the left you don't want it at (0,0): mmi->ptMaxPosition.x = availableGeometry.x(); mmi->ptMaxPosition.y = availableGeometry.y(); + if (!m_data.flags.testFlag(Qt::FramelessWindowHint)) { + const int borderWidth = getBorderWidth(screen->handle()); + mmi->ptMaxSize.x += borderWidth * 2; + mmi->ptMaxSize.y += borderWidth * 2; + mmi->ptMaxTrackSize = mmi->ptMaxSize; + mmi->ptMaxPosition.x -= borderWidth; + mmi->ptMaxPosition.y -= borderWidth; + } } else if (!screen){ qWarning("window()->screen() returned a null screen"); } -- cgit v1.2.3 From 96218681f22588b93999626684ec73717207bb39 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Sun, 14 Oct 2018 20:26:38 +0200 Subject: Restore "Do not create instance of QPlatformIntegration for invalid displays" This patch is amended version of 67cc8fea106c35c7ca75bf476667d07b3bbf3257, which was temporary reverted to simplify integration of conflicting patches. What was amended: - Dropped the factory interface. It is sufficiently clean to check for QXcbConnection::isConnected(). Task-number: QTBUG-68859 Change-Id: I810897b3ea20e356fc4d62e6f01231fd287962dc Reviewed-by: Johan Helsing Reviewed-by: Friedemann Kleint --- src/plugins/platforms/xcb/qxcbintegration.cpp | 16 +++++++--------- src/plugins/platforms/xcb/qxcbintegration.h | 1 + src/plugins/platforms/xcb/qxcbmain.cpp | 12 +++++++++--- 3 files changed, 17 insertions(+), 12 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 9a7d193767..ed9e87a036 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -195,14 +195,17 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char const int numParameters = parameters.size(); m_connections.reserve(1 + numParameters / 2); + auto conn = new QXcbConnection(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, displayName); - if (conn->isConnected()) - m_connections << conn; - else + if (!conn->isConnected()) { delete conn; + return; + } + m_connections << conn; + // ### Qt 6 (QTBUG-52408) remove this multi-connection code path for (int i = 0; i < numParameters - 1; i += 2) { - qCDebug(lcQpaScreen) << "connecting to additional display: " << parameters.at(i) << parameters.at(i+1); + qCDebug(lcQpaXcb) << "connecting to additional display: " << parameters.at(i) << parameters.at(i+1); QString display = parameters.at(i) + QLatin1Char(':') + parameters.at(i+1); conn = new QXcbConnection(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, display.toLatin1().constData()); if (conn->isConnected()) @@ -211,11 +214,6 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char delete conn; } - if (m_connections.isEmpty()) { - qCritical("Could not connect to any X display."); - exit(1); - } - m_fontDatabase.reset(new QGenericUnixFontDatabase()); #if QT_CONFIG(xcb_native_painting) diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index a8dd6402f6..f13e232291 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -102,6 +102,7 @@ public: QPlatformTheme *createPlatformTheme(const QString &name) const override; QVariant styleHint(StyleHint hint) const override; + bool hasDefaultConnection() const { return !m_connections.isEmpty(); } QXcbConnection *defaultConnection() const { return m_connections.first(); } QByteArray wmClass() const; diff --git a/src/plugins/platforms/xcb/qxcbmain.cpp b/src/plugins/platforms/xcb/qxcbmain.cpp index f8cb9a9269..c1e37f3704 100644 --- a/src/plugins/platforms/xcb/qxcbmain.cpp +++ b/src/plugins/platforms/xcb/qxcbmain.cpp @@ -52,10 +52,16 @@ public: QPlatformIntegration* QXcbIntegrationPlugin::create(const QString& system, const QStringList& parameters, int &argc, char **argv) { - if (!system.compare(QLatin1String("xcb"), Qt::CaseInsensitive)) - return new QXcbIntegration(parameters, argc, argv); + if (!system.compare(QLatin1String("xcb"), Qt::CaseInsensitive)) { + auto xcbIntegration = new QXcbIntegration(parameters, argc, argv); + if (!xcbIntegration->hasDefaultConnection()) { + delete xcbIntegration; + return nullptr; + } + return xcbIntegration; + } - return 0; + return nullptr; } QT_END_NAMESPACE -- cgit v1.2.3 From 83d56811ec95dc27d095da0fb55632ea46e4bea3 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Tue, 16 Oct 2018 15:06:04 +0200 Subject: Windows QPA: Fix Drag&Drop from touchscreen/pen The Drag&Drop functionality had stopped working with touchscreen/pen after the WM_POINTER-based input handling was added. The Drag&Drop functionality internally uses the DoDragDrop() WIN32 call which, according to Microsoft docs, is not supported for invocation inside handlers for touch/pen messages, and should be invoked in handlers for mouse messages that are synthesized by the OS afterwards. The result was that when DoDragDrop (which is a blocking function with its own event loop) was called it would hang ignoring all touch/pen messages until a mouse/touchpad message arrived. This change implements a workaround for this issue by enqueuing Qt touch/pen events that would be generated inside the pointer message handler, and that could start a Drag&Drop operation, and only producing them after the OS sends the associated mouse messages. Task-number: QTBUG-70887 Change-Id: Id45e0ecc70358ba250de9b3268856781ed21c9dd Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowsdrag.cpp | 4 + src/plugins/platforms/windows/qwindowsdrag.h | 2 + .../platforms/windows/qwindowspointerhandler.cpp | 149 +++++++++++++++++++-- 3 files changed, 145 insertions(+), 10 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index b7d225cb00..ee82b2f022 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -652,6 +652,7 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, */ bool QWindowsDrag::m_canceled = false; +bool QWindowsDrag::m_dragging = false; QWindowsDrag::QWindowsDrag() = default; @@ -699,7 +700,10 @@ Qt::DropAction QWindowsDrag::drag(QDrag *drag) const DWORD allowedEffects = translateToWinDragEffects(possibleActions); qCDebug(lcQpaMime) << '>' << __FUNCTION__ << "possible Actions=0x" << hex << int(possibleActions) << "effects=0x" << allowedEffects << dec; + // Indicate message handlers we are in DoDragDrop() event loop. + QWindowsDrag::m_dragging = true; const HRESULT r = DoDragDrop(dropDataObject, windowDropSource, allowedEffects, &resultEffect); + QWindowsDrag::m_dragging = false; const DWORD reportedPerformedEffect = dropDataObject->reportedPerformedEffect(); if (r == DRAGDROP_S_DROP) { if (reportedPerformedEffect == DROPEFFECT_MOVE && resultEffect != DROPEFFECT_MOVE) { diff --git a/src/plugins/platforms/windows/qwindowsdrag.h b/src/plugins/platforms/windows/qwindowsdrag.h index f116e50cbf..5f30c59882 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.h +++ b/src/plugins/platforms/windows/qwindowsdrag.h @@ -92,6 +92,7 @@ public: static QWindowsDrag *instance(); void cancelDrag() override { QWindowsDrag::m_canceled = true; } static bool isCanceled() { return QWindowsDrag::m_canceled; } + static bool isDragging() { return QWindowsDrag::m_dragging; } IDataObject *dropDataObject() const { return m_dropDataObject; } void setDropDataObject(IDataObject *dataObject) { m_dropDataObject = dataObject; } @@ -102,6 +103,7 @@ public: private: static bool m_canceled; + static bool m_dragging; QWindowsDropMimeData m_dropData; IDataObject *m_dropDataObject = nullptr; diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index c5acc38e7c..09eadb247a 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -50,6 +50,9 @@ #include "qwindowswindow.h" #include "qwindowsintegration.h" #include "qwindowsscreen.h" +#if QT_CONFIG(draganddrop) +# include "qwindowsdrag.h" +#endif #include #include @@ -60,6 +63,7 @@ #include #include #include +#include #include @@ -75,6 +79,111 @@ enum { QT_PT_TOUCHPAD = 5, // MinGW is missing PT_TOUCHPAD }; +struct PointerTouchEventInfo { + QPointer window; + QList points; + Qt::KeyboardModifiers modifiers; +}; + +struct PointerTabletEventInfo { + QPointer window; + QPointF local; + QPointF global; + int device; + int pointerType; + Qt::MouseButtons buttons; + qreal pressure; + int xTilt; + int yTilt; + qreal tangentialPressure; + qreal rotation; + int z; + qint64 uid; + Qt::KeyboardModifiers modifiers; +}; + +static QQueue touchEventQueue; +static QQueue tabletEventQueue; + +static void enqueueTouchEvent(QWindow *window, + const QList &points, + Qt::KeyboardModifiers modifiers) +{ + PointerTouchEventInfo eventInfo; + eventInfo.window = window; + eventInfo.points = points; + eventInfo.modifiers = modifiers; + touchEventQueue.enqueue(eventInfo); +} + +static void enqueueTabletEvent(QWindow *window, const QPointF &local, const QPointF &global, + int device, int pointerType, Qt::MouseButtons buttons, qreal pressure, + int xTilt, int yTilt, qreal tangentialPressure, qreal rotation, + int z, qint64 uid, Qt::KeyboardModifiers modifiers) +{ + PointerTabletEventInfo eventInfo; + eventInfo.window = window; + eventInfo.local = local; + eventInfo.global = global; + eventInfo.device = device; + eventInfo.pointerType = pointerType; + eventInfo.buttons = buttons; + eventInfo.pressure = pressure; + eventInfo.xTilt = xTilt; + eventInfo.yTilt = yTilt; + eventInfo.tangentialPressure = tangentialPressure; + eventInfo.rotation = rotation; + eventInfo.z = z; + eventInfo.uid = uid; + eventInfo.modifiers = modifiers; + tabletEventQueue.enqueue(eventInfo); +} + +static void flushTouchEvents(QTouchDevice *touchDevice) +{ + while (!touchEventQueue.isEmpty()) { + PointerTouchEventInfo eventInfo = touchEventQueue.dequeue(); + if (eventInfo.window) { + QWindowSystemInterface::handleTouchEvent(eventInfo.window, + touchDevice, + eventInfo.points, + eventInfo.modifiers); + } + } +} + +static void flushTabletEvents() +{ + while (!tabletEventQueue.isEmpty()) { + PointerTabletEventInfo eventInfo = tabletEventQueue.dequeue(); + if (eventInfo.window) { + QWindowSystemInterface::handleTabletEvent(eventInfo.window, + eventInfo.local, + eventInfo.global, + eventInfo.device, + eventInfo.pointerType, + eventInfo.buttons, + eventInfo.pressure, + eventInfo.xTilt, + eventInfo.yTilt, + eventInfo.tangentialPressure, + eventInfo.rotation, + eventInfo.z, + eventInfo.uid, + eventInfo.modifiers); + } + } +} + +static bool draggingActive() +{ +#if QT_CONFIG(draganddrop) + return QWindowsDrag::isDragging(); +#else + return false; +#endif +} + bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result) { *result = 0; @@ -426,6 +535,9 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, if (et & QtWindows::NonClientEventFlag) return false; // Let DefWindowProc() handle Non Client messages. + if (draggingActive()) + return false; // Let DoDragDrop() loop handle it. + if (count < 1) return false; @@ -452,6 +564,8 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, QList touchPoints; + bool primaryPointer = false; + if (QWindowsContext::verbose > 1) qCDebug(lcQpaEvents).noquote().nospace() << showbase << __FUNCTION__ @@ -494,16 +608,23 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, touchPoint.state = stationaryTouchPoint ? Qt::TouchPointStationary : Qt::TouchPointMoved; m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition); } + if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_PRIMARY) + primaryPointer = true; + touchPoints.append(touchPoint); // Avoid getting repeated messages for this frame if there are multiple pointerIds QWindowsContext::user32dll.skipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId); } - - QWindowSystemInterface::handleTouchEvent(window, m_touchDevice, touchPoints, - QWindowsKeyMapper::queryKeyboardModifiers()); - - return true; + if (primaryPointer) { + // Postpone event delivery to avoid hanging inside DoDragDrop(). + // Only the primary pointer will generate mouse messages. + enqueueTouchEvent(window, touchPoints, QWindowsKeyMapper::queryKeyboardModifiers()); + } else { + QWindowSystemInterface::handleTouchEvent(window, m_touchDevice, touchPoints, + QWindowsKeyMapper::queryKeyboardModifiers()); + } + return false; // Allow mouse messages to be generated. } bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, @@ -512,6 +633,9 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin if (et & QtWindows::NonClientEventFlag) return false; // Let DefWindowProc() handle Non Client messages. + if (draggingActive()) + return false; // Let DoDragDrop() loop handle it. + POINTER_PEN_INFO *penInfo = static_cast(vPenInfo); RECT pRect, dRect; @@ -592,20 +716,25 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin } const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); - QWindowSystemInterface::handleTabletEvent(target, localPos, hiResGlobalPos, device, type, mouseButtons, - pressure, xTilt, yTilt, tangentialPressure, rotation, z, - pointerId, keyModifiers); - break; + // Postpone event delivery to avoid hanging inside DoDragDrop(). + enqueueTabletEvent(target, localPos, hiResGlobalPos, device, type, mouseButtons, + pressure, xTilt, yTilt, tangentialPressure, rotation, z, + pointerId, keyModifiers); + return false; // Allow mouse messages to be generated. } } return true; } -// SetCursorPos()/TrackMouseEvent() will generate old-style WM_MOUSE messages. Handle them here. +// Process old-style mouse messages here. bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result) { Q_UNUSED(et); + // Generate enqueued events. + flushTouchEvents(m_touchDevice); + flushTabletEvents(); + *result = 0; if (msg.message != WM_MOUSELEAVE && msg.message != WM_MOUSEMOVE) return false; -- cgit v1.2.3 From b88eaa255a4646446e0842f3d8f732b39d09a65f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Wed, 17 Oct 2018 11:42:22 +0200 Subject: macOS: Use correct text background color MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 582d221b29bbf introduced a regression where the default Base color is no longer white in light mode, for some use cases like querying QApplication::palette() and when using style sheets. [NSColor windowBackgroundColor] is not the correct color for QPalette:Base, [NSColor textBackgroundColor] is, except for the Disabled state which uses windowBackgroundColor to get a grayed-out look. This also changes the dark mode Base color slightly, from RGB(0.196, 0.196, 0.196) to RGB(0.118, 0.118, 0.118). Task-number: QTBUG-70966 Change-Id: I1ff494a09980ff2d04b2e2c43ee0bcc8e26ba9e7 Fixes: QTBUG-70966 Reviewed-by: Tor Arne Vestbø Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qcocoasystemsettings.mm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm index 672b0e4f25..aef2c6cf48 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm @@ -75,8 +75,9 @@ QPalette * qt_mac_createSystemPalette() palette->setBrush(QPalette::Disabled, QPalette::Text, dark); palette->setBrush(QPalette::Disabled, QPalette::ButtonText, dark); palette->setBrush(QPalette::Disabled, QPalette::Base, backgroundBrush); - palette->setBrush(QPalette::Active, QPalette::Base, backgroundBrush); - palette->setBrush(QPalette::Inactive, QPalette::Base, backgroundBrush); + QBrush textBackgroundBrush = qt_mac_toQBrush([NSColor textBackgroundColor]); + palette->setBrush(QPalette::Active, QPalette::Base, textBackgroundBrush); + palette->setBrush(QPalette::Inactive, QPalette::Base, textBackgroundBrush); palette->setColor(QPalette::Disabled, QPalette::Dark, QColor(191, 191, 191)); palette->setColor(QPalette::Active, QPalette::Dark, QColor(191, 191, 191)); palette->setColor(QPalette::Inactive, QPalette::Dark, QColor(191, 191, 191)); -- cgit v1.2.3 From 5760545ebb5961015e1d2d19a3713ff1d08f91e5 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Thu, 18 Oct 2018 10:39:18 +0200 Subject: QCocoaMenuItem: ignore font hints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Native applications do not use custom fonts in menus, so we should avoid it - our own example app 'menus' demonstrates the problem. To quote Gabriel: Although the Mac HIG don't say that you shouldn't, and there's even a API to do it (which we're obviously not using properly), the truth is that nobody does it. Simply put, it looks wrong on Mac (although it's arguable whether it looks good or bad regardless of the platform). Task-number: QTBUG-29654 Change-Id: Iffd08ad63d419164102b2e738cdf1ebda1967a05 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoamenuitem.h | 1 - src/plugins/platforms/cocoa/qcocoamenuitem.mm | 18 ++---------------- 2 files changed, 2 insertions(+), 17 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h index 20fc741fb8..c842b08d52 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.h +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h @@ -119,7 +119,6 @@ private: QString m_text; QIcon m_icon; QPointer m_menu; - QFont m_font; MenuRole m_role; MenuRole m_detectedRole; #ifndef QT_NO_SHORTCUT diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index 21faa6d985..e54b6284e5 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -173,7 +173,7 @@ void QCocoaMenuItem::setIsSeparator(bool isSeparator) void QCocoaMenuItem::setFont(const QFont &font) { - m_font = font; + Q_UNUSED(font) } void QCocoaMenuItem::setRole(MenuRole role) @@ -319,21 +319,7 @@ NSMenuItem *QCocoaMenuItem::sync() text += QLatin1String(" (") + accel.toString(QKeySequence::NativeText) + QLatin1String(")"); #endif - QString finalString = QPlatformTheme::removeMnemonics(text); - bool useAttributedTitle = false; - // Cocoa Font and title - if (m_font.resolve()) { - NSFont *customMenuFont = [NSFont fontWithName:m_font.family().toNSString() - size:m_font.pointSize()]; - if (customMenuFont) { - NSAttributedString *str = [[[NSAttributedString alloc] initWithString:finalString.toNSString() - attributes:@{NSFontAttributeName: customMenuFont}] autorelease]; - m_native.attributedTitle = str; - useAttributedTitle = true; - } - } - if (!useAttributedTitle) - m_native.title = finalString.toNSString(); + m_native.title = QPlatformTheme::removeMnemonics(text).toNSString(); #ifndef QT_NO_SHORTCUT if (accel.count() == 1) { -- cgit v1.2.3 From 0b4ab214db5f0368b33d4cfdfcaadf137070b7a8 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Thu, 18 Oct 2018 16:26:59 +0200 Subject: Fix a regression in qmacstyle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit square/flat button had an erroneous size adjustment, resulting in a wrong highlighted area. This button is anyway nothing like a real control on macOS - they don't have 'flat' button which highlights when pressed. Anyway, now our flat button looks more like AppKit's 'square' button when pressed. Task-number: QTBUG-69533 Change-Id: I9643c1d4a25329c3f3c2148cc1821922655d9a8b Reviewed-by: Tor Arne Vestbø --- src/plugins/styles/mac/qmacstyle_mac.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 2a21673054..1aab0309c9 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -1468,8 +1468,8 @@ QRectF QMacStylePrivate::CocoaControl::adjustedControlFrame(const QRectF &rect) QRectF frameRect; const auto frameSize = defaultFrameSize(); if (type == QMacStylePrivate::Button_SquareButton) { - frameRect = rect.adjusted(3, 1, -3, -5) - .adjusted(focusRingWidth, focusRingWidth, -focusRingWidth, -focusRingWidth); + frameRect = rect.adjusted(3, 1, -3, -1) + .adjusted(focusRingWidth, focusRingWidth, -focusRingWidth, -focusRingWidth); } else if (type == QMacStylePrivate::Button_PushButton) { // Start from the style option's top-left corner. frameRect = QRectF(rect.topLeft(), -- cgit v1.2.3 From 3c4f94b7cb3f319f24fda6502e49bdd199c0f77d Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Fri, 12 Oct 2018 15:45:27 +0200 Subject: QMacStyle: fix group box for macOS Mojave MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change is based on a patch started by Gabriel. It works around the apparently noop (on macOS Mojave, light theme) -drawRect: call on NSBox, replacing it with -displayRectIgnoringOpacity:inContext:. Unfortunately, this turns out to be extremely slow with dark theme, so we have to resort to a custom version of NSBox/-drawRect: which calls its super's -drawRect: and look more or less correct. Task-number: QTBUG-69650 Change-Id: I5a614d7cd8002b378c6c3804663b6559e227f628 Reviewed-by: Richard Moe Gustavsen Reviewed-by: Morten Johan Sørvig --- src/plugins/styles/mac/qmacstyle_mac.mm | 69 +++++++++++++++++++++++++++--- src/plugins/styles/mac/qmacstyle_mac_p_p.h | 1 + 2 files changed, 63 insertions(+), 7 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 1aab0309c9..94d048ca7e 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -238,6 +238,33 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QVerticalSplitView); } @end +// See render code in drawPrimitive(PE_FrameTabWidget) +@interface QT_MANGLE_NAMESPACE(QDarkNSBox) : NSBox +@end + +QT_NAMESPACE_ALIAS_OBJC_CLASS(QDarkNSBox); + +@implementation QDarkNSBox +- (instancetype)init +{ + if ((self = [super init])) { + self.title = @""; + self.titlePosition = NSNoTitle; + self.boxType = NSBoxCustom; + self.cornerRadius = 3; + self.borderColor = [NSColor.controlColor colorWithAlphaComponent:0.1]; + self.fillColor = [NSColor.darkGrayColor colorWithAlphaComponent:0.2]; + } + + return self; +} + +- (void)drawRect:(NSRect)rect +{ + [super drawRect:rect]; +} +@end + QT_BEGIN_NAMESPACE // The following constants are used for adjusting the size @@ -1704,18 +1731,28 @@ NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const || widget.size == QStyleHelper::SizeDefault) return nil; + if (widget.type == Box) { + if (__builtin_available(macOS 10.14, *)) { + if (qt_mac_applicationIsInDarkMode()) { + // See render code in drawPrimitive(PE_FrameTabWidget) + widget.type = Box_Dark; + } + } + } + NSView *bv = cocoaControls.value(widget, nil); if (!bv) { switch (widget.type) { case Box: { - NSBox *bc = [[NSBox alloc] init]; - bc.title = @""; - bc.titlePosition = NSNoTitle; - bc.boxType = NSBoxPrimary; - bc.borderType = NSBezelBorder; - bv = bc; + NSBox *box = [[NSBox alloc] init]; + bv = box; + box.title = @""; + box.titlePosition = NSNoTitle; break; } + case Box_Dark: + bv = [[QDarkNSBox alloc] init]; + break; case Button_CheckBox: case Button_Disclosure: case Button_PushButton: @@ -2922,10 +2959,28 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai { const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Box, QStyleHelper::SizeLarge); auto *box = static_cast(d->cocoaControl(cw)); + // FIXME Since macOS 10.14, simply calling drawRect: won't display anything anymore. + // The AppKit team is aware of this and has proposed a couple of solutions. + // The first solution was to call displayRectIgnoringOpacity:inContext: instead. + // However, it doesn't seem to work on 10.13. More importantly, dark mode on 10.14 + // is extremely slow. Light mode works fine. + // The second solution is to subclass NSBox and reimplement a trivial drawRect: which + // would only call super. This works without any issue on 10.13, but a double border + // shows on 10.14 in both light and dark modes. + // The code below picks what works on each version and mode. On 10.13 and earlier, we + // simply call drawRect: on a regular NSBox. On 10.14, we call displayRectIgnoringOpacity: + // inContext:, but only in light mode. In dark mode, we use a custom NSBox subclass, + // QDarkNSBox, of type NSBoxCustom. Its appearance is close enough to the real thing so + // we can use this for now. d->drawNSViewInRect(box, opt->rect, p, ^(CGContextRef ctx, const CGRect &rect) { CGContextTranslateCTM(ctx, 0, rect.origin.y + rect.size.height); CGContextScaleCTM(ctx, 1, -1); - [box drawRect:rect]; + if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSMojave + || [box isMemberOfClass:QDarkNSBox.class]) { + [box drawRect:rect]; + } else { + [box displayRectIgnoringOpacity:box.bounds inContext:NSGraphicsContext.currentContext]; + } }); break; } diff --git a/src/plugins/styles/mac/qmacstyle_mac_p_p.h b/src/plugins/styles/mac/qmacstyle_mac_p_p.h index 8c712e838a..dd99cf4bb5 100644 --- a/src/plugins/styles/mac/qmacstyle_mac_p_p.h +++ b/src/plugins/styles/mac/qmacstyle_mac_p_p.h @@ -187,6 +187,7 @@ public: enum CocoaControlType { NoControl, // For when there's no such a control in Cocoa Box, // QGroupBox + Box_Dark, // FIXME See render code in drawPrimitive(PE_FrameTabWidget) Button_CheckBox, Button_Disclosure, // Disclosure triangle, like in QTreeView Button_PopupButton, // Non-editable QComboBox -- cgit v1.2.3 From 10b8ed816d0dff4321d5a8b0723a8090b2058678 Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Wed, 17 Oct 2018 15:06:47 +1000 Subject: wasm: fix wheel scroll logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-71180 Fixes: QTBUG-71180 Change-Id: If442da096b847fdf69f3b24615e99c2ca988fb79 Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/wasm/qwasmeventtranslator.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp index cc48c15b64..23251fd610 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp @@ -50,7 +50,7 @@ using namespace emscripten; // the existing switching code in QtGui, but for now do it here. static bool g_usePlatformMacCtrlMetaSwitching = false; -bool g_useNaturalScrolling = false; +bool g_useNaturalScrolling = true; // natural scrolling is default on linux/windows void setNaturalScrolling(bool use) { g_useNaturalScrolling = use; @@ -98,7 +98,7 @@ QWasmEventTranslator::QWasmEventTranslator(QObject *parent) g_usePlatformMacCtrlMetaSwitching = (platform == MacOSPlatform); if (platform == MacOSPlatform) { - g_useNaturalScrolling = true; //make this default on macOS + g_useNaturalScrolling = false; // make this !default on macOS EM_ASM( if (window.safari !== undefined) {//this only works on safari Module["canvas"].addEventListener('wheel', mouseWheelEvent); @@ -492,6 +492,9 @@ int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wh if (wheelEvent->deltaX != 0) pixelDelta.setX(wheelEvent->deltaX * scrollFactor); QWindowSystemInterface::handleWheelEvent(window2, timestamp, localPoint, globalPoint, QPoint(), pixelDelta, modifiers); + + QWasmEventDispatcher::maintainTimers(); + return 1; } -- cgit v1.2.3 From c0538857358e57c1551f7d10c07a9bb80d848cd7 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 19 Oct 2018 08:19:04 +0200 Subject: Windows/QPA: Fix receiving mouse clicks after double clicks in QQuickWidget The Qt QPA does not handle native double clicks as such; change the plugin not to send them. For Ink, remove the doubleclick detection. For the old code path, map them to Press. Fixes: QTBUG-70999 Change-Id: I54b858f9e146bf325a861554d5ef74143db7d2b7 Reviewed-by: Oliver Wolff --- .../platforms/windows/qwindowsmousehandler.cpp | 16 ++++++------- .../platforms/windows/qwindowspointerhandler.cpp | 26 ++-------------------- 2 files changed, 10 insertions(+), 32 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index c1c275144f..fcdd179a31 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -207,26 +207,26 @@ static inline MouseEvent eventFromMsg(const MSG &msg) return {QEvent::MouseButtonPress, Qt::LeftButton}; case WM_LBUTTONUP: return {QEvent::MouseButtonRelease, Qt::LeftButton}; - case WM_LBUTTONDBLCLK: - return {QEvent::MouseButtonDblClick, Qt::LeftButton}; + case WM_LBUTTONDBLCLK: // Qt QPA does not handle double clicks, send as press + return {QEvent::MouseButtonPress, Qt::LeftButton}; case WM_MBUTTONDOWN: return {QEvent::MouseButtonPress, Qt::MidButton}; case WM_MBUTTONUP: return {QEvent::MouseButtonRelease, Qt::MidButton}; case WM_MBUTTONDBLCLK: - return {QEvent::MouseButtonDblClick, Qt::MidButton}; + return {QEvent::MouseButtonPress, Qt::MidButton}; case WM_RBUTTONDOWN: return {QEvent::MouseButtonPress, Qt::RightButton}; case WM_RBUTTONUP: return {QEvent::MouseButtonRelease, Qt::RightButton}; case WM_RBUTTONDBLCLK: - return {QEvent::MouseButtonDblClick, Qt::RightButton}; + return {QEvent::MouseButtonPress, Qt::RightButton}; case WM_XBUTTONDOWN: return {QEvent::MouseButtonPress, extraButton(msg.wParam)}; case WM_XBUTTONUP: return {QEvent::MouseButtonRelease, extraButton(msg.wParam)}; case WM_XBUTTONDBLCLK: - return {QEvent::MouseButtonDblClick, extraButton(msg.wParam)}; + return {QEvent::MouseButtonPress, extraButton(msg.wParam)}; case WM_NCMOUSEMOVE: return {QEvent::NonClientAreaMouseMove, Qt::NoButton}; case WM_NCLBUTTONDOWN: @@ -234,19 +234,19 @@ static inline MouseEvent eventFromMsg(const MSG &msg) case WM_NCLBUTTONUP: return {QEvent::NonClientAreaMouseButtonRelease, Qt::LeftButton}; case WM_NCLBUTTONDBLCLK: - return {QEvent::NonClientAreaMouseButtonDblClick, Qt::LeftButton}; + return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton}; case WM_NCMBUTTONDOWN: return {QEvent::NonClientAreaMouseButtonPress, Qt::MidButton}; case WM_NCMBUTTONUP: return {QEvent::NonClientAreaMouseButtonRelease, Qt::MidButton}; case WM_NCMBUTTONDBLCLK: - return {QEvent::NonClientAreaMouseButtonDblClick, Qt::MidButton}; + return {QEvent::NonClientAreaMouseButtonPress, Qt::MidButton}; case WM_NCRBUTTONDOWN: return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton}; case WM_NCRBUTTONUP: return {QEvent::NonClientAreaMouseButtonRelease, Qt::RightButton}; case WM_NCRBUTTONDBLCLK: - return {QEvent::NonClientAreaMouseButtonDblClick, Qt::RightButton}; + return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton}; default: // WM_MOUSELEAVE break; } diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 09eadb247a..21dc0cd577 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -280,7 +280,7 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q return false; } -static void getMouseEventInfo(UINT message, POINTER_BUTTON_CHANGE_TYPE changeType, QPoint globalPos, QEvent::Type *eventType, Qt::MouseButton *mouseButton) +static void getMouseEventInfo(UINT message, POINTER_BUTTON_CHANGE_TYPE changeType, QEvent::Type *eventType, Qt::MouseButton *mouseButton) { static const QHash buttonMapping { {POINTER_CHANGE_FIRSTBUTTON_DOWN, Qt::LeftButton}, @@ -334,28 +334,6 @@ static void getMouseEventInfo(UINT message, POINTER_BUTTON_CHANGE_TYPE changeTyp } *mouseButton = buttonMapping.value(changeType, Qt::NoButton); - - // Pointer messages lack a double click indicator. Check if this is the case here. - if (*eventType == QEvent::MouseButtonPress || - *eventType == QEvent::NonClientAreaMouseButtonPress) { - static LONG lastTime = 0; - static Qt::MouseButton lastButton = Qt::NoButton; - static QEvent::Type lastEvent = QEvent::None; - static QPoint lastPos; - LONG messageTime = GetMessageTime(); - if (*mouseButton == lastButton - && *eventType == lastEvent - && messageTime - lastTime < (LONG)GetDoubleClickTime() - && qAbs(globalPos.x() - lastPos.x()) < GetSystemMetrics(SM_CXDOUBLECLK) - && qAbs(globalPos.y() - lastPos.y()) < GetSystemMetrics(SM_CYDOUBLECLK)) { - *eventType = nonClient ? QEvent::NonClientAreaMouseButtonDblClick : - QEvent::MouseButtonDblClick; - } - lastTime = messageTime; - lastButton = *mouseButton; - lastEvent = *eventType; - lastPos = globalPos; - } } static QWindow *getWindowUnderPointer(QWindow *window, QPoint globalPos) @@ -467,7 +445,7 @@ bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND h QEvent::Type eventType; Qt::MouseButton button; - getMouseEventInfo(msg.message, pointerInfo->ButtonChangeType, globalPos, &eventType, &button); + getMouseEventInfo(msg.message, pointerInfo->ButtonChangeType, &eventType, &button); if (et & QtWindows::NonClientEventFlag) { QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons, button, eventType, -- cgit v1.2.3 From ebfad73b4e44fe6db8059200da105b4b87888718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 22 Oct 2018 16:29:29 +0200 Subject: macOS: Fix NSOpenGLContext view association check The expression "m_context.view = view" always evaluates to the view, so the check was flawed. Change-Id: Icef4ba5244975ccd78a151c7d40c53b2364c6148 Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qcocoaglcontext.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index 1e1b3907ed..1cd77a22e4 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -414,7 +414,8 @@ bool QCocoaGLContext::setDrawable(QPlatformSurface *surface) // have the same effect as an update. // Now we are ready to associate the view with the context - if ((m_context.view = view) != view) { + m_context.view = view; + if (m_context.view != view) { qCInfo(lcQpaOpenGLContext) << "Failed to set" << view << "as drawable for" << m_context; m_updateObservers.clear(); return false; -- cgit v1.2.3 From 72bedd49bfb02ba7c7abf2a1a4c6cd165ebcd447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Br=C3=BCning?= Date: Tue, 16 Oct 2018 18:17:56 +0200 Subject: [cocoa] Disable offline renderers for dual AMD FirePro GPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AMD FirePro dual gpus on the Mac Pro have a problem with offline renderers in Chromium. Therefore, Chromium and thus Qt WebEngine disable this option via the pixel format attributes. The Qt Cocoa plugin on the other hand enables it in the recent versions, causing context creation in Qt WebEngine to fail when run on a Mac Pro with dual AMD FirePro gpus due to incompatible context options. This patch uses the environment variable QT_MAC_PRO_WEBENGINE_WORKAROUND which is set by Qt WebEngine upon application startup if the application is running on a late 2013 Mac Pro. It should typically not be set from anywhere else. [ChangeLog] Offline renderers will be disabled when the application is using Qt WebEngine and running on one of the late 2013 Mac Pro models. Fixes: QTBUG-70062 Change-Id: I0b0831efb6f4073ebd37672040aaed6370853fc0 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoaglcontext.mm | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index 7ffe0003d3..76f8a7bb02 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -456,7 +456,13 @@ NSOpenGLPixelFormat *QCocoaGLContext::createNSOpenGLPixelFormat(const QSurfaceFo if (format.stereo()) attrs << NSOpenGLPFAStereo; - attrs << NSOpenGLPFAAllowOfflineRenderers; + //Workaround for problems with Chromium and offline renderers on the lat 2013 MacPros. + //FIXME: Think if this could be solved via QSurfaceFormat in the future. + static bool offlineRenderersAllowed = qEnvironmentVariableIsEmpty("QT_MAC_PRO_WEBENGINE_WORKAROUND"); + if (offlineRenderersAllowed) { + // Allow rendering on GPUs without a connected display + attrs << NSOpenGLPFAAllowOfflineRenderers; + } QByteArray useLayer = qgetenv("QT_MAC_WANTS_LAYER"); if (!useLayer.isEmpty() && useLayer.toInt() > 0) { -- cgit v1.2.3 From 88fe7c8cad0bb8e9aee1373c7a7a24d1e4be24ca Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Wed, 24 Oct 2018 14:22:43 +0200 Subject: Windows QPA: Fix 2-finger scroll not working with some touchpads It seems some touchpads only send legacy WM_MOUSEWHEEL/WM_MOUSEHWHEEL messages for 2-finger scrolling, instead of WM_POINTERWHEEL/ WM_POINTERHWHEEL, even after EnableMouseInPointer(TRUE), in spite of sending the expected pointer messages for normal pointer movement/taps. This change adds a workaround to handle legacy wheel messages even when in pointer mode. Task-number: QTBUG-71257 Change-Id: Ib360051147c4521751a5b91d90fa7657496777fa Reviewed-by: Oliver Wolff Reviewed-by: Friedemann Kleint --- .../platforms/windows/qwindowspointerhandler.cpp | 43 +++++++++++++++++----- 1 file changed, 34 insertions(+), 9 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 21dc0cd577..2b6c696979 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -484,6 +484,9 @@ bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND h case WM_POINTERHWHEEL: case WM_POINTERWHEEL: { + if (!isValidWheelReceiver(window)) + return true; + int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam); // Qt horizontal wheel rotation orientation is opposite to the one in WM_POINTERHWHEEL @@ -493,8 +496,7 @@ bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND h const QPoint angleDelta = (msg.message == WM_POINTERHWHEEL || (keyModifiers & Qt::AltModifier)) ? QPoint(delta, 0) : QPoint(0, delta); - if (isValidWheelReceiver(window)) - QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers); + QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers); return true; } case WM_POINTERLEAVE: @@ -508,7 +510,6 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, MSG msg, PVOID vTouchInfo, quint32 count) { Q_UNUSED(hwnd); - Q_UNUSED(et); if (et & QtWindows::NonClientEventFlag) return false; // Let DefWindowProc() handle Non Client messages. @@ -707,21 +708,46 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin // Process old-style mouse messages here. bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result) { - Q_UNUSED(et); - // Generate enqueued events. flushTouchEvents(m_touchDevice); flushTabletEvents(); *result = 0; - if (msg.message != WM_MOUSELEAVE && msg.message != WM_MOUSEMOVE) + if (et != QtWindows::MouseWheelEvent && msg.message != WM_MOUSELEAVE && msg.message != WM_MOUSEMOVE) return false; - const QPoint localPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)); - const QPoint globalPos = QWindowsGeometryHint::mapToGlobal(hwnd, localPos); + const QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)); + QPoint localPos; + QPoint globalPos; + if ((et == QtWindows::MouseWheelEvent) || (et & QtWindows::NonClientEventFlag)) { + globalPos = eventPos; + localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, eventPos); + } else { + localPos = eventPos; + globalPos = QWindowsGeometryHint::mapToGlobal(hwnd, eventPos); + } + const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); QWindowsWindow *platformWindow = static_cast(window->handle()); + if (et == QtWindows::MouseWheelEvent) { + + if (!isValidWheelReceiver(window)) + return true; + + int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam); + + // Qt horizontal wheel rotation orientation is opposite to the one in WM_MOUSEHWHEEL + if (msg.message == WM_MOUSEHWHEEL) + delta = -delta; + + const QPoint angleDelta = (msg.message == WM_MOUSEHWHEEL || (keyModifiers & Qt::AltModifier)) ? + QPoint(delta, 0) : QPoint(0, delta); + + QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers); + return true; + } + if (msg.message == WM_MOUSELEAVE) { if (window == m_currentWindow) { QWindowSystemInterface::handleLeaveEvent(window); @@ -762,7 +788,6 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW m_windowUnderPointer = currentWindowUnderPointer; } - const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); const Qt::MouseButtons mouseButtons = queryMouseButtons(); if (!discardEvent) -- cgit v1.2.3 From 8e1c8076282f87a8d19f73feb1bb5baf068de1e1 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Wed, 24 Oct 2018 11:11:21 +0200 Subject: xcb: fix unresponsive mouse clicks after VT switch This patch amends d67214302f269242ae3d8d2b962fd91ec42c979e. The issue was caused by mistakenly interchanging m_hasXRender <-> m_hasXRandr. Also renamed selectXRandrEvents() -> xrandrSelectEvents() to be more consistent with xi2Select*() API. And moved the xrandrSelectEvents() to QXcbConnection ctor for the same reason. Fixes: QTBUG-71305 Change-Id: I26f9bac3ae1f997f53134eb97f3569fb6d3c13fe Reviewed-by: Allan Sandfeld Jensen --- src/plugins/platforms/xcb/qxcbconnection.cpp | 3 +++ src/plugins/platforms/xcb/qxcbconnection.h | 2 +- src/plugins/platforms/xcb/qxcbconnection_basic.cpp | 4 ++-- src/plugins/platforms/xcb/qxcbconnection_screens.cpp | 6 ++---- 4 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 9e857ea2ff..45f096a13a 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -105,6 +105,9 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra m_xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP").toLower(); + if (hasXRandr()) + xrandrSelectEvents(); + initializeScreens(); #if QT_CONFIG(xcb_xinput) diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 49e79ec3fd..5d53b97d37 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -250,7 +250,7 @@ protected: bool event(QEvent *e) override; private: - void selectXRandrEvents(); + void xrandrSelectEvents(); 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; diff --git a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp index 7bed3c8937..b8335d1240 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp @@ -308,7 +308,7 @@ void QXcbBasicConnection::initializeXRandr() return; } - m_hasXRender = true; + m_hasXRandr = true; m_xrenderVersion.first = xrenderQuery->major_version; m_xrenderVersion.second = xrenderQuery->minor_version; #endif @@ -358,7 +358,7 @@ void QXcbBasicConnection::initializeXRender() return; } - m_hasXRandr = true; + m_hasXRender = true; m_xrandrFirstEvent = reply->first_event; } diff --git a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp index 4c380bf39f..fe9e0be86d 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp @@ -46,7 +46,7 @@ #include -void QXcbConnection::selectXRandrEvents() +void QXcbConnection::xrandrSelectEvents() { xcb_screen_iterator_t rootIter = xcb_setup_roots_iterator(setup()); for (; rootIter.rem; xcb_screen_next(&rootIter)) { @@ -270,8 +270,6 @@ void QXcbConnection::destroyScreen(QXcbScreen *screen) void QXcbConnection::initializeScreens() { - selectXRandrEvents(); - xcb_screen_iterator_t it = xcb_setup_roots_iterator(setup()); int xcbScreenNumber = 0; // screen number in the xcb sense QXcbScreen *primaryScreen = nullptr; @@ -284,7 +282,7 @@ void QXcbConnection::initializeScreens() QXcbVirtualDesktop *virtualDesktop = new QXcbVirtualDesktop(this, xcbScreen, xcbScreenNumber); m_virtualDesktops.append(virtualDesktop); QList siblings; - if (hasXRender()) { + if (hasXRandr()) { // RRGetScreenResourcesCurrent is fast but it may return nothing if the // configuration is not initialized wrt to the hardware. We should call // RRGetScreenResources in this case. -- cgit v1.2.3 From ae57e271e8d37c05cede83ada594b0f58d388a58 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 24 Oct 2018 17:13:57 +0200 Subject: Fix out of bounds memory access when setting motif window hint properties Commit b4bd5f9df3e69da707513ba544537c80a8564fb4 removed two members from the mwm hints structure but told xcb_change_property that the structure has still five members when it had been reduced to three. This lead to xcb_change_property accessing memory out of bounds. As identified by Gatis, the safest option to avoid the access is to add the two members again. Other window managers may be expecting their presence in the window property. Change-Id: Id4f0c9536cd317c35f2c6ebd1ac9ccc6f72de6a5 Reviewed-by: Gatis Paeglis Reviewed-by: Mikhail Svetkin --- src/plugins/platforms/xcb/qxcbwindow.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index e56f6b13d8..70aab77a51 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -904,6 +904,8 @@ void QXcbWindow::doFocusOut() struct QtMotifWmHints { quint32 flags, functions, decorations; + qint32 input_mode; // unused + quint32 status; // unused }; enum { -- cgit v1.2.3 From 269172037db11d6e62bcef2d5c7491af9244f203 Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Thu, 18 Oct 2018 10:20:42 +1000 Subject: wasm: use maintainTimers instead of processEvents for touch callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: If39cdeedef60a47c0ba1afbab6adf1668bf5d0d6 Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/wasm/qwasmeventtranslator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp index 23251fd610..a3fdcd1025 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp @@ -546,7 +546,7 @@ int QWasmEventTranslator::touchCallback(int eventType, const EmscriptenTouchEven else QWindowSystemInterface::handleTouchCancelEvent(window2, wasmEventTranslator->getTimestamp(), wasmEventTranslator->touchDevice, keyModifier); - QCoreApplication::processEvents(); + QWasmEventDispatcher::maintainTimers(); return 1; } -- cgit v1.2.3 From 199b67f11c7c5b9ae0aaf60f3e7ea20dafc21ce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 18 Oct 2018 18:00:40 +0200 Subject: macOS: Log Qt and macOS version information at startup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SDK and deployment target versions are helpful to know when diagnosing issues. Change-Id: I85026bd9c1d706a923e8953837bd59bf9ed0266f Reviewed-by: Tor Arne Vestbø Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qcocoahelpers.h | 31 +++++++++ src/plugins/platforms/cocoa/qcocoahelpers.mm | 82 ++++++++++++++++++++++++ src/plugins/platforms/cocoa/qcocoaintegration.mm | 28 ++++++++ 3 files changed, 141 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h index 953bf331bb..69aa7937b6 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.h +++ b/src/plugins/platforms/cocoa/qcocoahelpers.h @@ -52,6 +52,7 @@ // #include "qt_mac_p.h" #include +#include #include #include @@ -60,6 +61,8 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSView)); +struct mach_header; + QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(lcQpaWindow) @@ -173,6 +176,34 @@ T qt_mac_resolveOption(const T &fallback, QWindow *window, const QByteArray &pro return fallback; } +// ------------------------------------------------------------------------- + +#if !defined(Q_PROCESSOR_X86_64) +#error "32-bit builds are not supported" +#endif + +class QMacVersion +{ +public: + enum VersionTarget { + ApplicationBinary, + QtLibraries + }; + + static QOperatingSystemVersion buildSDK(VersionTarget target = ApplicationBinary); + static QOperatingSystemVersion deploymentTarget(VersionTarget target = ApplicationBinary); + static QOperatingSystemVersion currentRuntime(); + +private: + QMacVersion() = default; + using VersionTuple = QPair; + static VersionTuple versionsForImage(const mach_header *machHeader); + static VersionTuple applicationVersion(); + static VersionTuple libraryVersion(); +}; + +// ------------------------------------------------------------------------- + QT_END_NAMESPACE // @compatibility_alias doesn't work with protocols diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 0f5ddfa49a..36841c77ab 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -55,6 +55,9 @@ #include +#include +#include + QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window"); @@ -368,6 +371,85 @@ QString qt_mac_removeAmpersandEscapes(QString s) return QPlatformTheme::removeMnemonics(s).trimmed(); } +// ------------------------------------------------------------------------- + +#if !defined(Q_PROCESSOR_X86_64) +#error "32-bit builds are not supported" +#endif + +QOperatingSystemVersion QMacVersion::buildSDK(VersionTarget target) +{ + switch (target) { + case ApplicationBinary: return applicationVersion().second; + case QtLibraries: return libraryVersion().second; + } + Q_UNREACHABLE(); +} + +QOperatingSystemVersion QMacVersion::deploymentTarget(VersionTarget target) +{ + switch (target) { + case ApplicationBinary: return applicationVersion().first; + case QtLibraries: return libraryVersion().first; + } + Q_UNREACHABLE(); +} + +QOperatingSystemVersion QMacVersion::currentRuntime() +{ + return QOperatingSystemVersion::current(); +} + +QMacVersion::VersionTuple QMacVersion::versionsForImage(const mach_header *machHeader) +{ + auto commandCursor = uintptr_t(machHeader) + sizeof(mach_header_64); + for (uint32_t i = 0; i < machHeader->ncmds; ++i) { + load_command *loadCommand = reinterpret_cast(commandCursor); + if (loadCommand->cmd == LC_VERSION_MIN_MACOSX) { + auto versionCommand = reinterpret_cast(loadCommand); + uint32_t dt = versionCommand->version; // Deployment target + uint32_t sdk = versionCommand->sdk; // Build SDK + return qMakePair( + QOperatingSystemVersion(QOperatingSystemVersion::MacOS, + dt >> 16 & 0xffff, dt >> 8 & 0xff, dt & 0xff), + QOperatingSystemVersion(QOperatingSystemVersion::MacOS, + sdk >> 16 & 0xffff, sdk >> 8 & 0xff, sdk & 0xff) + ); + } + commandCursor += loadCommand->cmdsize; + } + Q_ASSERT_X(false, "QCocoaIntegration", "Could not find version-min load command"); + Q_UNREACHABLE(); +} + +QMacVersion::VersionTuple QMacVersion::applicationVersion() +{ + static VersionTuple version = []() { + const mach_header *executableHeader = nullptr; + for (uint32_t i = 0; i < _dyld_image_count(); ++i) { + auto header = _dyld_get_image_header(i); + if (header->filetype == MH_EXECUTE) { + executableHeader = header; + break; + } + } + Q_ASSERT_X(executableHeader, "QCocoaIntegration", "Failed to resolve Mach-O header of executable"); + return versionsForImage(executableHeader); + }(); + return version; +} + +QMacVersion::VersionTuple QMacVersion::libraryVersion() +{ + static VersionTuple version = []() { + Dl_info cocoaPluginImage; + dladdr((const void *)&QMacVersion::libraryVersion, &cocoaPluginImage); + Q_ASSERT_X(cocoaPluginImage.dli_fbase, "QCocoaIntegration", "Failed to resolve Mach-O header of Cocoa plugin"); + return versionsForImage(static_cast(cocoaPluginImage.dli_fbase)); + }(); + return version; +} + QT_END_NAMESPACE /*! \internal diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 612290c9bd..936fecf8de 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -79,6 +79,32 @@ static void initResources() QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcQpa, "qt.qpa", QtWarningMsg); + +static void logVersionInformation() +{ + if (!lcQpa().isInfoEnabled()) + return; + + auto osVersion = QMacVersion::currentRuntime(); + auto qtBuildSDK = QMacVersion::buildSDK(QMacVersion::QtLibraries); + auto qtDeploymentTarget = QMacVersion::deploymentTarget(QMacVersion::QtLibraries); + auto appBuildSDK = QMacVersion::buildSDK(QMacVersion::ApplicationBinary); + auto appDeploymentTarget = QMacVersion::deploymentTarget(QMacVersion::ApplicationBinary); + + qCInfo(lcQpa, "Loading macOS (Cocoa) platform plugin for Qt " QT_VERSION_STR ", running on macOS %d.%d.%d\n\n" \ + " Component SDK version Deployment target \n" \ + " ------------- ------------- -------------------\n" \ + " Qt " QT_VERSION_STR " %d.%d.%d %d.%d.%d\n" \ + " Application %d.%d.%d %d.%d.%d\n", + osVersion.majorVersion(), osVersion.minorVersion(), osVersion.microVersion(), + qtBuildSDK.majorVersion(), qtBuildSDK.minorVersion(), qtBuildSDK.microVersion(), + qtDeploymentTarget.majorVersion(), qtDeploymentTarget.minorVersion(), qtDeploymentTarget.microVersion(), + appBuildSDK.majorVersion(), appBuildSDK.minorVersion(), appBuildSDK.microVersion(), + appDeploymentTarget.majorVersion(), appDeploymentTarget.minorVersion(), appDeploymentTarget.microVersion()); +} + + class QCoreTextFontEngine; class QFontEngineFT; @@ -112,6 +138,8 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) , mServices(new QCocoaServices) , mKeyboardMapper(new QCocoaKeyMapper) { + logVersionInformation(); + if (mInstance) qWarning("Creating multiple Cocoa platform integrations is not supported"); mInstance = this; -- cgit v1.2.3 From acf5c37046944d6483cfc68b3d877b015292d415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 22 Oct 2018 19:29:32 +0200 Subject: macOS: Add local auto-release pool during updating of window flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevents no-longer used QNSWindows from staying around (closed and invisible, but alive), due to being auto-released when there is no pool in place (during main(), before exec). Change-Id: I4eb63c7140290ffe6bded8a76732354c846ed579 Reviewed-by: Timur Pocheptsov Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoawindow.mm | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 98e48a8b70..a28bdd628b 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -541,6 +541,12 @@ void QCocoaWindow::setWindowZoomButton(Qt::WindowFlags flags) void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags) { + // Updating the window flags may affect the window's theme frame, which + // in the process retains and then autoreleases the NSWindow. To make + // sure this doesn't leave lingering releases when there is no pool in + // place (e.g. during main(), before exec), we add one locally here. + QMacAutoReleasePool pool; + if (!isContentView()) return; -- cgit v1.2.3 From d02fed67814a3cb8f28a4f0ec61e075858fce238 Mon Sep 17 00:00:00 2001 From: Rafael Roquetto Date: Mon, 1 Oct 2018 09:16:28 +1000 Subject: macOS: restore hidden popup windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to to explicitly unhide popup windows that were previously explicitly hidden by applicationWillHide, so that their visibility will be effectively restored when the application is unhidden (otherwise the windows are gone forever even though their internal visibility is set to true). Change-Id: I4dbd209b07f769cc815851b40c41db0739ca2dc9 Task-number: QTBUG-71014 Reviewed-by: Timur Pocheptsov Reviewed-by: Edward Welbourne Reviewed-by: Tor Arne Vestbø --- .../platforms/cocoa/qcocoaapplicationdelegate.mm | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index 221a8b0866..44ab16d300 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -86,6 +86,7 @@ #include #include "qt_mac_p.h" #include +#include QT_USE_NAMESPACE @@ -93,6 +94,7 @@ QT_USE_NAMESPACE bool startedQuit; NSObject *reflectionDelegate; bool inLaunch; + QWindowList hiddenWindows; } + (instancetype)sharedDelegate @@ -322,12 +324,28 @@ QT_USE_NAMESPACE // fact that the application itself is hidden, which will cause a problem when // the application is made visible again. const QWindowList topLevelWindows = QGuiApplication::topLevelWindows(); - for (QWindow *topLevelWindow : qAsConst(topLevelWindows)) { - if ((topLevelWindow->type() & Qt::Popup) == Qt::Popup && topLevelWindow->isVisible()) + for (QWindow *topLevelWindow : topLevelWindows) { + if ((topLevelWindow->type() & Qt::Popup) == Qt::Popup && topLevelWindow->isVisible()) { topLevelWindow->hide(); + + if ((topLevelWindow->type() & Qt::Tool) == Qt::Tool) + hiddenWindows << topLevelWindow; + } } } +- (void)applicationDidUnhide:(NSNotification *)notification +{ + if (reflectionDelegate + && [reflectionDelegate respondsToSelector:@selector(applicationDidUnhide:)]) + [reflectionDelegate applicationDidUnhide:notification]; + + for (QWindow *window : qAsConst(hiddenWindows)) + window->show(); + + hiddenWindows.clear(); +} + - (void)applicationDidBecomeActive:(NSNotification *)notification { if (reflectionDelegate -- cgit v1.2.3 From e02d758c9509de31aafc82d53296f1acdab55151 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 22 Oct 2018 21:22:05 +0200 Subject: macOS: Treat explicitly set Qt::SubWindows as not needing a NSWindow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We used to have logic that explicitly marked a QWindow as "embedded", but we now resolve this dynamically based on whether or not we have a parent window owned by Qt or not. As part of this refactoring the fix for QTBUG-63443 in ac35f9c44c got lost. We restore the behavior by treating Qt::SubWindow as a reason not to create a NSWindow for a view. This flag is set by QMenuPrivate::moveWidgetToPlatformItem already. Fixes: QTBUG-63443 Change-Id: I12bff546eefcb8f6c9ca43b1b879773d129a28f9 Reviewed-by: Morten Johan Sørvig Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoawindow.mm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index a28bdd628b..1ce671941d 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1378,11 +1378,14 @@ void QCocoaWindow::recreateWindowIfNeeded() if (m_windowModality != window()->modality()) recreateReason |= WindowModalityChanged; - const bool shouldBeContentView = !parentWindow && !isEmbeddedView; + Qt::WindowType type = window()->type(); + + const bool shouldBeContentView = !parentWindow + && !((type & Qt::SubWindow) == Qt::SubWindow) + && !isEmbeddedView; if (isContentView() != shouldBeContentView) recreateReason |= ContentViewChanged; - Qt::WindowType type = window()->type(); const bool isPanel = isContentView() && [m_view.window isKindOfClass:[QNSPanel class]]; const bool shouldBePanel = shouldBeContentView && ((type & Qt::Popup) == Qt::Popup || (type & Qt::Dialog) == Qt::Dialog); -- cgit v1.2.3 From d4e937a6280f34bc1cce8c8cea3806a741312fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C5=82a=C5=BCej=20Szczygie=C5=82?= Date: Tue, 25 Sep 2018 18:45:10 +0200 Subject: xcb: Don't get initial screen rotation "xcb_randr_get_screen_info" can be slow and in some configurations can cause short mouse cursor freezes (which will happen on Qt application startup). Initial screen rotation was used only to not handle possible redundant screen change event. Fixes: QTBUG-70760 Change-Id: I9f01325a045d2c82c4dd2fce91a18a34e54a4bcd Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbscreen.cpp | 7 ------- src/plugins/platforms/xcb/qxcbscreen.h | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 7f2793b2b7..a696e2a311 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -118,13 +118,6 @@ QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t xcb_depth_next(&depth_iterator); } - - if (connection->hasXRandr()) { - xcb_connection_t *conn = connection->xcb_connection(); - auto screen_info = Q_XCB_REPLY(xcb_randr_get_screen_info, conn, screen->root); - if (screen_info) - m_rotation = screen_info->rotation; - } } QXcbVirtualDesktop::~QXcbVirtualDesktop() diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index 6438669e7a..792aca4b06 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -220,7 +220,7 @@ private: xcb_randr_crtc_t m_crtc; xcb_randr_mode_t m_mode = XCB_NONE; bool m_primary = false; - uint8_t m_rotation = XCB_RANDR_ROTATION_ROTATE_0; + uint8_t m_rotation = 0; QString m_outputName; QSizeF m_outputSizeMillimeters; -- cgit v1.2.3 From 4c37b64411f60d2667963db8e7d42459cad663e6 Mon Sep 17 00:00:00 2001 From: Jan Grulich Date: Thu, 18 Oct 2018 10:02:48 +0200 Subject: Add terminating character when sending byte arrays in FileChooser portal Terminating character is needed for gtk portal backend, which is not able to contruct a string without it and thus not able to pre-select a file or a directory in file dialog. Change-Id: I5b40fb1ce584936fc92e93f38dc8559890852d99 Reviewed-by: Thiago Macieira --- .../platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp index cda267d24b..5e94d1558e 100644 --- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp +++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp @@ -181,10 +181,10 @@ void QXdgDesktopPortalFileDialog::openPortal() if (d->saveFile) { if (!d->directory.isEmpty()) - options.insert(QLatin1String("current_folder"), d->directory.toLatin1()); + options.insert(QLatin1String("current_folder"), d->directory.toLatin1().append('\0')); if (!d->selectedFiles.isEmpty()) - options.insert(QLatin1String("current_file"), d->selectedFiles.first().toLatin1()); + options.insert(QLatin1String("current_file"), d->selectedFiles.first().toLatin1().append('\0')); } // Insert filters -- cgit v1.2.3 From f25c68646226fe19e98887ad43a7e12e0d87734b Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Fri, 26 Oct 2018 15:56:39 +0200 Subject: xcb: remove leftover function It was forgotten in 4050ee6ac7da0e5e7414c699c3cd4e26193c653d Change-Id: Icace56161b8ae372dba105f82da0d1c1b69542c1 Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbwindow.h | 1 - 1 file changed, 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 6667f45343..d2ca9fe0b9 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -207,7 +207,6 @@ protected: void setTransparentForMouseEvents(bool transparent); void updateDoesNotAcceptFocus(bool doesNotAcceptFocus); - QRect windowToWmGeometry(QRect r) const; void sendXEmbedMessage(xcb_window_t window, quint32 message, quint32 detail = 0, quint32 data1 = 0, quint32 data2 = 0); void handleXEmbedMessage(const xcb_client_message_event_t *event); -- cgit v1.2.3 From f5c0a19077989b5ac14071ecd095e29f62d05602 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Wed, 17 Oct 2018 17:28:55 +0200 Subject: xcb: move clipboard code out of QXcbConnection::processXcbEvents ... to QXcbConnection::handleXcbEvent(), which is where it belongs. This patch amends bc6f5b3ff61f4b1dea14084349702f2895feda66 (Sep, 2013). And some other design cleanups. Change-Id: Iefa0793c58de16a59d2294f38311e1e8dfa3035b Reviewed-by: Allan Sandfeld Jensen --- src/plugins/platforms/xcb/qxcbclipboard.cpp | 190 +++++++++++---------------- src/plugins/platforms/xcb/qxcbclipboard.h | 41 +++++- src/plugins/platforms/xcb/qxcbconnection.cpp | 13 +- src/plugins/platforms/xcb/qxcbconnection.h | 1 + 4 files changed, 118 insertions(+), 127 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index 3fd14a659e..9c7559d514 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -153,114 +153,71 @@ private: QByteArray format_atoms; }; -namespace { -class INCRTransaction; -typedef QMap TransactionMap; -static TransactionMap *transactions = 0; +QXcbClipboardTransaction::QXcbClipboardTransaction(QXcbClipboard *clipboard, xcb_window_t w, + xcb_atom_t p, QByteArray d, xcb_atom_t t, int f) + : m_clipboard(clipboard), m_window(w), m_property(p), m_data(d), m_target(t), m_format(f) +{ + const quint32 values[] = { XCB_EVENT_MASK_PROPERTY_CHANGE }; + xcb_change_window_attributes(m_clipboard->xcb_connection(), m_window, + XCB_CW_EVENT_MASK, values); -//#define INCR_DEBUG + m_abortTimerId = startTimer(m_clipboard->clipboardTimeout()); +} -class INCRTransaction : public QObject +QXcbClipboardTransaction::~QXcbClipboardTransaction() { - Q_OBJECT -public: - INCRTransaction(QXcbConnection *c, xcb_window_t w, xcb_atom_t p, - QByteArray d, uint i, xcb_atom_t t, int f, int to) : - conn(c), win(w), property(p), data(d), increment(i), - target(t), format(f), timeout(to), offset(0) - { - const quint32 values[] = { XCB_EVENT_MASK_PROPERTY_CHANGE }; - xcb_change_window_attributes(conn->xcb_connection(), win, - XCB_CW_EVENT_MASK, values); - if (!transactions) { -#ifdef INCR_DEBUG - qDebug("INCRTransaction: creating the TransactionMap"); -#endif - transactions = new TransactionMap; - conn->clipboard()->setProcessIncr(true); - } - transactions->insert(win, this); - abort_timer = startTimer(timeout); - } + if (m_abortTimerId) + killTimer(m_abortTimerId); + m_abortTimerId = 0; + m_clipboard->removeTransaction(m_window); +} - ~INCRTransaction() - { - if (abort_timer) - killTimer(abort_timer); - abort_timer = 0; - transactions->remove(win); - if (transactions->isEmpty()) { -#ifdef INCR_DEBUG - qDebug("INCRTransaction: no more INCR transactions left in the TransactionMap"); -#endif - delete transactions; - transactions = 0; - conn->clipboard()->setProcessIncr(false); - } - } +bool QXcbClipboardTransaction::updateIncrementalProperty(const xcb_property_notify_event_t *event) +{ + if (event->atom != m_property || event->state != XCB_PROPERTY_DELETE) + return false; - void updateIncrProperty(xcb_property_notify_event_t *event, bool &accepted) - { - xcb_connection_t *c = conn->xcb_connection(); - if (event->atom == property && event->state == XCB_PROPERTY_DELETE) { - accepted = true; - // restart the timer - if (abort_timer) - killTimer(abort_timer); - abort_timer = startTimer(timeout); - - unsigned int bytes_left = data.size() - offset; - if (bytes_left > 0) { - unsigned int bytes_to_send = qMin(increment, bytes_left); -#ifdef INCR_DEBUG - qDebug("INCRTransaction: sending %d bytes, %d remaining (INCR transaction %p)", - bytes_to_send, bytes_left - bytes_to_send, this); -#endif - int dataSize = bytes_to_send / (format / 8); - xcb_change_property(c, XCB_PROP_MODE_REPLACE, win, property, - target, format, dataSize, data.constData() + offset); - offset += bytes_to_send; - } else { -#ifdef INCR_DEBUG - qDebug("INCRTransaction: INCR transaction %p completed", this); -#endif - xcb_change_property(c, XCB_PROP_MODE_REPLACE, win, property, - target, format, 0, (const void *)0); - const quint32 values[] = { XCB_EVENT_MASK_NO_EVENT }; - xcb_change_window_attributes(conn->xcb_connection(), win, - XCB_CW_EVENT_MASK, values); - // self destroy - delete this; - } - } - } + // restart the timer + if (m_abortTimerId) + killTimer(m_abortTimerId); + m_abortTimerId = startTimer(m_clipboard->clipboardTimeout()); -protected: - void timerEvent(QTimerEvent *ev) override - { - if (ev->timerId() == abort_timer) { - // this can happen when the X client we are sending data - // to decides to exit (normally or abnormally) -#ifdef INCR_DEBUG - qDebug("INCRTransaction: Timed out while sending data to %p", this); -#endif - delete this; - } + uint bytes_left = uint(m_data.size()) - m_offset; + if (bytes_left > 0) { + int increment = m_clipboard->increment(); + uint bytes_to_send = qMin(uint(increment), bytes_left); + + qCDebug(lcQpaClipboard, "sending %d bytes, %d remaining, transaction: %p)", + bytes_to_send, bytes_left - bytes_to_send, this); + + uint32_t dataSize = bytes_to_send / (m_format / 8); + xcb_change_property(m_clipboard->xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + m_property, m_target, m_format, dataSize, m_data.constData() + m_offset); + m_offset += bytes_to_send; + } else { + qCDebug(lcQpaClipboard, "transaction %p completed", this); + + xcb_change_property(m_clipboard->xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + m_property, m_target, m_format, 0, nullptr); + + const quint32 values[] = { XCB_EVENT_MASK_NO_EVENT }; + xcb_change_window_attributes(m_clipboard->xcb_connection(), m_window, + XCB_CW_EVENT_MASK, values); + delete this; // self destroy } + return true; +} -private: - QXcbConnection *conn; - xcb_window_t win; - xcb_atom_t property; - QByteArray data; - uint increment; - xcb_atom_t target; - int format; - int timeout; - uint offset; - int abort_timer; -}; -} // unnamed namespace + +void QXcbClipboardTransaction::timerEvent(QTimerEvent *ev) +{ + if (ev->timerId() == m_abortTimerId) { + // this can happen when the X client we are sending data + // to decides to exit (normally or abnormally) + qCDebug(lcQpaClipboard, "timed out while sending data to %p", this); + delete this; // self destroy + } +} const int QXcbClipboard::clipboard_timeout = 5000; @@ -282,6 +239,9 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c) xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, XCB_ATOM_PRIMARY, mask); xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, atom(QXcbAtom::CLIPBOARD), mask); } + + // change property protocol request is 24 bytes + m_increment = (xcb_get_maximum_request_length(xcb_connection()) * 4) - 24; } QXcbClipboard::~QXcbClipboard() @@ -313,16 +273,17 @@ QXcbClipboard::~QXcbClipboard() delete m_clientClipboard[QClipboard::Selection]; } -void QXcbClipboard::incrTransactionPeeker(xcb_generic_event_t *ge, bool &accepted) +bool QXcbClipboard::handlePropertyNotify(const xcb_generic_event_t *event) { - uint response_type = ge->response_type & ~0x80; - if (response_type == XCB_PROPERTY_NOTIFY) { - xcb_property_notify_event_t *event = (xcb_property_notify_event_t *)ge; - TransactionMap::Iterator it = transactions->find(event->window); - if (it != transactions->end()) { - (*it)->updateIncrProperty(event, accepted); - } - } + if (m_transactions.isEmpty() || event->response_type != XCB_PROPERTY_NOTIFY) + return false; + + auto propertyNotify = reinterpret_cast(event); + TransactionMap::Iterator it = m_transactions.find(propertyNotify->window); + if (it == m_transactions.constEnd()) + return false; + + return (*it)->updateIncrementalProperty(propertyNotify); } xcb_window_t QXcbClipboard::getSelectionOwner(xcb_atom_t atom) const @@ -522,19 +483,18 @@ xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_win // This 'bool' can be removed once there is a proper fix for QTBUG-32853 if (m_clipboard_closing) allow_incr = false; - // X_ChangeProperty protocol request is 24 bytes - const int increment = (xcb_get_maximum_request_length(xcb_connection()) * 4) - 24; - if (data.size() > increment && allow_incr) { + + if (data.size() > m_increment && allow_incr) { long bytes = data.size(); xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property, atom(QXcbAtom::INCR), 32, 1, (const void *)&bytes); - new INCRTransaction(connection(), window, property, data, increment, - atomFormat, dataFormat, clipboard_timeout); + auto transaction = new QXcbClipboardTransaction(this, window, property, data, atomFormat, dataFormat); + m_transactions.insert(window, transaction); return property; } // make sure we can perform the XChangeProperty in a single request - if (data.size() > increment) + if (data.size() > m_increment) return XCB_NONE; // ### perhaps use several XChangeProperty calls w/ PropModeAppend? int dataSize = data.size() / (dataFormat / 8); // use a single request to transfer data diff --git a/src/plugins/platforms/xcb/qxcbclipboard.h b/src/plugins/platforms/xcb/qxcbclipboard.h index abab42a613..26d3b3b395 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.h +++ b/src/plugins/platforms/xcb/qxcbclipboard.h @@ -45,14 +45,41 @@ #include #include +#include + QT_BEGIN_NAMESPACE #ifndef QT_NO_CLIPBOARD class QXcbConnection; class QXcbScreen; +class QXcbClipboard; class QXcbClipboardMime; +class QXcbClipboardTransaction : public QObject +{ + Q_OBJECT +public: + QXcbClipboardTransaction(QXcbClipboard *clipboard, xcb_window_t w, xcb_atom_t p, + QByteArray d, xcb_atom_t t, int f); + ~QXcbClipboardTransaction(); + + bool updateIncrementalProperty(const xcb_property_notify_event_t *event); + +protected: + void timerEvent(QTimerEvent *ev) override; + +private: + QXcbClipboard *m_clipboard; + xcb_window_t m_window; + xcb_atom_t m_property; + QByteArray m_data; + xcb_atom_t m_target; + uint8_t m_format; + uint m_offset = 0; + int m_abortTimerId = 0; +}; + class QXcbClipboard : public QXcbObject, public QPlatformClipboard { public: @@ -81,13 +108,16 @@ public: QByteArray getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtatom); - void setProcessIncr(bool process) { m_incr_active = process; } - bool processIncr() { return m_incr_active; } - void incrTransactionPeeker(xcb_generic_event_t *ge, bool &accepted); + bool handlePropertyNotify(const xcb_generic_event_t *event); xcb_window_t getSelectionOwner(xcb_atom_t atom) const; QByteArray getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t t = 0); + int increment() const { return m_increment; } + int clipboardTimeout() const { return clipboard_timeout; } + + void removeTransaction(xcb_window_t window) { m_transactions.remove(window); } + private: xcb_generic_event_t *waitForClipboardEvent(xcb_window_t window, int type, bool checkManager = false); @@ -107,9 +137,12 @@ private: static const int clipboard_timeout; - bool m_incr_active = false; + int m_increment = 0; bool m_clipboard_closing = false; xcb_timestamp_t m_incr_receive_time = 0; + + using TransactionMap = QMap; + TransactionMap m_transactions; }; #endif // QT_NO_CLIPBOARD diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 45f096a13a..37ee980924 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -84,6 +84,7 @@ Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events") Q_LOGGING_CATEGORY(lcQpaEventReader, "qt.qpa.events.reader") Q_LOGGING_CATEGORY(lcQpaPeeker, "qt.qpa.peeker") Q_LOGGING_CATEGORY(lcQpaKeyboard, "qt.qpa.xkeyboard") +Q_LOGGING_CATEGORY(lcQpaClipboard, "qt.qpa.clipboard") Q_LOGGING_CATEGORY(lcQpaXDnd, "qt.qpa.xdnd") // this event type was added in libxcb 1.10, @@ -651,6 +652,10 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) break; case XCB_PROPERTY_NOTIFY: { +#ifndef QT_NO_CLIPBOARD + if (m_clipboard->handlePropertyNotify(event)) + break; +#endif auto propertyNotify = reinterpret_cast(event); if (propertyNotify->atom == atom(QXcbAtom::_NET_WORKAREA)) { QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(propertyNotify->window); @@ -1010,14 +1015,6 @@ void QXcbConnection::processXcbEvents(QEventLoop::ProcessEventsFlags flags) if (compressEvent(event)) continue; -#ifndef QT_NO_CLIPBOARD - bool accepted = false; - if (clipboard()->processIncr()) - clipboard()->incrTransactionPeeker(event, accepted); - if (accepted) - continue; -#endif - auto isWaitingFor = [=](PeekFunc peekFunc) { // These callbacks return true if the event is what they were // waiting for, remove them from the list in that case. diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 5d53b97d37..47036ca257 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -68,6 +68,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen) Q_DECLARE_LOGGING_CATEGORY(lcQpaEvents) Q_DECLARE_LOGGING_CATEGORY(lcQpaPeeker) Q_DECLARE_LOGGING_CATEGORY(lcQpaKeyboard) +Q_DECLARE_LOGGING_CATEGORY(lcQpaClipboard) Q_DECLARE_LOGGING_CATEGORY(lcQpaXDnd) Q_DECLARE_LOGGING_CATEGORY(lcQpaEventReader) -- cgit v1.2.3 From c9d18d4a9c9d1243a267316e2a702f9ba69de2fd Mon Sep 17 00:00:00 2001 From: Samuli Piippo Date: Wed, 31 Oct 2018 10:03:09 +0200 Subject: eglfs_kms: initialize m_deviceListener If QT_QPA_EGLFS_HIDECURSOR was enabled, m_deviceListener was never initialized, which caused segfault in the destructor. Task-number: QTBUG-71507 Change-Id: Id8b17f5312073249cd12995317213fd746753521 Reviewed-by: Laszlo Agocs --- .../platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp index 9bd7fee1fb..4d0cf0c47e 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp @@ -71,6 +71,7 @@ QEglFSKmsGbmCursor::QEglFSKmsGbmCursor(QEglFSKmsGbmScreen *screen) , m_bo(nullptr) , m_cursorImage(0, 0, 0, 0, 0, 0) , m_state(CursorPendingVisible) + , m_deviceListener(nullptr) { QByteArray hideCursorVal = qgetenv("QT_QPA_EGLFS_HIDECURSOR"); if (!hideCursorVal.isEmpty() && hideCursorVal.toInt()) { -- cgit v1.2.3 From d28c241ca1451812fafc0c761587abfa44405914 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Thu, 9 Aug 2018 14:08:04 +0200 Subject: xcb: cleanup _NET_WM_STATE handling Use function name overloading for all of _NET_WM_STATE setters for a mapped window, instead of few similar sounding functions, where all do the same thing. For an unmapped window rename updateNetWmStateBeforeMap() -> setNetWmStateOnUnmappedWindow(). Merge setNetWmStates(NetWmStates) into setNetWmStateOnUnmappedWindow() and add a comment explaining why it does what it does, as it was not obvious. Internally there are 2 variants: a) When a window is already mapped, to change the window state we send XCB_CLIENT_MESSAGE(_NET_WM_STATE) messages to the root window as per EWMH spec. The Window Manager MUST keep this property updated to reflect the current state of the window. If this variant of the overload is called while a window is not mapped yet, it does nothing. WM would ignore this message anyway. The state change is not lost, it will be set later and that is where the second variant comes in. b) On an unmapped window we can set _NET_WM_STATE by using setNetWmStateOnUnmappedWindow(). This function will read QWindow properties and set all of them via one xcb_change_property(_NET_WM_STATE) call. We do this inside QXcbWindow::show(), where we know that QWindow state properties won't change anymore until it gets mapped. Once it is mapped, we use the other variant. This patch doesn't change any functionality, just makes the code easier to follow. Change-Id: I4f4703a35de083fcfd398112eabd0a5aec358e51 Reviewed-by: Frederik Gladhorn --- src/plugins/platforms/xcb/qxcbwindow.cpp | 182 ++++++++++++++++--------------- src/plugins/platforms/xcb/qxcbwindow.h | 11 +- 2 files changed, 100 insertions(+), 93 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index e56f6b13d8..f553c286f9 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -755,7 +755,7 @@ void QXcbWindow::show() xcb_delete_property(xcb_connection(), m_window, XCB_ATOM_WM_TRANSIENT_FOR); // update _NET_WM_STATE - updateNetWmStateBeforeMap(); + setNetWmStateOnUnmappedWindow(); } // QWidget-attribute Qt::WA_ShowWithoutActivating. @@ -961,46 +961,6 @@ QXcbWindow::NetWmStates QXcbWindow::netWmStates() return result; } -void QXcbWindow::setNetWmStates(NetWmStates states) -{ - QVector atoms; - - auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(), - 0, m_window, atom(QXcbAtom::_NET_WM_STATE), - XCB_ATOM_ATOM, 0, 1024); - if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM && reply->value_len > 0) { - const xcb_atom_t *data = static_cast(xcb_get_property_value(reply.get())); - atoms.resize(reply->value_len); - memcpy((void *)&atoms.first(), (void *)data, reply->value_len * sizeof(xcb_atom_t)); - } - - if (states & NetWmStateAbove && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_ABOVE))) - atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_ABOVE)); - if (states & NetWmStateBelow && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_BELOW))) - atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_BELOW)); - if (states & NetWmStateFullScreen && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN))) - atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); - if (states & NetWmStateMaximizedHorz && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ))) - atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ)); - if (states & NetWmStateMaximizedVert && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT))) - atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); - if (states & NetWmStateModal && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_MODAL))) - atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MODAL)); - if (states & NetWmStateStaysOnTop && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP))) - atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP)); - if (states & NetWmStateDemandsAttention && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION))) - atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)); - - if (atoms.isEmpty()) { - xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_STATE)); - } else { - xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, - atom(QXcbAtom::_NET_WM_STATE), XCB_ATOM_ATOM, 32, - atoms.count(), atoms.constData()); - } - xcb_flush(xcb_connection()); -} - void QXcbWindow::setWindowFlags(Qt::WindowFlags flags) { Qt::WindowType type = static_cast(int(flags & Qt::WindowType_Mask)); @@ -1027,7 +987,7 @@ void QXcbWindow::setWindowFlags(Qt::WindowFlags flags) } setWmWindowType(wmWindowTypes, flags); - setNetWmStateWindowFlags(flags); + setNetWmState(flags); setMotifWmHints(flags); setTransparentForMouseEvents(flags & Qt::WindowTransparentForInput); @@ -1111,7 +1071,7 @@ void QXcbWindow::setMotifWmHints(Qt::WindowFlags flags) } } -void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two) +void QXcbWindow::setNetWmState(bool set, xcb_atom_t one, xcb_atom_t two) { xcb_client_message_event_t event; @@ -1131,6 +1091,96 @@ void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two) (const char *)&event); } +void QXcbWindow::setNetWmState(Qt::WindowStates state) +{ + if ((m_windowState ^ state) & Qt::WindowMaximized) { + setNetWmState(state & Qt::WindowMaximized, + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ), + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); + } + + if ((m_windowState ^ state) & Qt::WindowFullScreen) + setNetWmState(state & Qt::WindowFullScreen, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); +} + +void QXcbWindow::setNetWmState(Qt::WindowFlags flags) +{ + setNetWmState(flags & Qt::WindowStaysOnTopHint, + atom(QXcbAtom::_NET_WM_STATE_ABOVE), + atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP)); + setNetWmState(flags & Qt::WindowStaysOnBottomHint, atom(QXcbAtom::_NET_WM_STATE_BELOW)); +} + +void QXcbWindow::setNetWmStateOnUnmappedWindow() +{ + if (Q_UNLIKELY(m_mapped)) + qCWarning(lcQpaXcb()) << "internal error: " << Q_FUNC_INFO << "called on mapped window"; + + NetWmStates states(0); + const Qt::WindowFlags flags = window()->flags(); + if (flags & Qt::WindowStaysOnTopHint) { + states |= NetWmStateAbove; + states |= NetWmStateStaysOnTop; + } else if (flags & Qt::WindowStaysOnBottomHint) { + states |= NetWmStateBelow; + } + + if (window()->windowStates() & Qt::WindowFullScreen) + states |= NetWmStateFullScreen; + + if (window()->windowStates() & Qt::WindowMaximized) { + states |= NetWmStateMaximizedHorz; + states |= NetWmStateMaximizedVert; + } + + if (window()->modality() != Qt::NonModal) + states |= NetWmStateModal; + + // According to EWMH: + // "The Window Manager should remove _NET_WM_STATE whenever a window is withdrawn". + // Which means that we don't have to read this property before changing it on a withdrawn + // window. But there are situations where users want to adjust this property as well + // (e4cea305ed2ba3c9f580bf9d16c59a1048af0e8a), so instead of overwriting the property + // we first read it and then merge our hints with the existing values, allowing a user + // to set custom hints. + + QVector atoms; + auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(), + 0, m_window, atom(QXcbAtom::_NET_WM_STATE), + XCB_ATOM_ATOM, 0, 1024); + if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM && reply->value_len > 0) { + const xcb_atom_t *data = static_cast(xcb_get_property_value(reply.get())); + atoms.resize(reply->value_len); + memcpy((void *)&atoms.first(), (void *)data, reply->value_len * sizeof(xcb_atom_t)); + } + + if (states & NetWmStateAbove && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_ABOVE))) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_ABOVE)); + if (states & NetWmStateBelow && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_BELOW))) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_BELOW)); + if (states & NetWmStateFullScreen && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN))) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); + if (states & NetWmStateMaximizedHorz && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ))) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ)); + if (states & NetWmStateMaximizedVert && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT))) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); + if (states & NetWmStateModal && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_MODAL))) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MODAL)); + if (states & NetWmStateStaysOnTop && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP))) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP)); + if (states & NetWmStateDemandsAttention && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION))) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)); + + if (atoms.isEmpty()) { + xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_STATE)); + } else { + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + atom(QXcbAtom::_NET_WM_STATE), XCB_ATOM_ATOM, 32, + atoms.count(), atoms.constData()); + } + xcb_flush(xcb_connection()); +} + void QXcbWindow::setWindowState(Qt::WindowStates state) { if (state == m_windowState) @@ -1158,14 +1208,7 @@ void QXcbWindow::setWindowState(Qt::WindowStates state) m_minimized = true; } - if ((m_windowState ^ state) & Qt::WindowMaximized) { - changeNetWmState(state & Qt::WindowMaximized, atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ), - atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); - } - - if ((m_windowState ^ state) & Qt::WindowFullScreen) { - changeNetWmState(state & Qt::WindowFullScreen, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); - } + setNetWmState(state); xcb_get_property_cookie_t cookie = xcb_get_wm_hints_unchecked(xcb_connection(), m_window); xcb_wm_hints_t hints; @@ -1181,41 +1224,6 @@ void QXcbWindow::setWindowState(Qt::WindowStates state) m_windowState = state; } -void QXcbWindow::updateNetWmStateBeforeMap() -{ - NetWmStates states(0); - - const Qt::WindowFlags flags = window()->flags(); - if (flags & Qt::WindowStaysOnTopHint) { - states |= NetWmStateAbove; - states |= NetWmStateStaysOnTop; - } else if (flags & Qt::WindowStaysOnBottomHint) { - states |= NetWmStateBelow; - } - - if (window()->windowStates() & Qt::WindowFullScreen) - states |= NetWmStateFullScreen; - - if (window()->windowStates() & Qt::WindowMaximized) { - states |= NetWmStateMaximizedHorz; - states |= NetWmStateMaximizedVert; - } - - if (window()->modality() != Qt::NonModal) - states |= NetWmStateModal; - - setNetWmStates(states); -} - -void QXcbWindow::setNetWmStateWindowFlags(Qt::WindowFlags flags) -{ - changeNetWmState(flags & Qt::WindowStaysOnTopHint, - atom(QXcbAtom::_NET_WM_STATE_ABOVE), - atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP)); - changeNetWmState(flags & Qt::WindowStaysOnBottomHint, - atom(QXcbAtom::_NET_WM_STATE_BELOW)); -} - void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp) { xcb_window_t wid = m_window; @@ -2588,7 +2596,7 @@ void QXcbWindow::setAlertState(bool enabled) m_alertState = enabled; - changeNetWmState(enabled, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)); + setNetWmState(enabled, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)); } uint QXcbWindow::visualId() const diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index d2ca9fe0b9..f98cd8a74d 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -193,17 +193,16 @@ protected: void setImageFormatForVisual(const xcb_visualtype_t *visual); QXcbScreen *parentScreen(); - QXcbScreen *initialScreen() const; - void changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two = 0); + + void setNetWmState(bool set, xcb_atom_t one, xcb_atom_t two = 0); + void setNetWmState(Qt::WindowFlags flags); + void setNetWmState(Qt::WindowStates state); + void setNetWmStateOnUnmappedWindow(); NetWmStates netWmStates(); - void setNetWmStates(NetWmStates); void setMotifWmHints(Qt::WindowFlags flags); - void setNetWmStateWindowFlags(Qt::WindowFlags flags); - void updateNetWmStateBeforeMap(); - void setTransparentForMouseEvents(bool transparent); void updateDoesNotAcceptFocus(bool doesNotAcceptFocus); -- cgit v1.2.3 From 98365711a0c06673b8f55d43ba227a640dc798a6 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Sun, 28 Oct 2018 15:30:51 +0100 Subject: Remove unused variable Change-Id: I241969d10502e944f7a73971771730d43dd2784f Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbeventdispatcher.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbeventdispatcher.h b/src/plugins/platforms/xcb/qxcbeventdispatcher.h index 6aadd63a70..ddf448cf87 100644 --- a/src/plugins/platforms/xcb/qxcbeventdispatcher.h +++ b/src/plugins/platforms/xcb/qxcbeventdispatcher.h @@ -107,9 +107,6 @@ class QXcbEventDispatcher { public: static QAbstractEventDispatcher *createEventDispatcher(QXcbConnection *connection); - -private: - QXcbConnection *m_connection; }; QT_END_NAMESPACE -- cgit v1.2.3 From 67c66c4ea4fbc11ee5547095117ef8930b3ab950 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 7 Sep 2018 15:01:07 +0200 Subject: windows: Give up on SwitchableComposition Opt out of switching between the normal and OpenGL based flush paths. Once a QOpenGLWidget or QQuickWidget becomes visible in a window, the window contents will be composed using OpenGL from that point on, even if said widgets become invisible afterwards. Now that Qt Creator does not rely on QQuickWidget the issue is less burning anyways. Task-number: QTBUG-68329 Change-Id: I177e6e6094ee06ea26d8d0343bd3d84aadfa5913 Reviewed-by: Friedemann Kleint Reviewed-by: Allan Sandfeld Jensen --- src/plugins/platforms/windows/qwindowsintegration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 0a9e8b9d91..66a5c52da5 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -300,7 +300,7 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co case AllGLFunctionsQueryable: return true; case SwitchableWidgetComposition: - return true; + return false; // QTBUG-68329 QTBUG-53515 QTBUG-54734 default: return QPlatformIntegration::hasCapability(cap); } -- cgit v1.2.3 From 9f2216667a96c2de94b28e4fd2891b6d3b938cb9 Mon Sep 17 00:00:00 2001 From: Andrew Smolko Date: Tue, 6 Nov 2018 11:20:34 +0300 Subject: Fix memory copy in QGIFFormat::disposePrevious() Fix invalid destination address in memcpy operation when RestoreImage disposal method is used. Task-number: QTBUG-71599 Change-Id: Ib74a044c0e45250ff708268c463f831ee54933e6 Reviewed-by: Eirik Aavitsland --- src/plugins/imageformats/gif/qgifhandler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/imageformats/gif/qgifhandler.cpp b/src/plugins/imageformats/gif/qgifhandler.cpp index ebe5964664..1aef1a24d2 100644 --- a/src/plugins/imageformats/gif/qgifhandler.cpp +++ b/src/plugins/imageformats/gif/qgifhandler.cpp @@ -213,7 +213,7 @@ void QGIFFormat::disposePrevious(QImage *image) case RestoreImage: { if (frame >= 0) { for (int ln=t; ln<=b; ln++) { - memcpy(image->scanLine(ln)+l, + memcpy(image->scanLine(ln)+l*sizeof(QRgb), backingstore.constScanLine(ln-t), (r-l+1)*sizeof(QRgb)); } @@ -426,7 +426,7 @@ int QGIFFormat::decode(QImage *image, const uchar *buffer, int length, unsigned char *dest_data = backingstore.bits(); for (int ln=0; ln Date: Mon, 19 Feb 2018 10:23:15 +0100 Subject: White-list more recent Mesa version for multi-threading The issue we had has been fixed for years, but was unfortunately in libxcb which we can't check at runtime. Instead assume very recent Mesa drivers works. Change-Id: I5fdd726b480b77edbedc0f369ae82ab4acbb77c9 Reviewed-by: Frederik Gladhorn Reviewed-by: Laszlo Agocs --- .../gl_integrations/xcb_glx/qglxintegration.cpp | 60 +++++++++------------- 1 file changed, 25 insertions(+), 35 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp index 741885e321..6316aa2d99 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -51,6 +51,7 @@ #undef register #include +#include #include #include @@ -692,32 +693,6 @@ static const char *qglx_threadedgl_blacklist_renderer[] = { 0 }; -// This disables threaded rendering on anything using mesa, e.g. -// - nvidia/nouveau -// - amd/gallium -// - intel -// - some software opengl implementations -// -// The client glx vendor string is used to identify those setups as that seems to show the least -// variance between the bad configurations. It's always "Mesa Project and SGI". There are some -// configurations which don't use mesa and which can do threaded rendering (amd and nvidia chips -// with their own proprietary drivers). -// -// This, of course, is very broad and disables threaded rendering on a lot of devices which would -// be able to use it. However, the bugs listed below don't follow any easily recognizable pattern -// and we should rather be safe. -// -// http://cgit.freedesktop.org/xcb/libxcb/commit/?id=be0fe56c3bcad5124dcc6c47a2fad01acd16f71a will -// fix some of the issues. Basically, the proprietary drivers seem to have a way of working around -// a fundamental flaw with multithreaded access to xcb, but mesa doesn't. The blacklist should be -// reevaluated once that patch is released in some version of xcb. -static const char *qglx_threadedgl_blacklist_vendor[] = { - "Mesa Project and SGI", // QTCREATORBUG-10875 (crash in creator) - // QTBUG-34492 (flickering in fullscreen) - // QTBUG-38221 - 0 -}; - void QGLXContext::queryDummyContext() { if (m_queriedDummyContext) @@ -777,18 +752,33 @@ void QGLXContext::queryDummyContext() } } - if (glxvendor) { - for (int i = 0; qglx_threadedgl_blacklist_vendor[i]; ++i) { - if (strstr(glxvendor, qglx_threadedgl_blacklist_vendor[i]) != 0) { - qCDebug(lcQpaGl).nospace() << "Multithreaded OpenGL disabled: " - "blacklisted vendor \"" - << qglx_threadedgl_blacklist_vendor[i] - << "\""; + if (glxvendor && m_supportsThreading) { + // Blacklist Mesa drivers due to QTCREATORBUG-10875 (crash in creator), + // QTBUG-34492 (flickering in fullscreen) and QTBUG-38221 + const char *mesaVersionStr = nullptr; + if (strstr(glxvendor, "Mesa Project") != 0) { + mesaVersionStr = (const char *) glGetString(GL_VERSION); + m_supportsThreading = false; + } - m_supportsThreading = false; - break; + if (mesaVersionStr) { + // The issue was fixed in Xcb 1.11, but we can't check for that + // at runtime, so instead assume it fixed with recent Mesa versions + // released several years after the Xcb fix. + QRegularExpression versionTest(QStringLiteral("Mesa (\\d+)")); + QRegularExpressionMatch result = versionTest.match(QString::fromLatin1(mesaVersionStr)); + int versionNr = 0; + if (result.hasMatch()) + versionNr = result.captured(1).toInt(); + if (versionNr >= 17) { + // White-listed + m_supportsThreading = true; } } + if (!m_supportsThreading) { + qCDebug(lcQpaGl).nospace() << "Multithreaded OpenGL disabled: " + "blacklisted vendor \"Mesa Project\""; + } } context.doneCurrent(); -- cgit v1.2.3 From edacfd2f0b6f95430b62296853c3ae5b3405b406 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 6 Nov 2018 12:01:33 +0100 Subject: Fix QTableView/Widget on macOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For this we can use whatever the current NSColor.gridColor contains. While this is mostly needed by the 'Dark' appearance, it also affects the 'Light' theme, since the color QCommonStyle returns is different. Let's use whatever Apple suggests. Task-number: QTBUG-71048 Change-Id: I084414bad546755e9e67792484fe4601826ed0fa Reviewed-by: Tor Arne Vestbø --- src/plugins/styles/mac/qmacstyle_mac.mm | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 94d048ca7e..0204bd6104 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -2789,6 +2789,9 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w case SH_SpinBox_ButtonsInsideFrame: ret = false; break; + case SH_Table_GridLineColor: + ret = int(qt_mac_toQColor(NSColor.gridColor).rgb()); + break; default: ret = QCommonStyle::styleHint(sh, opt, w, hret); break; -- cgit v1.2.3 From 825f98815683faea06144ab0262129b0367798ee Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Tue, 2 Oct 2018 12:59:24 +0200 Subject: Modernize the "textcodec" feature Also clean up QTextCodec usage in qmake build and some includes of qtextcodec.h. Change-Id: I0475b82690024054add4e85a8724c8ea3adcf62a Reviewed-by: Edward Welbourne Reviewed-by: Oswald Buddenhagen --- .../platforms/cocoa/qcocoafiledialoghelper.mm | 1 - src/plugins/platforms/cocoa/qpaintengine_mac.mm | 1 - src/plugins/platforms/xcb/qxcbmime.cpp | 2 +- src/plugins/sqldrivers/mysql/qsql_mysql.cpp | 20 +++++++++++--------- 4 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 94f2125bad..0035d30e36 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -56,7 +56,6 @@ #include #include #include -#include #include #include #include diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm index 3f363b62d5..f3629c2eb4 100644 --- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include diff --git a/src/plugins/platforms/xcb/qxcbmime.cpp b/src/plugins/platforms/xcb/qxcbmime.cpp index 7170d259fd..d611f86a9c 100644 --- a/src/plugins/platforms/xcb/qxcbmime.cpp +++ b/src/plugins/platforms/xcb/qxcbmime.cpp @@ -168,7 +168,7 @@ QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, if (!encoding.isEmpty() && atomName == format + QLatin1String(";charset=") + QLatin1String(encoding)) { -#ifndef QT_NO_TEXTCODEC +#if QT_CONFIG(textcodec) if (requestedType == QVariant::String) { QTextCodec *codec = QTextCodec::codecForName(encoding); if (codec) diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp index 5a100b8075..49bceb88a0 100644 --- a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp +++ b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp @@ -48,7 +48,9 @@ #include #include #include +#if QT_CONFIG(textcodec) #include +#endif #include #include #include @@ -82,7 +84,7 @@ class QMYSQLDriverPrivate : public QSqlDriverPrivate public: QMYSQLDriverPrivate() : QSqlDriverPrivate(), mysql(0), -#ifndef QT_NO_TEXTCODEC +#if QT_CONFIG(textcodec) tc(QTextCodec::codecForLocale()), #else tc(0), @@ -96,7 +98,7 @@ public: static inline QString toUnicode(QTextCodec *tc, const char *str) { -#ifdef QT_NO_TEXTCODEC +#if !QT_CONFIG(textcodec) Q_UNUSED(tc); return QString::fromLatin1(str); #else @@ -106,7 +108,7 @@ static inline QString toUnicode(QTextCodec *tc, const char *str) static inline QString toUnicode(QTextCodec *tc, const char *str, int length) { -#ifdef QT_NO_TEXTCODEC +#if !QT_CONFIG(textcodec) Q_UNUSED(tc); return QString::fromLatin1(str, length); #else @@ -116,7 +118,7 @@ static inline QString toUnicode(QTextCodec *tc, const char *str, int length) static inline QByteArray fromUnicode(QTextCodec *tc, const QString &str) { -#ifdef QT_NO_TEXTCODEC +#if !QT_CONFIG(textcodec) Q_UNUSED(tc); return str.toLatin1(); #else @@ -251,7 +253,7 @@ public: bool preparedQuery; }; -#ifndef QT_NO_TEXTCODEC +#if QT_CONFIG(textcodec) static QTextCodec* codec(MYSQL* mysql) { #if MYSQL_VERSION_ID >= 32321 @@ -261,7 +263,7 @@ static QTextCodec* codec(MYSQL* mysql) #endif return QTextCodec::codecForLocale(); } -#endif // QT_NO_TEXTCODEC +#endif // textcodec static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, const QMYSQLDriverPrivate* p) @@ -1199,7 +1201,7 @@ QMYSQLDriver::QMYSQLDriver(MYSQL * con, QObject * parent) init(); if (con) { d->mysql = (MYSQL *) con; -#ifndef QT_NO_TEXTCODEC +#if QT_CONFIG(textcodec) d->tc = codec(con); #endif setOpen(true); @@ -1428,14 +1430,14 @@ bool QMYSQLDriver::open(const QString& db, if (mysql_get_client_version() >= 50503 && mysql_get_server_version(d->mysql) >= 50503) { // force the communication to be utf8mb4 (only utf8mb4 supports 4-byte characters) mysql_set_character_set(d->mysql, "utf8mb4"); -#ifndef QT_NO_TEXTCODEC +#if QT_CONFIG(textcodec) d->tc = QTextCodec::codecForName("UTF-8"); #endif } else { // force the communication to be utf8 mysql_set_character_set(d->mysql, "utf8"); -#ifndef QT_NO_TEXTCODEC +#if QT_CONFIG(textcodec) d->tc = codec(d->mysql); #endif } -- cgit v1.2.3 From 2569ac2857a52fa271a7038e0c36fe3e5b2d760e Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Fri, 26 Oct 2018 14:07:36 +0200 Subject: xcb: fix regression with open/close hand cursors On Linux the correspondence between cursor functions and names of cursors has never been standardized. Projects have either assembled their own cursor function-to-name lookup table or borrowed the table from other projects. The origins of our table is described in QTBUG-71423. On Ubuntu the default theme is called Adwaita. Before bd72950fbedc457fb997e99beff4767505ff5d8f, we would not find a cursor for 'openhand' and would fall-back to QXcbCursor:: createNonStandardCursor(). Which was sub-optimal, because the cursors created by the fall-back path don't look like the themed ones. But the situation was worse after bd72950fb (hence the regression) - the 'openhand' fall-back name 'fleur' is a symbolic link to 'grabbing', so we would get into a situation where Qt::OpenHandCursor displays the same as Qt::ClosedHandCursor. This patch adds a correct fall-back name for 'openhand' on Adwaita, which is 'grab'. 'grab' actually is a symbolic link to 'hand1', but 'hand1' with other theams is a pointing hand cursor, that is why we use the symbolic link's name in this case. The lookup table still appears to be incomplete when comparing e.g with KWin. Eventually we need to revise the table and put in a common place so it can be shared between X11 and Wayland, but is out-of-scope for this patch (see QTBUG-71423). Fixes: QTBUG-71296 Task-number: QTBUG-71423 Change-Id: I247ed4b346c2cd3fe1c7fd0440d3763e0033346b Reviewed-by: Frederik Gladhorn --- src/plugins/platforms/xcb/qxcbcursor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp index 57629ac03a..7831671d42 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.cpp +++ b/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -255,6 +255,7 @@ static const uint8_t * const cursor_bits20[] = { forbidden_bits, forbiddenm_bits }; +// ### FIXME This mapping is incomplete - QTBUG-71423 static const std::vector cursorNames[] = { { "left_ptr", "default", "top_left_arrow", "left_arrow" }, { "up_arrow" }, @@ -273,7 +274,7 @@ static const std::vector cursorNames[] = { { "forbidden", "not-allowed", "crossed_circle", "circle", "03b6e0fcb3499374a867c041f52298f0" }, { "whats_this", "help", "question_arrow", "5c6cd98b3f3ebcb1f9c7f1c204630408", "d9ce0ab605698f320427677b458ad60b" }, { "left_ptr_watch", "half-busy", "progress", "00000000000000020006000e7e9ffc3f", "08e8e1c95fe2fc01f976f1e063a24ccd" }, - { "openhand", "fleur", "5aca4d189052212118709018842178c0", "9d800788f1b08800ae810202380a0822" }, + { "openhand", "grab", "fleur", "5aca4d189052212118709018842178c0", "9d800788f1b08800ae810202380a0822" }, { "closedhand", "grabbing", "208530c400c041818281048008011002" }, { "dnd-copy", "copy" }, { "dnd-move", "move" }, -- cgit v1.2.3 From 35069301f048eed21a27f89b6495d56c44f2b55d Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Tue, 30 Oct 2018 17:58:17 +0100 Subject: Windows QPA: Fix incorrect button state reporting for touchpad The current state of (emulated) mouse buttons was being incorrectly reported for touchpad events under some conditions. In the handling of pointer messages, GetAsyncKeyState() was being used to retrieve the mouse button state. However, it does not seem to work always with all touchpads. Furthermore, its use is not necessary, since the button state information comes as a set of flags with the pointer message itself. This change makes the handler use these flags instead. Fixes: QTBUG-71470 Change-Id: Ie2e35bd80778ef74db672604a0f2af659785efbf Reviewed-by: Friedemann Kleint --- .../platforms/windows/qwindowspointerhandler.cpp | 53 ++++++++++++++-------- .../platforms/windows/qwindowspointerhandler.h | 1 - 2 files changed, 34 insertions(+), 20 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 2b6c696979..4d3e2f71ec 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -336,6 +336,38 @@ static void getMouseEventInfo(UINT message, POINTER_BUTTON_CHANGE_TYPE changeTyp *mouseButton = buttonMapping.value(changeType, Qt::NoButton); } +static Qt::MouseButtons mouseButtonsFromPointerFlags(POINTER_FLAGS pointerFlags) +{ + Qt::MouseButtons result = Qt::NoButton; + if (pointerFlags & POINTER_FLAG_FIRSTBUTTON) + result |= Qt::LeftButton; + if (pointerFlags & POINTER_FLAG_SECONDBUTTON) + result |= Qt::RightButton; + if (pointerFlags & POINTER_FLAG_THIRDBUTTON) + result |= Qt::MiddleButton; + if (pointerFlags & POINTER_FLAG_FOURTHBUTTON) + result |= Qt::XButton1; + if (pointerFlags & POINTER_FLAG_FIFTHBUTTON) + result |= Qt::XButton2; + return result; +} + +static Qt::MouseButtons mouseButtonsFromKeyState(WPARAM keyState) +{ + Qt::MouseButtons result = Qt::NoButton; + if (keyState & MK_LBUTTON) + result |= Qt::LeftButton; + if (keyState & MK_RBUTTON) + result |= Qt::RightButton; + if (keyState & MK_MBUTTON) + result |= Qt::MiddleButton; + if (keyState & MK_XBUTTON1) + result |= Qt::XButton1; + if (keyState & MK_XBUTTON2) + result |= Qt::XButton2; + return result; +} + static QWindow *getWindowUnderPointer(QWindow *window, QPoint globalPos) { QWindow *currentWindowUnderPointer = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT); @@ -405,23 +437,6 @@ QTouchDevice *QWindowsPointerHandler::ensureTouchDevice() return m_touchDevice; } -Qt::MouseButtons QWindowsPointerHandler::queryMouseButtons() -{ - Qt::MouseButtons result = 0; - const bool mouseSwapped = GetSystemMetrics(SM_SWAPBUTTON); - if (GetAsyncKeyState(VK_LBUTTON) < 0) - result |= mouseSwapped ? Qt::RightButton: Qt::LeftButton; - if (GetAsyncKeyState(VK_RBUTTON) < 0) - result |= mouseSwapped ? Qt::LeftButton : Qt::RightButton; - if (GetAsyncKeyState(VK_MBUTTON) < 0) - result |= Qt::MidButton; - if (GetAsyncKeyState(VK_XBUTTON1) < 0) - result |= Qt::XButton1; - if (GetAsyncKeyState(VK_XBUTTON2) < 0) - result |= Qt::XButton2; - return result; -} - bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPointerInfo) @@ -430,7 +445,7 @@ bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND h const QPoint globalPos = QPoint(pointerInfo->ptPixelLocation.x, pointerInfo->ptPixelLocation.y); const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos); const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); - const Qt::MouseButtons mouseButtons = queryMouseButtons(); + const Qt::MouseButtons mouseButtons = mouseButtonsFromPointerFlags(pointerInfo->pointerFlags); QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos); QWindowsWindow *platformWindow = static_cast(window->handle()); @@ -788,7 +803,7 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW m_windowUnderPointer = currentWindowUnderPointer; } - const Qt::MouseButtons mouseButtons = queryMouseButtons(); + const Qt::MouseButtons mouseButtons = mouseButtonsFromKeyState(msg.wParam); if (!discardEvent) QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, Qt::NoButton, QEvent::MouseMove, diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.h b/src/plugins/platforms/windows/qwindowspointerhandler.h index c4d0e0ce4a..3861ebf919 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.h +++ b/src/plugins/platforms/windows/qwindowspointerhandler.h @@ -61,7 +61,6 @@ public: bool translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result); QTouchDevice *touchDevice() const { return m_touchDevice; } QTouchDevice *ensureTouchDevice(); - Qt::MouseButtons queryMouseButtons(); QWindow *windowUnderMouse() const { return m_windowUnderPointer.data(); } void clearWindowUnderMouse() { m_windowUnderPointer = nullptr; } -- cgit v1.2.3 From 9137691e745039f8ad9cdee2594a958e244ba341 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 5 Nov 2018 10:18:50 +0100 Subject: Windows QPA: Fix crash showing QSystemTrayIcon's context menu with PROCESS_DPI_UNAWARE The coordinates of the WM_CONTEXT message may be out of any screen in PROCESS_DPI_UNAWARE mode since hi-res coordinates are delivered in this case (Windows issue). Default to primary screen with check to prevent a crash. Fixes: QTBUG-67966 Change-Id: I1950360520e93cbf3509611b3057635769f6543a Reviewed-by: Andre de la Rocha --- .../platforms/windows/qwindowssystemtrayicon.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp index 901d132ea5..3c27f2914d 100644 --- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp +++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp @@ -382,12 +382,20 @@ bool QWindowsSystemTrayIcon::winEvent(const MSG &message, long *result) emit activated(DoubleClick); // release we must ignore it break; case WM_CONTEXTMENU: { + // QTBUG-67966: Coordinates may be out of any screen in PROCESS_DPI_UNAWARE mode + // since hi-res coordinates are delivered in this case (Windows issue). + // Default to primary screen with check to prevent a crash. const QPoint globalPos = QPoint(GET_X_LPARAM(message.wParam), GET_Y_LPARAM(message.wParam)); - const QPlatformScreen *screen = QWindowsContext::instance()->screenManager().screenAtDp(globalPos); - emit contextMenuRequested(globalPos, screen); - emit activated(Context); - if (m_menu) - m_menu->trackPopupMenu(message.hwnd, globalPos.x(), globalPos.y()); + const auto &screenManager = QWindowsContext::instance()->screenManager(); + const QPlatformScreen *screen = screenManager.screenAtDp(globalPos); + if (!screen) + screen = screenManager.screens().value(0); + if (screen) { + emit contextMenuRequested(globalPos, screen); + emit activated(Context); + if (m_menu) + m_menu->trackPopupMenu(message.hwnd, globalPos.x(), globalPos.y()); + } } break; case NIN_BALLOONUSERCLICK: -- cgit v1.2.3 From 2697148775703883ae700b15d4efe240050273a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 22 Oct 2018 13:04:42 +0200 Subject: macOS: Only enable layer-backed views on 10.14 if built against 10.14 SDK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of explicitly enabling layer-backing for Qt 5.12 on all macOS version, we follow the macOS default to enable it for 10.14 if the application binary was built against the 10.14 SDK. Aligning ourselves with Apple's switch to forced layer-backing means we have an easier story when it comes to supporting different runtime configurations. Fixes: QTBUG-71499 Change-Id: I34ee49b3daeb6ed8df444a3759d3573ebc9ea30f Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qnsview.mm | 15 +------ src/plugins/platforms/cocoa/qnsview_drawing.mm | 61 +++++++++++++++++++++----- 2 files changed, 53 insertions(+), 23 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 9bd53ed334..540f701d43 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -71,7 +71,7 @@ @end @interface QT_MANGLE_NAMESPACE(QNSView) (Drawing) -- (BOOL)wantsLayerHelper; +- (void)initDrawing; @end @interface QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) : NSObject @@ -152,19 +152,8 @@ self.focusRingType = NSFocusRingTypeNone; self.cursor = nil; - self.wantsLayer = [self wantsLayerHelper]; - - // Enable high-DPI OpenGL for retina displays. Enabling has the side - // effect that Cocoa will start calling glViewport(0, 0, width, height), - // overriding any glViewport calls in application code. This is usually not a - // problem, except if the application wants to have a "custom" viewport. - // (like the hellogl example) - if (m_platformWindow->window()->supportsOpenGL()) { - self.wantsBestResolutionOpenGLSurface = qt_mac_resolveOption(YES, m_platformWindow->window(), - "_q_mac_wantsBestResolutionOpenGLSurface", "QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE"); - // See also QCocoaGLContext::makeCurrent for software renderer workarounds. - } + [self initDrawing]; [self registerDragTypes]; [[NSNotificationCenter defaultCenter] addObserver:self diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm index 4f9d17504d..e9af90a45c 100644 --- a/src/plugins/platforms/cocoa/qnsview_drawing.mm +++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm @@ -41,6 +41,24 @@ @implementation QT_MANGLE_NAMESPACE(QNSView) (Drawing) +- (void)initDrawing +{ + self.wantsLayer = [self layerExplicitlyRequested] + || [self shouldUseMetalLayer] + || [self layerEnabledByMacOS]; + + // Enable high-DPI OpenGL for retina displays. Enabling has the side + // effect that Cocoa will start calling glViewport(0, 0, width, height), + // overriding any glViewport calls in application code. This is usually not a + // problem, except if the application wants to have a "custom" viewport. + // (like the hellogl example) + if (m_platformWindow->window()->supportsOpenGL()) { + self.wantsBestResolutionOpenGLSurface = qt_mac_resolveOption(YES, m_platformWindow->window(), + "_q_mac_wantsBestResolutionOpenGLSurface", "QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE"); + // See also QCocoaGLContext::makeCurrent for software renderer workarounds. + } +} + - (BOOL)isOpaque { if (!m_platformWindow) @@ -71,23 +89,38 @@ m_platformWindow->handleExposeEvent(exposedRegion); } -- (BOOL)shouldUseMetalLayer +- (BOOL)layerEnabledByMacOS { - // MetalSurface needs a layer, and so does VulkanSurface (via MoltenVK) - QSurface::SurfaceType surfaceType = m_platformWindow->window()->surfaceType(); - return surfaceType == QWindow::MetalSurface || surfaceType == QWindow::VulkanSurface; + // AppKit has its own logic for this, but if we rely on that, our layers are created + // by AppKit at a point where we've already set up other parts of the platform plugin + // based on the presence of layers or not. Once we've rewritten these parts to support + // dynamically picking up layer enablement we can let AppKit do its thing. + return QMacVersion::buildSDK() >= QOperatingSystemVersion::MacOSMojave + && QMacVersion::currentRuntime() >= QOperatingSystemVersion::MacOSMojave; } -- (BOOL)wantsLayerHelper +- (BOOL)layerExplicitlyRequested { - Q_ASSERT(m_platformWindow); + static bool wantsLayer = [&]() { + int wantsLayer = qt_mac_resolveOption(-1, m_platformWindow->window(), + "_q_mac_wantsLayer", "QT_MAC_WANTS_LAYER"); - bool wantsLayer = qt_mac_resolveOption(true, m_platformWindow->window(), - "_q_mac_wantsLayer", "QT_MAC_WANTS_LAYER"); + if (wantsLayer != -1 && [self layerEnabledByMacOS]) { + qCWarning(lcQpaDrawing) << "Layer-backing can not be explicitly controlled on 10.14 when built against the 10.14 SDK"; + return true; + } - bool layerForSurfaceType = [self shouldUseMetalLayer]; + return wantsLayer == 1; + }(); - return wantsLayer || layerForSurfaceType; + return wantsLayer; +} + +- (BOOL)shouldUseMetalLayer +{ + // MetalSurface needs a layer, and so does VulkanSurface (via MoltenVK) + QSurface::SurfaceType surfaceType = m_platformWindow->window()->surfaceType(); + return surfaceType == QWindow::MetalSurface || surfaceType == QWindow::VulkanSurface; } - (CALayer *)makeBackingLayer @@ -115,6 +148,14 @@ return [super makeBackingLayer]; } +- (void)setLayer:(CALayer *)layer +{ + qCDebug(lcQpaDrawing) << "Making" << self << "layer-backed with" << layer + << "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested" + : [self shouldUseMetalLayer] ? "needed by surface type" : "enabled by macOS"); + [super setLayer:layer]; +} + - (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy { // We need to set this explicitly since the super implementation -- cgit v1.2.3 From 1b0080a456871a52ac9b11ed8c9685b93bf20723 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 30 Oct 2018 13:07:34 +0100 Subject: Fix no-opengl developer builds Change-Id: I0c8fb7d0aa9a0d95a13447315bd8c1104089fed1 Reviewed-by: Friedemann Kleint Reviewed-by: Andy Nichols Reviewed-by: Laszlo Agocs --- src/plugins/platforms/eglfs/api/qeglfsintegration.cpp | 1 + src/plugins/platforms/eglfs/api/qeglfsscreen.cpp | 10 +++++++++- src/plugins/platforms/minimalegl/qminimaleglintegration.cpp | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp index 43f2e31a49..72420199e3 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp @@ -198,6 +198,7 @@ QPlatformBackingStore *QEglFSIntegration::createPlatformBackingStore(QWindow *wi static_cast(window->handle())->setBackingStore(bs); return bs; #else + Q_UNUSED(window); return nullptr; #endif } diff --git a/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp index d5c22b3d37..285dbd93d3 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp @@ -183,6 +183,8 @@ void QEglFSScreen::handleCursorMove(const QPoint &pos) if (enter && leave) QWindowSystemInterface::handleEnterLeaveEvent(enter, leave, enter->mapFromGlobal(pos), pos); +#else + Q_UNUSED(pos); #endif } @@ -231,7 +233,13 @@ QPixmap QEglFSScreen::grabWindow(WId wid, int x, int y, int width, int height) c return QPixmap::fromImage(img).copy(rect); } } -#endif // QT_NO_OPENGL +#else // QT_NO_OPENGL + Q_UNUSED(wid); + Q_UNUSED(x); + Q_UNUSED(y); + Q_UNUSED(width); + Q_UNUSED(height); +#endif return QPixmap(); } diff --git a/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp b/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp index 5d31af53d5..da58441d67 100644 --- a/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp +++ b/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp @@ -132,6 +132,7 @@ QPlatformBackingStore *QMinimalEglIntegration::createPlatformBackingStore(QWindo #ifndef QT_NO_OPENGL return new QMinimalEglBackingStore(window); #else + Q_UNUSED(window); return nullptr; #endif } -- cgit v1.2.3 From 59a09022f3a6b773f73c21054b7a6c52434a8939 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 6 Nov 2018 09:54:45 +0100 Subject: Windows QPA: Extend the debug operator for IShellItem Output URL string and file system name, too. Task-number: QTBUG-67932 Change-Id: Ic5d1927d70d98f7c081bee06af85b9f3a2a09812 Reviewed-by: Andre de la Rocha --- src/plugins/platforms/windows/qwindowsdialoghelpers.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 681b35eb7c..b629cc00a3 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -558,6 +558,10 @@ public: SFGAOF attributes() const { return m_attributes; } QString normalDisplay() const // base name, usually { return displayName(m_item, SIGDN_NORMALDISPLAY); } + QString urlString() const + { return displayName(m_item, SIGDN_URL); } + QString fileSysPath() const + { return displayName(m_item, SIGDN_FILESYSPATH); } QString desktopAbsoluteParsing() const { return displayName(m_item, SIGDN_DESKTOPABSOLUTEPARSING); } QString path() const; // Only set for 'FileSystem' (SFGAO_FILESYSTEM) items @@ -734,7 +738,8 @@ void QWindowsShellItem::format(QDebug &d) const if (canCopy()) d << " [copyable]"; d << ", normalDisplay=\"" << normalDisplay() - << "\", desktopAbsoluteParsing=\"" << desktopAbsoluteParsing() << '"'; + << "\", desktopAbsoluteParsing=\"" << desktopAbsoluteParsing() + << "\", urlString=\"" << urlString() << "\", fileSysPath=\"" << fileSysPath() << '"'; const QString pathS = path(); if (!pathS.isEmpty()) d << ", path=\"" << pathS << '"'; -- cgit v1.2.3 From ae5f440c3393f086a27241b69c4f9dddaf91ce73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Tue, 25 Sep 2018 12:25:10 +0200 Subject: macOS: set dpr on pixmap returned by grabWindow() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This matches the behavior of QScreen::grabWindow(), and gives the caller direct access to the scale factor. Change-Id: Ia3ed165a62eaa0f386f8b508ea6b1128ba6be604 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoascreen.mm | 1 + 1 file changed, 1 insertion(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm index f82ef202b1..5b6b2c13be 100644 --- a/src/plugins/platforms/cocoa/qcocoascreen.mm +++ b/src/plugins/platforms/cocoa/qcocoascreen.mm @@ -466,6 +466,7 @@ QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height const qreal dpr = devicePixelRatio(); QPixmap windowPixmap(windowSize * dpr); + windowPixmap.setDevicePixelRatio(dpr); windowPixmap.fill(Qt::transparent); for (uint i = 0; i < displayCount; ++i) { -- cgit v1.2.3 From 98c789eb0fb36493254d60cddce4a1eaa6a1665b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Tue, 25 Sep 2018 12:54:09 +0200 Subject: macOS: Make QScreen::grabWindow() work again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 17b73b0d2b8 introduced a regression where the grab rect position was added to the size when bounding to the display size. This is incorrect. Change-Id: I11d7ba7f53b96badfdead190ef9ddb525ed4ba99 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoascreen.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm index 5b6b2c13be..0d6567070e 100644 --- a/src/plugins/platforms/cocoa/qcocoascreen.mm +++ b/src/plugins/platforms/cocoa/qcocoascreen.mm @@ -474,8 +474,8 @@ QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height // Calculate the position and size of the requested area QPoint pos(qAbs(bounds.origin.x - x), qAbs(bounds.origin.y - y)); - QSize size(qMin(pos.x() + width, qRound(bounds.size.width)), - qMin(pos.y() + height, qRound(bounds.size.height))); + QSize size(qMin(width, qRound(bounds.size.width)), + qMin(height, qRound(bounds.size.height))); pos *= dpr; size *= dpr; -- cgit v1.2.3 From 508b9b49b9d178db959d2e2066b8d4b9f5173573 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Fri, 2 Nov 2018 11:48:55 +0100 Subject: Fix image grab when XCB is rgb-swapping The rgbSwap produces an image that fits the X-server, but not one that fits our internal image definitions, so instead return our internal image. Task-number: QTBUG-56806 Change-Id: I25aedf7279bcd86792213b11dbd07a77b49538de Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbbackingstore.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index c8c806749f..ba9a3e68ee 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -837,6 +837,9 @@ void QXcbBackingStore::endPaint() QImage QXcbBackingStore::toImage() const { + // If the backingstore is rgbSwapped, return the internal image type here. + if (!m_rgbImage.isNull()) + return m_rgbImage; return m_image && m_image->image() ? *m_image->image() : QImage(); } -- cgit v1.2.3 From 6857cd60dd884a763af26e43863187e9157fe32c Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Tue, 6 Nov 2018 11:03:42 +0100 Subject: win32: Fix text prediction with on screen keyboard When the on-screen keyboard completes a word via text prediction, the message contains VK_PACKET as identifier for a character sequence. While each character is send, the code only contains the first character of the sequence. Hence, resolve the actual code manually in case of a sequence. This does not modify the virtual key, so that users are able to distinguish between manual and predictive input. Fixes: QTBUG-71210 Change-Id: I787f1f2d83acaf124dfbbab6c4614a1bfe7bb2eb Reviewed-by: Andre de la Rocha Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowskeymapper.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index 9e6101b758..96abfdb9d7 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -1263,6 +1263,13 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg, } #endif // !QT_NO_SHORTCUT key_recorder.storeKey(int(msg.wParam), a, state, text); + + // QTBUG-71210 + // VK_PACKET specifies multiple characters. The system only sends the first + // character of this sequence for each. + if (msg.wParam == VK_PACKET) + code = asciiToKeycode(char(uch.cell()), state); + QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyPress, code, modifiers, scancode, quint32(msg.wParam), nModifiers, text, false); result =true; -- cgit v1.2.3 From 49bbc9df99e1927b6e377054add05599587f88d3 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Fri, 9 Nov 2018 14:23:23 +0100 Subject: QMacStyle: remove weird frame translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Numbers look completely out of thin air, and while I trust it was not an error back then it was introduced, today we end up with QComboBox vertically translated and thus misaligned. Task-number: QTBUG-69908 Change-Id: I784e06f00e4c92c4af67e9bd885b86648183f2e0 Reviewed-by: Morten Johan Sørvig --- src/plugins/styles/mac/qmacstyle_mac.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 0204bd6104..1fd3420899 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -1512,7 +1512,7 @@ QRectF QMacStylePrivate::CocoaControl::adjustedControlFrame(const QRectF &rect) frameRect = frameRect.translated(rect.topLeft()); if (type == QMacStylePrivate::Button_PullDown || type == QMacStylePrivate::Button_PopupButton) { if (size == QStyleHelper::SizeLarge) - frameRect = frameRect.adjusted(0, 0, -6, 0).translated(3, -1); + frameRect = frameRect.adjusted(0, 0, -6, 0).translated(3, 0); else if (size == QStyleHelper::SizeSmall) frameRect = frameRect.adjusted(0, 0, -4, 0).translated(2, 1); else if (size == QStyleHelper::SizeMini) -- cgit v1.2.3 From 15b1c3fd9b82c8a29148c73be7aa4e8b2e07add1 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Fri, 9 Nov 2018 15:44:02 +0100 Subject: Purge some unused code for the OpenGL library name We had a global static, a setter for it (that's nowhere used within Qt code) and a getter for it whose only use was commented out. Neither was declared in any header; the getter's commented-out client had a local extern declaration at the point of (non-)use. Found while reviewing a change to the next few lines of code after the commented-out use of the getter. Change-Id: I393d56219cb7dd7cf836ca80e1bdd605a2914003 Reviewed-by: Laszlo Agocs Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp index 741885e321..93cd3e215f 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -648,8 +648,6 @@ QFunctionPointer QGLXContext::getProcAddress(const char *procName) #endif { #if QT_CONFIG(library) - extern const QString qt_gl_library_name(); -// QLibrary lib(qt_gl_library_name()); QLibrary lib(QLatin1String("GL")); if (!lib.load()) lib.setFileNameAndVersion(QLatin1String("GL"), 1); -- cgit v1.2.3 From ee3c66ca917b77f759acea7c6b27d15066f0b814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 12 Nov 2018 15:29:33 +0100 Subject: macOS: Disable threaded GL rendering on SDK 10.14+ AppKit expects rendering to happen on the main thread, or at least any interaction with AppKit UI classes such as NSView. Our OpenGL helpers, such as QOpenGLContext, do not enforce this, and we may end up calling into AppKit UI classes on the render thread, deadlocking the application. Until this can be investigated and new APIs possibly introduced that allow a more fine grained control in our own classes, we disable threaded GL as a capability of the platform, which will inform clients such as QtQuick to use the basic render loop. [ChangeLog][macOS] Threaded OpenGL usage has been disabled when building using Xcode 10/SDK 10.14 and later. Qt Quick defaults to the 'basic' render loop now on macOS. Task-number: QTBUG-71731 Change-Id: I6fc3295e833ecd48ad49382b8275c762fa7978a6 Reviewed-by: Laszlo Agocs Reviewed-by: Allan Sandfeld Jensen Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/plugins/platforms/cocoa/qcocoaintegration.mm | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 936fecf8de..1bd1029863 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -340,12 +340,17 @@ QCocoaScreen *QCocoaIntegration::screenForNSScreen(NSScreen *nsScreen) bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) const { switch (cap) { - case ThreadedPixmaps: #ifndef QT_NO_OPENGL - case OpenGL: case ThreadedOpenGL: + // AppKit expects rendering to happen on the main thread, and we can + // easily end up in situations where rendering on secondary threads + // will result in visual artifacts, bugs, or even deadlocks, when + // building with SDK 10.14 or higher which enbles view layer-backing. + return QMacVersion::buildSDK() < QOperatingSystemVersion(QOperatingSystemVersion::MacOSMojave); + case OpenGL: case BufferQueueingOpenGL: #endif + case ThreadedPixmaps: case WindowMasks: case MultipleWindows: case ForeignWindows: -- cgit v1.2.3 From d9200fcac58a9347decd417c217c18b7e34471ec Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Tue, 13 Nov 2018 20:22:20 +0100 Subject: Windows QPA: Fix broken focus for native child windows This issue was caused by missing logic in the implementation of the pointer message handler, necessary to support "click to focus" for native child windows. Fixes: QTBUG-71352 Change-Id: I2e261caa8dfab096647799ec1e7d781bec40654e Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowspointerhandler.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 4d3e2f71ec..3c7372958f 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -467,6 +467,11 @@ bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND h keyModifiers, Qt::MouseEventNotSynthesized); return false; // To allow window dragging, etc. } else { + if (eventType == QEvent::MouseButtonPress) { + // Implement "Click to focus" for native child windows (unless it is a native widget window). + if (!window->isTopLevel() && !window->inherits("QWidgetWindow") && QGuiApplication::focusWindow() != window) + window->requestActivate(); + } if (currentWindowUnderPointer != m_windowUnderPointer) { if (m_windowUnderPointer && m_windowUnderPointer == m_currentWindow) { QWindowSystemInterface::handleLeaveEvent(m_windowUnderPointer); -- cgit v1.2.3 From ad2c7f588321f8c671cb9419f90a1e24887ed562 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Wed, 14 Nov 2018 18:10:25 +0100 Subject: Windows QPA: Fix input context visibility status QWindowsInputContext::isInputPanelVisible() was ignoring the visibility status of the IME, only returning the status of the Win10 virtual keyboard. This issue caused qtwebengine to try to show the IME multiple times, breaking Asian languages input. Task-number: QTBUG-71753 Change-Id: Iaa4cef37b7dc98a9e0a787750a34d2e98a87a777 Reviewed-by: Allan Sandfeld Jensen Reviewed-by: Alexandru Croitor Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowsinputcontext.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index 30da0da1de..d1e99c037b 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -242,7 +242,18 @@ QRectF QWindowsInputContext::keyboardRect() const bool QWindowsInputContext::isInputPanelVisible() const { HWND hwnd = getVirtualKeyboardWindowHandle(); - return hwnd && ::IsWindowEnabled(hwnd) && ::IsWindowVisible(hwnd); + if (hwnd && ::IsWindowEnabled(hwnd) && ::IsWindowVisible(hwnd)) + return true; + // check if the Input Method Editor is open + if (inputMethodAccepted()) { + if (QWindow *window = QGuiApplication::focusWindow()) { + if (QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(window)) { + if (HIMC himc = ImmGetContext(platformWindow->handle())) + return ImmGetOpenStatus(himc); + } + } + } + return false; } void QWindowsInputContext::showInputPanel() -- cgit v1.2.3 From a94a3098d0cc82a850d2d0c62baad6edef72e142 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Wed, 14 Nov 2018 12:49:00 +0100 Subject: Windows QPA: Fix building with -no-feature-tabletevent This change fixes building Qt with the -no-feature-tabletevent configure option by disabling handling of pointer messages associated with tablet events within the pointer message handler. Fixes: QTBUG-71774 Change-Id: Icb47a39793edb9a0f87c07c656b6ea6573d5f947 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowspointerhandler.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 2b6c696979..d88049019b 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -609,6 +609,7 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPenInfo) { +#if QT_CONFIG(tabletevent) if (et & QtWindows::NonClientEventFlag) return false; // Let DefWindowProc() handle Non Client messages. @@ -703,6 +704,14 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin } } return true; +#else + Q_UNUSED(window); + Q_UNUSED(hwnd); + Q_UNUSED(et); + Q_UNUSED(msg); + Q_UNUSED(vPenInfo); + return false; +#endif } // Process old-style mouse messages here. -- cgit v1.2.3 From 8e8c11f4f3d5ccb8b1a9042d363e4d1639797df3 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Thu, 15 Nov 2018 17:19:23 +0100 Subject: Windows QPA: Fix onPressedChanged only reported on touch up This issue was caused by the workaround added to fix QTBUG-70887. Certain events like the initial touch down do not generate mouse messages after the pointer messages (but only touch messages) and should not be postponed by the pointer handler. Fixes: QTBUG-71775 Change-Id: I7b64ae4d422f6a4c1bb465ce5f8255e85640dab1 Reviewed-by: Friedemann Kleint Reviewed-by: Oliver Wolff --- src/plugins/platforms/windows/qwindowspointerhandler.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 3c7372958f..b3bc6e6d7b 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -564,6 +564,7 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, QList touchPoints; bool primaryPointer = false; + bool pressRelease = false; if (QWindowsContext::verbose > 1) qCDebug(lcQpaEvents).noquote().nospace() << showbase @@ -600,9 +601,11 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_DOWN) { touchPoint.state = Qt::TouchPointPressed; m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition); + pressRelease = true; } else if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_UP) { touchPoint.state = Qt::TouchPointReleased; m_lastTouchPositions.remove(touchPoint.id); + pressRelease = true; } else { touchPoint.state = stationaryTouchPoint ? Qt::TouchPointStationary : Qt::TouchPointMoved; m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition); @@ -615,7 +618,7 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, // Avoid getting repeated messages for this frame if there are multiple pointerIds QWindowsContext::user32dll.skipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId); } - if (primaryPointer) { + if (primaryPointer && !pressRelease) { // Postpone event delivery to avoid hanging inside DoDragDrop(). // Only the primary pointer will generate mouse messages. enqueueTouchEvent(window, touchPoints, QWindowsKeyMapper::queryKeyboardModifiers()); -- cgit v1.2.3 From 6c1656397a2d0c30810cdbd880eda9e9c43fbe67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 15 Nov 2018 13:45:46 +0100 Subject: macOS: Ensure NSWindow delegate is released in sync with its NSWindow Releasing it in [QNSWindow closeAndRelease] is wrong, as we only call that method from a few call sites, and can easily end up with a normal dealloc by means of e.g. the [m_nsWindow release] in ~QCocoaWindow. This still leaves Xcode thinking we have a single leaking delegate per active NSWindow, as it apparently doesn't realize we're calling release manually. This needs to be investigated further. Task-number: QTBUG-65693 Change-Id: I9105602274d8532465e5108aba2b05bf253268e9 Reviewed-by: Andy Shaw Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qnswindow.mm | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm index 1b9dd95cbc..b3cd3c1d8c 100644 --- a/src/plugins/platforms/cocoa/qnswindow.mm +++ b/src/plugins/platforms/cocoa/qnswindow.mm @@ -239,10 +239,6 @@ static bool isMouseEvent(NSEvent *ev) - (void)closeAndRelease { qCDebug(lcQpaWindow) << "closeAndRelease" << self; - - [self.delegate release]; - self.delegate = nil; - [self close]; [self release]; } @@ -252,6 +248,9 @@ static bool isMouseEvent(NSEvent *ev) - (void)dealloc { qCDebug(lcQpaWindow) << "dealloc" << self; + [self.delegate release]; + self.delegate = nil; + qt_objcDynamicSuper(); } #pragma clang diagnostic pop -- cgit v1.2.3 From 12045801f742dd956f17d1a6c72b21f8f245a671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 15 Nov 2018 14:21:56 +0100 Subject: macOS: Use shared NSWindowDelegate instead of one per window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All the delegate callbacks give us the relevant NSWindow, so we don't need one delegate per window just to be able to resolve the correct platform window. Change-Id: I8e44186da63bf01f029bb0b1fefcd8880f49dda6 Fixes: QTBUG-65693 Reviewed-by: Morten Johan Sørvig Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qcocoawindow.mm | 4 ++- src/plugins/platforms/cocoa/qnswindow.mm | 1 - src/plugins/platforms/cocoa/qnswindowdelegate.h | 3 -- src/plugins/platforms/cocoa/qnswindowdelegate.mm | 44 +++++++++++++----------- 4 files changed, 27 insertions(+), 25 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 1ce671941d..4dc3ea4bd6 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1548,7 +1548,9 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel) QWindowSystemInterface::SynchronousDelivery>(window(), targetScreen); } - nsWindow.delegate = [[QNSWindowDelegate alloc] initWithQCocoaWindow:this]; + static QSharedPointer sharedDelegate([[QNSWindowDelegate alloc] init], + [](QNSWindowDelegate *delegate) { [delegate release]; }); + nsWindow.delegate = sharedDelegate.get(); // Prevent Cocoa from releasing the window on close. Qt // handles the close event asynchronously and we want to diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm index b3cd3c1d8c..dd6ee3058a 100644 --- a/src/plugins/platforms/cocoa/qnswindow.mm +++ b/src/plugins/platforms/cocoa/qnswindow.mm @@ -248,7 +248,6 @@ static bool isMouseEvent(NSEvent *ev) - (void)dealloc { qCDebug(lcQpaWindow) << "dealloc" << self; - [self.delegate release]; self.delegate = nil; qt_objcDynamicSuper(); diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.h b/src/plugins/platforms/cocoa/qnswindowdelegate.h index e71afcbb2a..be870deb3a 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.h +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.h @@ -48,9 +48,6 @@ class QCocoaWindow; QT_END_NAMESPACE @interface QT_MANGLE_NAMESPACE(QNSWindowDelegate) : NSObject - -- (instancetype)initWithQCocoaWindow:(QT_PREPEND_NAMESPACE(QCocoaWindow) *)cocoaWindow; - @end QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSWindowDelegate); diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index 97309ea990..14f1ca0114 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm @@ -49,23 +49,17 @@ static QRegExp whitespaceRegex = QRegExp(QStringLiteral("\\s*")); -@implementation QNSWindowDelegate { - QCocoaWindow *m_cocoaWindow; -} - -- (instancetype)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow +static QCocoaWindow *toPlatformWindow(NSWindow *window) { - if ((self = [self init])) - m_cocoaWindow = cocoaWindow; - return self; + return qnsview_cast(window.contentView).platformWindow; } -- (BOOL)windowShouldClose:(NSNotification *)notification +@implementation QNSWindowDelegate + +- (BOOL)windowShouldClose:(NSWindow *)window { - Q_UNUSED(notification); - if (m_cocoaWindow) { - return m_cocoaWindow->windowShouldClose(); - } + if (QCocoaWindow *platformWindow = toPlatformWindow(window)) + return platformWindow->windowShouldClose(); return YES; } @@ -79,14 +73,16 @@ static QRegExp whitespaceRegex = QRegExp(QStringLiteral("\\s*")); - (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)proposedFrame { Q_UNUSED(proposedFrame); - Q_ASSERT(window == m_cocoaWindow->nativeWindow()); - const QWindow *w = m_cocoaWindow->window(); + + QCocoaWindow *platformWindow = toPlatformWindow(window); + Q_ASSERT(platformWindow); + const QWindow *w = platformWindow->window(); // maximumSize() refers to the client size, but AppKit expects the full frame size QSizeF maximumSize = w->maximumSize() + QSize(0, w->frameMargins().top()); // The window should never be larger than the current screen geometry - const QRectF screenGeometry = m_cocoaWindow->screen()->geometry(); + const QRectF screenGeometry = platformWindow->screen()->geometry(); maximumSize = maximumSize.boundedTo(screenGeometry.size()); // Use the current frame position for the initial maximized frame, @@ -113,6 +109,8 @@ static QRegExp whitespaceRegex = QRegExp(QStringLiteral("\\s*")); #pragma clang diagnostic ignored "-Wdeprecated-declarations" - (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)frameSize { + Q_ASSERT(toPlatformWindow(window)); + qCDebug(lcQpaWindow) << window << "will resize to" << QSizeF::fromCGSize(frameSize) << "- disabling screen updates temporarily"; @@ -131,6 +129,8 @@ static QRegExp whitespaceRegex = QRegExp(QStringLiteral("\\s*")); - (void)windowDidResize:(NSNotification *)notification { NSWindow *window = notification.object; + Q_ASSERT(toPlatformWindow(window)); + qCDebug(lcQpaWindow) << window << "was resized - re-enabling screen updates"; NSEnableScreenUpdates(); } @@ -138,23 +138,27 @@ static QRegExp whitespaceRegex = QRegExp(QStringLiteral("\\s*")); - (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu { - Q_UNUSED(window); Q_UNUSED(menu); + QCocoaWindow *platformWindow = toPlatformWindow(window); + Q_ASSERT(platformWindow); + // Only pop up document path if the filename is non-empty. We allow whitespace, to // allow faking a window icon by setting the file path to a single space character. - return !whitespaceRegex.exactMatch(m_cocoaWindow->window()->filePath()); + return !whitespaceRegex.exactMatch(platformWindow->window()->filePath()); } - (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard { - Q_UNUSED(window); Q_UNUSED(event); Q_UNUSED(dragImageLocation); Q_UNUSED(pasteboard); + QCocoaWindow *platformWindow = toPlatformWindow(window); + Q_ASSERT(platformWindow); + // Only allow drag if the filename is non-empty. We allow whitespace, to // allow faking a window icon by setting the file path to a single space. - return !whitespaceRegex.exactMatch(m_cocoaWindow->window()->filePath()); + return !whitespaceRegex.exactMatch(platformWindow->window()->filePath()); } @end -- cgit v1.2.3 From 9c560eb8b5ca2768ffa3a6e1b208e3e6b55470d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 16 Nov 2018 19:34:36 +0100 Subject: macOS: Improve logging during QNSView/QNSWindow deallocation Change-Id: Ie6945f2a1f35db6d1259b77ee63137abcaf68318 Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qnsview.mm | 2 ++ src/plugins/platforms/cocoa/qnswindow.mm | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 540f701d43..03c5001270 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -166,6 +166,8 @@ - (void)dealloc { + qCDebug(lcQpaWindow) << "Deallocating" << self; + if (m_trackingArea) { [self removeTrackingArea:m_trackingArea]; [m_trackingArea release]; diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm index dd6ee3058a..c17ad47aba 100644 --- a/src/plugins/platforms/cocoa/qnswindow.mm +++ b/src/plugins/platforms/cocoa/qnswindow.mm @@ -238,7 +238,7 @@ static bool isMouseEvent(NSEvent *ev) - (void)closeAndRelease { - qCDebug(lcQpaWindow) << "closeAndRelease" << self; + qCDebug(lcQpaWindow) << "Closing and releasing" << self; [self close]; [self release]; } @@ -247,7 +247,7 @@ static bool isMouseEvent(NSEvent *ev) #pragma clang diagnostic ignored "-Wobjc-missing-super-calls" - (void)dealloc { - qCDebug(lcQpaWindow) << "dealloc" << self; + qCDebug(lcQpaWindow) << "Deallocating" << self; self.delegate = nil; qt_objcDynamicSuper(); -- cgit v1.2.3 From d5b3ddffae0a878618bb2637539054dc2e397706 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Fri, 9 Nov 2018 15:54:42 +0100 Subject: QMacStyle: account for QStyleSheetStyle using QTabBar directly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit in this case w->parentWidget() is not QTabBar, but QTabWidget and we never draw PE_IndicatorTabClose control (before the recent major re-write in qmacstyle we never tested the actual type). Task-number: QTBUG-61092 Change-Id: I87c4813258cc2b483b2ef278c4a2f8796973af1c Reviewed-by: Tor Arne Vestbø Reviewed-by: Morten Johan Sørvig --- src/plugins/styles/mac/qmacstyle_mac.mm | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 1fd3420899..b84448d5e2 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -3229,7 +3229,13 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai break; case PE_IndicatorTabClose: { // Make close button visible only on the hovered tab. - if (QTabBar *tabBar = qobject_cast(w->parentWidget())) { + QTabBar *tabBar = qobject_cast(w->parentWidget()); + if (!tabBar) { + // QStyleSheetStyle instead of CloseButton (which has + // a QTabBar as a parent widget) uses the QTabBar itself: + tabBar = qobject_cast(const_cast(w)); + } + if (tabBar) { const bool documentMode = tabBar->documentMode(); const QTabBarPrivate *tabBarPrivate = static_cast(QObjectPrivate::get(tabBar)); const int hoveredTabIndex = tabBarPrivate->hoveredTabIndex(); -- cgit v1.2.3 From 54dabdd1e831491359e85fae444ab3ec700a0d2b Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 29 Oct 2018 17:04:38 +0100 Subject: wasm: fix qpa plugin build system integration fix the plugin name (it was missing the leading 'q') and the name used in configure (the latter making it unnecessary to mess with it in the mkspec). the qt.prf override which forced linkage of the plugin is also removed due to being completely redundant. Change-Id: I94687a34a295c36754e36a298af902b656ba2ecc Reviewed-by: Kyle Edwards Reviewed-by: Lorn Potter --- src/plugins/platforms/wasm/wasm.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/wasm/wasm.pro b/src/plugins/platforms/wasm/wasm.pro index f1205702ef..eaaba53aa2 100644 --- a/src/plugins/platforms/wasm/wasm.pro +++ b/src/plugins/platforms/wasm/wasm.pro @@ -1,4 +1,4 @@ -TARGET = wasm +TARGET = qwasm CONFIG += static plugin QT += \ core-private gui-private \ -- cgit v1.2.3 From e71b640f3cde7e748f962240489888325accbfeb Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Wed, 21 Nov 2018 15:19:50 +0100 Subject: Fix crash when painting with pattern brush to print device on macOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CGContextRelease was called twice, both manual and from the destructor of QMacCGContext. Change-Id: Icba7dcda37af7e1f7c72937b3dd2d2cc4ea22c63 Fixes: QTBUG-71934 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qpaintengine_mac.mm | 1 - 1 file changed, 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm index ce7f92f2c7..5c880b1cad 100644 --- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm @@ -313,7 +313,6 @@ static void qt_mac_draw_pattern(void *info, CGContextRef c) } pat->image = qt_mac_create_imagemask(pm, pm.rect()); CGImageRelease(swatch); - CGContextRelease(pm_ctx); w *= QMACPATTERN_MASK_MULTIPLIER; h *= QMACPATTERN_MASK_MULTIPLIER; #endif -- cgit v1.2.3 From 755521aba6d63fc572b5b3ee43193ea24a2d5513 Mon Sep 17 00:00:00 2001 From: Andrew Smolko Date: Thu, 8 Nov 2018 18:18:55 +0300 Subject: Fix hang in QMacPasteboard::formats() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PasteboardGetItemCount() can return -1 as result to unsigned variable, so the further loop will iterate "forever". Return early to avoid hang. Change-Id: Ie91dba1c193d04513f0496d20bd0b6b0b5b6c151 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qmacclipboard.mm | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qmacclipboard.mm b/src/plugins/platforms/cocoa/qmacclipboard.mm index f3467fdc73..3a39e32fb5 100644 --- a/src/plugins/platforms/cocoa/qmacclipboard.mm +++ b/src/plugins/platforms/cocoa/qmacclipboard.mm @@ -49,6 +49,7 @@ #include #include #include "qcocoahelpers.h" +#include QT_BEGIN_NAMESPACE @@ -61,6 +62,23 @@ QT_BEGIN_NAMESPACE QMacPasteboard code *****************************************************************************/ +namespace +{ +OSStatus PasteboardGetItemCountSafe(PasteboardRef paste, ItemCount *cnt) +{ + Q_ASSERT(paste); + Q_ASSERT(cnt); + const OSStatus result = PasteboardGetItemCount(paste, cnt); + // Despite being declared unsigned, this API can return -1 + if (std::make_signed::type(*cnt) < 0) + *cnt = 0; + return result; +} +} // namespace + +// Ensure we don't call the broken one later on +#define PasteboardGetItemCount + class QMacMimeData : public QMimeData { public: @@ -210,7 +228,7 @@ QMacPasteboard::hasOSType(int c_flavor) const sync(); ItemCount cnt = 0; - if (PasteboardGetItemCount(paste, &cnt) || !cnt) + if (PasteboardGetItemCountSafe(paste, &cnt) || !cnt) return false; #ifdef DEBUG_PASTEBOARD @@ -257,7 +275,7 @@ QMacPasteboard::hasFlavor(QString c_flavor) const sync(); ItemCount cnt = 0; - if (PasteboardGetItemCount(paste, &cnt) || !cnt) + if (PasteboardGetItemCountSafe(paste, &cnt) || !cnt) return false; #ifdef DEBUG_PASTEBOARD @@ -374,7 +392,7 @@ QMacPasteboard::formats() const QStringList ret; ItemCount cnt = 0; - if (PasteboardGetItemCount(paste, &cnt) || !cnt) + if (PasteboardGetItemCountSafe(paste, &cnt) || !cnt) return ret; #ifdef DEBUG_PASTEBOARD @@ -417,7 +435,7 @@ QMacPasteboard::hasFormat(const QString &format) const sync(); ItemCount cnt = 0; - if (PasteboardGetItemCount(paste, &cnt) || !cnt) + if (PasteboardGetItemCountSafe(paste, &cnt) || !cnt) return false; #ifdef DEBUG_PASTEBOARD @@ -460,7 +478,7 @@ QMacPasteboard::retrieveData(const QString &format, QVariant::Type) const sync(); ItemCount cnt = 0; - if (PasteboardGetItemCount(paste, &cnt) || !cnt) + if (PasteboardGetItemCountSafe(paste, &cnt) || !cnt) return QByteArray(); #ifdef DEBUG_PASTEBOARD -- cgit v1.2.3 From 14984bd59affd3d7f14bf8f67b58b7a87957ead6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 21 Nov 2018 15:47:18 +0100 Subject: macOS: Don't assume platform input context is our own A plugin (such as the Qt virtual keyboard) may provide a platform input context. Change-Id: I349ac6c4b96a3536bcde0d44a785cb7bb989fcc6 Fixes: QTBUG-68328 Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qnsview_complextext.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qnsview_complextext.mm b/src/plugins/platforms/cocoa/qnsview_complextext.mm index d357082d33..6ff9b26ca4 100644 --- a/src/plugins/platforms/cocoa/qnsview_complextext.mm +++ b/src/plugins/platforms/cocoa/qnsview_complextext.mm @@ -307,8 +307,8 @@ { Q_UNUSED(textInputContextKeyboardSelectionDidChangeNotification) if (([NSApp keyWindow] == self.window) && self.window.firstResponder == self) { - QCocoaInputContext *ic = qobject_cast(QCocoaIntegration::instance()->inputContext()); - ic->updateLocale(); + if (QCocoaInputContext *ic = qobject_cast(QCocoaIntegration::instance()->inputContext())) + ic->updateLocale(); } } -- cgit v1.2.3 From 4538dd7ec4efcce5760f87dc1751b142b8f35479 Mon Sep 17 00:00:00 2001 From: Michal Klocek Date: Mon, 12 Nov 2018 13:17:40 +0100 Subject: Remove need for glXGetProcAddressARB We do already require glXGetProcAddress in line 241. Fixes: QTBUG-71488 Change-Id: Id0f3bc256a71097241b99d2dcba927c1165e980e Reviewed-by: Gatis Paeglis --- .../gl_integrations/xcb_glx/qglxintegration.cpp | 43 +--------------------- 1 file changed, 1 insertion(+), 42 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp index 2ffb5d2629..ddb8f45188 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -38,9 +38,6 @@ ****************************************************************************/ #include -#if QT_CONFIG(library) -#include -#endif #include "qxcbwindow.h" #include "qxcbscreen.h" @@ -61,10 +58,6 @@ #include "qxcbglintegration.h" -#if !defined(QT_STATIC) && QT_CONFIG(dlopen) -#include -#endif - QT_BEGIN_NAMESPACE typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); @@ -627,41 +620,7 @@ void QGLXContext::swapBuffers(QPlatformSurface *surface) QFunctionPointer QGLXContext::getProcAddress(const char *procName) { -#ifdef QT_STATIC - return glXGetProcAddressARB(reinterpret_cast(procName)); -#else - typedef void *(*qt_glXGetProcAddressARB)(const GLubyte *); - static qt_glXGetProcAddressARB glXGetProcAddressARB = 0; - static bool resolved = false; - - if (resolved && !glXGetProcAddressARB) - return 0; - if (!glXGetProcAddressARB) { - QList glxExt = QByteArray(glXGetClientString(m_display, GLX_EXTENSIONS)).split(' '); - if (glxExt.contains("GLX_ARB_get_proc_address")) { -#if QT_CONFIG(dlopen) - void *handle = dlopen(NULL, RTLD_LAZY); - if (handle) { - glXGetProcAddressARB = (qt_glXGetProcAddressARB) dlsym(handle, "glXGetProcAddressARB"); - dlclose(handle); - } - if (!glXGetProcAddressARB) -#endif - { -#if QT_CONFIG(library) - QLibrary lib(QLatin1String("GL")); - if (!lib.load()) - lib.setFileNameAndVersion(QLatin1String("GL"), 1); - glXGetProcAddressARB = (qt_glXGetProcAddressARB) lib.resolve("glXGetProcAddressARB"); -#endif - } - } - resolved = true; - } - if (!glXGetProcAddressARB) - return 0; - return (void (*)())glXGetProcAddressARB(reinterpret_cast(procName)); -#endif + return glXGetProcAddress(reinterpret_cast(procName)); } QSurfaceFormat QGLXContext::format() const -- cgit v1.2.3 From 5f49788e3348406f1399e4e911a765f850f5788f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 16 Nov 2018 18:37:01 +0100 Subject: macOS: Allow raising and lowering child windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ic598d200e2f774ced489a37c33b7a02767db4402 Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qcocoawindow.mm | 42 +++++++++++++++-------------- 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 4dc3ea4bd6..df1ad82592 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -897,34 +897,36 @@ void QCocoaWindow::raise() qCDebug(lcQpaWindow) << "QCocoaWindow::raise" << window(); // ### handle spaces (see Qt 4 raise_sys in qwidget_mac.mm) - if (!isContentView()) - return; - - if (m_view.window.visible) { - { - // Clean up autoreleased temp objects from orderFront immediately. - // Failure to do so has been observed to cause leaks also beyond any outer - // autorelease pool (for example around a complete QWindow - // construct-show-raise-hide-delete cyle), counter to expected autoreleasepool - // behavior. - QMacAutoReleasePool pool; - [m_view.window orderFront:m_view.window]; - } - static bool raiseProcess = qt_mac_resolveOption(true, "QT_MAC_SET_RAISE_PROCESS"); - if (raiseProcess) { - [NSApp activateIgnoringOtherApps:YES]; + if (isContentView()) { + if (m_view.window.visible) { + { + // Clean up auto-released temp objects from orderFront immediately. + // Failure to do so has been observed to cause leaks also beyond any outer + // autorelease pool (for example around a complete QWindow + // construct-show-raise-hide-delete cycle), counter to expected autoreleasepool + // behavior. + QMacAutoReleasePool pool; + [m_view.window orderFront:m_view.window]; + } + static bool raiseProcess = qt_mac_resolveOption(true, "QT_MAC_SET_RAISE_PROCESS"); + if (raiseProcess) + [NSApp activateIgnoringOtherApps:YES]; } + } else { + [m_view.superview addSubview:m_view positioned:NSWindowAbove relativeTo:nil]; } } void QCocoaWindow::lower() { qCDebug(lcQpaWindow) << "QCocoaWindow::lower" << window(); - if (!isContentView()) - return; - if (m_view.window.visible) - [m_view.window orderBack:m_view.window]; + if (isContentView()) { + if (m_view.window.visible) + [m_view.window orderBack:m_view.window]; + } else { + [m_view.superview addSubview:m_view positioned:NSWindowBelow relativeTo:nil]; + } } bool QCocoaWindow::isExposed() const -- cgit v1.2.3 From 1931aedcf827f837ce81a58a8f8f0e55d8212df6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 16 Nov 2018 18:41:11 +0100 Subject: macOS: Track changes to our NSView's superview and window properties As a start, we just log the changes, but going forward we can use this to report parent changes to QPA or get rid of old QNSWindows. Change-Id: Id3625fb0b7608d85240f58bdecc70a5892075da3 Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qnsview.mm | 73 +++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 6 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 03c5001270..7f826942f3 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -68,6 +68,8 @@ // Private interface @interface QT_MANGLE_NAMESPACE(QNSView) () - (BOOL)isTransparentForUserInput; +@property (assign) NSView* previousSuperview; +@property (assign) NSWindow* previousWindow; @end @interface QT_MANGLE_NAMESPACE(QNSView) (Drawing) @@ -153,6 +155,9 @@ self.focusRingType = NSFocusRingTypeNone; self.cursor = nil; + self.previousSuperview = nil; + self.previousWindow = nil; + [self initDrawing]; [self registerDragTypes]; @@ -195,8 +200,40 @@ return description; } +// ----------------------------- Re-parenting --------------------------------- + +- (void)removeFromSuperview +{ + QMacAutoReleasePool pool; + [super removeFromSuperview]; +} + +- (void)viewWillMoveToSuperview:(NSView *)newSuperview +{ + Q_ASSERT(!self.previousSuperview); + self.previousSuperview = self.superview; + + if (newSuperview == self.superview) + qCDebug(lcQpaWindow) << "Re-ordering" << self << "inside" << self.superview; + else + qCDebug(lcQpaWindow) << "Re-parenting" << self << "from" << self.superview << "to" << newSuperview; +} + - (void)viewDidMoveToSuperview { + auto cleanup = qScopeGuard([&] { self.previousSuperview = nil; }); + + if (self.superview == self.previousSuperview) { + qCDebug(lcQpaWindow) << "Done re-ordering" << self << "new index:" + << [self.superview.subviews indexOfObject:self]; + return; + } + + qCDebug(lcQpaWindow) << "Done re-parenting" << self << "into" << self.superview; + + // Note: at this point the view's window property hasn't been updated to match the window + // of the new superview. We have to wait for viewDidMoveToWindow for that to be reflected. + if (!m_platformWindow) return; @@ -210,6 +247,36 @@ } } +- (void)viewWillMoveToWindow:(NSWindow *)newWindow +{ + Q_ASSERT(!self.previousWindow); + self.previousWindow = self.window; + + // This callback is documented to be called also when a view is just moved between + // subviews in the same NSWindow, so we're not necessarily moving between NSWindows. + if (newWindow == self.window) + return; + + qCDebug(lcQpaWindow) << "Moving" << self << "from" << self.window << "to" << newWindow; + + // Note: at this point the superview has already been updated, so we know which view inside + // the new window the view will be a child of. +} + +- (void)viewDidMoveToWindow +{ + auto cleanup = qScopeGuard([&] { self.previousWindow = nil; }); + + // This callback is documented to be called also when a view is just moved between + // subviews in the same NSWindow, so we're not necessarily moving between NSWindows. + if (self.window == self.previousWindow) + return; + + qCDebug(lcQpaWindow) << "Done moving" << self << "to" << self.window; +} + +// ---------------------------------------------------------------------------- + - (QWindow *)topLevelWindow { if (!m_platformWindow) @@ -239,12 +306,6 @@ // viewDidUnhide so no reason to override it here. } -- (void)removeFromSuperview -{ - QMacAutoReleasePool pool; - [super removeFromSuperview]; -} - - (BOOL)isTransparentForUserInput { return m_platformWindow->window() && -- cgit v1.2.3 From 9f6f796a50bf42290d8abbbb08149bd98b1619a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Boris=20Du=C5=A1ek?= Date: Sat, 3 Nov 2018 12:58:42 +0100 Subject: Fix VoiceOver interaction with multiline text components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `convertLineOffset` requires exactly one of `line` and `offset` parameters to be -1. [ChangeLog][macOS][Accessibility] VoiceOver now reads all lines in multiline text components when navigating by lines. Change-Id: I2872c4f5255a33dd2b493b46b22e672eb5779ee8 Fixes: QTBUG-71563 Reviewed-by: Frederik Gladhorn Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm | 1 + 1 file changed, 1 insertion(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index 03dc895ffb..68cf273f32 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -351,6 +351,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of if (QAccessibleTextInterface *text = iface->textInterface()) { int line = 0; // true for all single line edits if (iface->state().multiLine) { + line = -1; int position = text->cursorPosition(); convertLineOffset(text, &line, &position); } -- cgit v1.2.3 From 9dc19d6716f936e8b93a63fb2d27565e43ccb1ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Boris=20Du=C5=A1ek?= Date: Sat, 3 Nov 2018 13:59:22 +0100 Subject: qcocoaaccessibilityelement.mm: Document convertLineOffset function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I359768a7cbd4c3e1e11a453a32bb28add891cf20 Reviewed-by: Frederik Gladhorn Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index 68cf273f32..63233a0390 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -51,6 +51,19 @@ QT_USE_NAMESPACE #ifndef QT_NO_ACCESSIBILITY +/** + * Converts between absolute character offsets and line numbers of a + * QAccessibleTextInterface. Works in exactly one of two modes: + * + * - Pass *line == -1 in order to get a line containing character at the given + * *offset + * - Pass *offset == -1 in order to get the offset of first character of the + * given *line + * + * You can optionally also pass non-NULL `start` and `end`, which will in both + * modes be filled with the offset of the first and last characters of the + * relevant line. + */ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *offset, NSUInteger *start = 0, NSUInteger *end = 0) { Q_ASSERT(*line == -1 || *offset == -1); -- cgit v1.2.3 From 6be4a67322403b44a39650f0dd3e6daf7eafe5c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Boris=20Du=C5=A1ek?= Date: Sat, 3 Nov 2018 14:30:35 +0100 Subject: Align implementation of LineForIndex with InsertionPointLineNumber MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On macOS, the accessibility implementation of InsertionPointLineNumber currently reflects a fix for issue (QTBUG-49437). While it seems from testing this issue no longer requires such a fix, it still is a nice optimization for single-line edits. So we hereby bring the same optimization to LineForIndex parameterized attribute as well, and makes the code for both attributes consistent. Change-Id: I18b8cc249b6c65a25150f4e503999b04437e0306 Reviewed-by: Frederik Gladhorn Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index 63233a0390..b826e821fc 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -424,8 +424,11 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of int index = [parameter intValue]; if (index < 0 || index > iface->textInterface()->characterCount()) return nil; - int line = -1; - convertLineOffset(iface->textInterface(), &line, &index); + int line = 0; // true for all single line edits + if (iface->state().multiLine) { + line = -1; + convertLineOffset(iface->textInterface(), &line, &index); + } return @(line); } if ([attribute isEqualToString: NSAccessibilityRangeForLineParameterizedAttribute]) { -- cgit v1.2.3 From 18b1dc35e90a6a3946e9e88c8cfa1ced3a00b1fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Boris=20Du=C5=A1ek?= Date: Mon, 5 Nov 2018 10:22:12 +0100 Subject: macOS a11y: Implement AXInsertionPointLineNumber with AXLineForIndex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow DRY and do not repeat implementation of basically the same thing, especially now that the implementation is no longer completely trivial. AXLineForIndex can be considered a primitive attribute, and AXInsertionPointLineNumber a derived attribute, hence this opportunity to not repeat oneself. Change-Id: I64b596d8351e681f4438b91400a767407612c118 Reviewed-by: Frederik Gladhorn Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index b826e821fc..1a3c7793c0 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -362,13 +362,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of } else if ([attribute isEqualToString:NSAccessibilityInsertionPointLineNumberAttribute]) { if (QAccessibleTextInterface *text = iface->textInterface()) { - int line = 0; // true for all single line edits - if (iface->state().multiLine) { - line = -1; - int position = text->cursorPosition(); - convertLineOffset(text, &line, &position); - } - return @(line); + int position = text->cursorPosition(); + return [self accessibilityAttributeValue:NSAccessibilityLineForIndexParameterizedAttribute forParameter:@(position)]; } return nil; } else if ([attribute isEqualToString:NSAccessibilityMinValueAttribute]) { -- cgit v1.2.3 From bc1678c618342774be285f24c1e2995c0a0e1600 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Thu, 22 Nov 2018 13:22:34 +0100 Subject: macOS accessibility: fix crash for NSAccessibilityVisibleCharacterRangeAttribute MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VoiceOver or other tools may query this property even when there is no text interface. Make sure not to crash by verifying that the interface is supported. Found while using AccessibilityInspector to verify other changes. Change-Id: If7ee21b7616f091b71e86bab03a871ddbabe9200 Reviewed-by: Jan Arve Sæther --- src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index 03dc895ffb..a1176da33f 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -345,8 +345,9 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of return [NSValue valueWithRange: NSMakeRange(0, 0)]; } else if ([attribute isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) { // FIXME This is not correct and may impact performance for big texts - return [NSValue valueWithRange: NSMakeRange(0, iface->textInterface()->characterCount())]; - + if (QAccessibleTextInterface *text = iface->textInterface()) + return [NSValue valueWithRange: NSMakeRange(0, text->characterCount())]; + return [NSValue valueWithRange: NSMakeRange(0, iface->text(QAccessible::Name).length())]; } else if ([attribute isEqualToString:NSAccessibilityInsertionPointLineNumberAttribute]) { if (QAccessibleTextInterface *text = iface->textInterface()) { int line = 0; // true for all single line edits -- cgit v1.2.3 From 7264bf19dbc47b805bb7af5df584ce1aae081962 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 21 Nov 2018 09:06:50 +0100 Subject: Windows: Add a default setting for hasBorderInFullScreen The hasBorderInFullScreen only has an effect when set before the window is shown or switched to fullscreen. This is currently not possible in the QML case since the window is only accessible after all properties (including visibility) have been set. Add a function to set a default value. [ChangeLog][QtPlatformHeaders][QWindowsWindowFunctions] Add a default setting for hasBorderInFullScreen Task-number: QTBUG-47247 Task-number: QTBUG-71855 Change-Id: I3952e3f34bc4eb134cf1c5265b4489fc74112688 Reviewed-by: Andre de la Rocha Reviewed-by: Andy Shaw --- src/plugins/platforms/windows/qwindowsnativeinterface.cpp | 2 ++ src/plugins/platforms/windows/qwindowswindow.cpp | 8 +++++++- src/plugins/platforms/windows/qwindowswindow.h | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp index de11356fd4..a1ff6f1141 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -277,6 +277,8 @@ QFunctionPointer QWindowsNativeInterface::platformFunction(const QByteArray &fun return QFunctionPointer(QWindowsWindow::setTouchWindowTouchTypeStatic); if (function == QWindowsWindowFunctions::setHasBorderInFullScreenIdentifier()) return QFunctionPointer(QWindowsWindow::setHasBorderInFullScreenStatic); + if (function == QWindowsWindowFunctions::setHasBorderInFullScreenDefaultIdentifier()) + return QFunctionPointer(QWindowsWindow::setHasBorderInFullScreenDefault); if (function == QWindowsWindowFunctions::setWindowActivationBehaviorIdentifier()) return QFunctionPointer(QWindowsNativeInterface::setWindowActivationBehavior); if (function == QWindowsWindowFunctions::isTabletModeIdentifier()) diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index f340f16679..6201da7b72 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1190,6 +1190,7 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w, const char *QWindowsWindow::embeddedNativeParentHandleProperty = "_q_embedded_native_parent_handle"; const char *QWindowsWindow::hasBorderInFullScreenProperty = "_q_has_border_in_fullscreen"; +bool QWindowsWindow::m_borderInFullScreenDefault = false; QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) : QWindowsBaseWindow(aWindow), @@ -1227,7 +1228,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) if (aWindow->isTopLevel()) setWindowIcon(aWindow->icon()); - if (aWindow->property(hasBorderInFullScreenProperty).toBool()) + if (m_borderInFullScreenDefault || aWindow->property(hasBorderInFullScreenProperty).toBool()) setFlag(HasBorderInFullScreen); clearFlag(WithinCreate); } @@ -2804,6 +2805,11 @@ void QWindowsWindow::setHasBorderInFullScreenStatic(QWindow *window, bool border window->setProperty(hasBorderInFullScreenProperty, QVariant(border)); } +void QWindowsWindow::setHasBorderInFullScreenDefault(bool border) +{ + m_borderInFullScreenDefault = border; +} + void QWindowsWindow::setHasBorderInFullScreen(bool border) { if (testFlag(HasBorderInFullScreen) == border) diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index e8c30bd44b..4d136151fe 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -338,6 +338,7 @@ public: static void setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes); void registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes = QWindowsWindowFunctions::NormalTouch); static void setHasBorderInFullScreenStatic(QWindow *window, bool border); + static void setHasBorderInFullScreenDefault(bool border); void setHasBorderInFullScreen(bool border); static QString formatWindowTitle(const QString &title); @@ -381,6 +382,7 @@ private: // note: intentionally not using void * in order to avoid breaking x86 VkSurfaceKHR m_vkSurface = 0; #endif + static bool m_borderInFullScreenDefault; }; #ifndef QT_NO_DEBUG_STREAM -- cgit v1.2.3 From b98c43ea602b336813fa967e610da2be100f748d Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 18 Oct 2018 21:43:59 +0200 Subject: Compile with QT_STRICT_ITERATORS defined This will be the only options for Qt 6, so make sure the code compiles now. Change-Id: I23f791d1efcbd0bd33805bb4563d40460954db43 Reviewed-by: Oswald Buddenhagen --- src/plugins/platforms/xcb/qxcbeventqueue.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.cpp b/src/plugins/platforms/xcb/qxcbeventqueue.cpp index 862f68764b..883268b083 100644 --- a/src/plugins/platforms/xcb/qxcbeventqueue.cpp +++ b/src/plugins/platforms/xcb/qxcbeventqueue.cpp @@ -257,7 +257,7 @@ qint32 QXcbEventQueue::generatePeekerId() bool QXcbEventQueue::removePeekerId(qint32 peekerId) { - const auto it = m_peekerToNode.find(peekerId); + const auto it = m_peekerToNode.constFind(peekerId); if (it == m_peekerToNode.constEnd()) { qCWarning(lcQpaXcb, "failed to remove unknown peeker id: %d", peekerId); return false; @@ -276,7 +276,7 @@ bool QXcbEventQueue::peekEventQueue(PeekerCallback peeker, void *peekerData, const bool peekerIdProvided = peekerId != -1; auto peekerToNodeIt = m_peekerToNode.find(peekerId); - if (peekerIdProvided && peekerToNodeIt == m_peekerToNode.constEnd()) { + if (peekerIdProvided && peekerToNodeIt == m_peekerToNode.end()) { qCWarning(lcQpaXcb, "failed to find index for unknown peeker id: %d", peekerId); return false; } @@ -336,7 +336,7 @@ bool QXcbEventQueue::peekEventQueue(PeekerCallback peeker, void *peekerData, // Before updating, make sure that a peeker callback did not remove // the peeker id. peekerToNodeIt = m_peekerToNode.find(peekerId); - if (peekerToNodeIt != m_peekerToNode.constEnd()) + if (peekerToNodeIt != m_peekerToNode.end()) *peekerToNodeIt = node; // id still in the cache, update node } -- cgit v1.2.3 From 4213f239361e042ae5a053e3eaa87931b6696caf Mon Sep 17 00:00:00 2001 From: Kirill Burtsev Date: Tue, 23 Oct 2018 18:06:55 +0200 Subject: xcb: Fix leaking events on destroy This patch amends 243c3044b647357ca6df79ac1497ae43de957d31 Change-Id: Ieeebb1e2b94d7c191bf80a1f439c826c406a0c08 Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbeventqueue.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.cpp b/src/plugins/platforms/xcb/qxcbeventqueue.cpp index 862f68764b..f6158d3127 100644 --- a/src/plugins/platforms/xcb/qxcbeventqueue.cpp +++ b/src/plugins/platforms/xcb/qxcbeventqueue.cpp @@ -105,7 +105,8 @@ QXcbEventQueue::~QXcbEventQueue() wait(); } - while (xcb_generic_event_t *event = takeFirst()) + flushBufferedEvents(); + while (xcb_generic_event_t *event = takeFirst(QEventLoop::AllEvents)) free(event); if (m_head && m_head->fromHeap) @@ -219,6 +220,8 @@ void QXcbEventQueue::run() tail->next = qXcbEventNodeFactory(event); tail = tail->next; m_tail.store(tail, std::memory_order_release); + } else { + free(event); } }; -- cgit v1.2.3 From bd989d1652b8ad77088edbc7a68475dd1aabe52e Mon Sep 17 00:00:00 2001 From: Kirill Burtsev Date: Fri, 23 Nov 2018 13:02:33 +0100 Subject: xcb: free leaking clipboard events The leak has been there since the beginnings of Qt 5.0. Change-Id: I238181dcc63cb4cf8a60b5c565b184d8278d0315 Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbclipboard.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index 9c7559d514..bc92f82d5f 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -261,7 +261,9 @@ QXcbClipboard::~QXcbClipboard() connection()->sync(); // waiting until the clipboard manager fetches the content. - if (!waitForClipboardEvent(m_owner, XCB_SELECTION_NOTIFY, true)) { + if (auto event = waitForClipboardEvent(m_owner, XCB_SELECTION_NOTIFY, true)) { + free(event); + } else { qWarning("QXcbClipboard: Unable to receive an event from the " "clipboard manager in a reasonable time"); } @@ -838,6 +840,7 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb if (!ge) break; xcb_property_notify_event_t *event = (xcb_property_notify_event_t *)ge; + QScopedPointer guard(event); if (event->atom != property || event->state != XCB_PROPERTY_NEW_VALUE @@ -869,8 +872,6 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb } else { break; } - - free(ge); } // timed out ... create a new requestor window, otherwise the requestor -- cgit v1.2.3 From d4e3442fdbb98b5c635448031ff9958819a46bc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Sun, 25 Nov 2018 15:59:04 +0100 Subject: CoreText: Modernize font smoothing and antialiasing threshold detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The way macOS does font smoothing has changed in Mojave, and we need to take both this new algorithm into account, as well as support users who set legacy preferences to revert back to subpixel font smoothing. As a followup to this patch we will tweak some of the existing logic to take the new font smoothing algorithm into account, so this is just a first step. Change-Id: If37014c18515f406b8bb8194c9df7a75c2eb10fc Reviewed-by: Simon Hausmann Reviewed-by: Tor Arne Vestbø Reviewed-by: Allan Sandfeld Jensen --- src/plugins/platforms/cocoa/qpaintengine_mac.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm index 5c880b1cad..69e7a92234 100644 --- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm @@ -914,7 +914,7 @@ void QCoreGraphicsPaintEngine::drawTextItem(const QPointF &pos, const QTextItem QFontEngine *fe = ti.fontEngine; const bool textAA = ((state->renderHints() & QPainter::TextAntialiasing) - && (fe->fontDef.pointSize > QCoreTextFontEngine::antialiasingThreshold) + && (fe->fontDef.pointSize > QCoreTextFontEngine::antialiasingThreshold()) && !(fe->fontDef.styleStrategy & QFont::NoAntialias)); const bool lineAA = state->renderHints() & QPainter::Antialiasing; if (textAA != lineAA) -- cgit v1.2.3 From 2a1c368c873afe9b222c759d4348b93beafca8ea Mon Sep 17 00:00:00 2001 From: Mikhail Svetkin Date: Fri, 16 Nov 2018 10:32:39 +0100 Subject: xcb: Use std::move and pass argument by rvalue reference It will avoid a creation of temporary object and avoid copying. Change-Id: Ifae5f6f9e36bcb07f4bacc31f151f8adcfa621a3 Reviewed-by: Anton Kudryavtsev Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbconnection_screens.cpp | 2 +- src/plugins/platforms/xcb/qxcbscreen.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp index fe9e0be86d..9aba996bb9 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp @@ -384,7 +384,7 @@ void QXcbConnection::initializeScreens() } siblings << screen; } - virtualDesktop->setScreens(siblings); + virtualDesktop->setScreens(std::move(siblings)); xcb_screen_next(&it); ++xcbScreenNumber; } // for each xcb screen diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index 7f22a8e4db..be6c45e415 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -79,7 +79,7 @@ public: QXcbScreen *screenAt(const QPoint &pos) const; QList screens() const { return m_screens; } - void setScreens(QList sl) { m_screens = sl; } + void setScreens(QList &&sl) { m_screens = std::move(sl); } void removeScreen(QPlatformScreen *s) { m_screens.removeOne(s); } void addScreen(QPlatformScreen *s); void setPrimaryScreen(QPlatformScreen *s); -- cgit v1.2.3 From 3944f45c4d74b0389dc2246d1292790a9591ab82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 27 Nov 2018 17:13:38 +0100 Subject: CoreText: Remove handling of the AppleAntiAliasingThreshold user default The setting is not relevant for modern macOS applications, and none of the applications shipped with macOS today are affected by it. The only code path in macOS that picks it up is +[NSFont initialize] in the UIFoundation framework, storing it for later so that -[NSFont screenFont] and -[NSFont screenFontWithRenderingMode:] can use it, but these APIs are deprecated and we don't use them in Qt. Other NSFont code paths will not hit these APIs unless screen font substitution is enabled, something it hasn't been since OSX 10.7. https://preview.tinyurl.com/yctpfnqp Removing handling of this setting allows us to simplify the reasoning for whether or not antialiasing and font smoothing is enabled for a given engine. Change-Id: Ie2809052a1a0815d9bddedd4a6236eb6c898f993 Reviewed-by: Lars Knoll Reviewed-by: Allan Sandfeld Jensen --- src/plugins/platforms/cocoa/qpaintengine_mac.mm | 1 - 1 file changed, 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm index 69e7a92234..3677877538 100644 --- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm @@ -914,7 +914,6 @@ void QCoreGraphicsPaintEngine::drawTextItem(const QPointF &pos, const QTextItem QFontEngine *fe = ti.fontEngine; const bool textAA = ((state->renderHints() & QPainter::TextAntialiasing) - && (fe->fontDef.pointSize > QCoreTextFontEngine::antialiasingThreshold()) && !(fe->fontDef.styleStrategy & QFont::NoAntialias)); const bool lineAA = state->renderHints() & QPainter::Antialiasing; if (textAA != lineAA) -- cgit v1.2.3 From 6d58a1cecbaf0a6ed7d751f67450a86c742770ff Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 23 Nov 2018 17:19:14 +0100 Subject: Fix QPpdPrintDevice::isDefault How to test: * Have two printers * Use lpoptions -d to set the default printer to be one and then the other * Use lpstat -d to check setting the default printer worked * Use this simple test program and check the resulting values make sense qDebug() << "DefaultPrinter" << QPrinterInfo::defaultPrinter().printerName(); const QList list = QPrinterInfo::availablePrinters(); for(const QPrinterInfo &pi : list) { qDebug() << pi.printerName() << pi.isDefault(); } Fixes: QTBUG-70317 Change-Id: I535d11451c568630a374f5c37d8cac32cbb6d3ab Reviewed-by: Frederik Gladhorn --- src/plugins/printsupport/cups/qcupsprintersupport.cpp | 5 +++++ src/plugins/printsupport/cups/qcupsprintersupport_p.h | 2 ++ src/plugins/printsupport/cups/qppdprintdevice.cpp | 9 ++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/printsupport/cups/qcupsprintersupport.cpp b/src/plugins/printsupport/cups/qcupsprintersupport.cpp index 19e1df31f6..42a7a821f2 100644 --- a/src/plugins/printsupport/cups/qcupsprintersupport.cpp +++ b/src/plugins/printsupport/cups/qcupsprintersupport.cpp @@ -174,6 +174,11 @@ QStringList QCupsPrinterSupport::availablePrintDeviceIds() const } QString QCupsPrinterSupport::defaultPrintDeviceId() const +{ + return staticDefaultPrintDeviceId(); +} + +QString QCupsPrinterSupport::staticDefaultPrintDeviceId() { QString printerId; cups_dest_t *dests; diff --git a/src/plugins/printsupport/cups/qcupsprintersupport_p.h b/src/plugins/printsupport/cups/qcupsprintersupport_p.h index 42de28aec0..c2b4895c7f 100644 --- a/src/plugins/printsupport/cups/qcupsprintersupport_p.h +++ b/src/plugins/printsupport/cups/qcupsprintersupport_p.h @@ -71,6 +71,8 @@ public: QStringList availablePrintDeviceIds() const override; QString defaultPrintDeviceId() const override; + static QString staticDefaultPrintDeviceId(); + private: QString cupsOption(int i, const QString &key) const; }; diff --git a/src/plugins/printsupport/cups/qppdprintdevice.cpp b/src/plugins/printsupport/cups/qppdprintdevice.cpp index 51b93a0016..ea6336c4d1 100644 --- a/src/plugins/printsupport/cups/qppdprintdevice.cpp +++ b/src/plugins/printsupport/cups/qppdprintdevice.cpp @@ -39,6 +39,8 @@ #include "qppdprintdevice.h" +#include "qcupsprintersupport_p.h" + #include #include @@ -118,7 +120,12 @@ bool QPpdPrintDevice::isValid() const bool QPpdPrintDevice::isDefault() const { - return printerTypeFlags() & CUPS_PRINTER_DEFAULT; + // There seems to be a bug in cups in which printerTypeFlags + // returns CUPS_PRINTER_DEFAULT based only on system values, ignoring user lpoptions + // so we can't use that. And also there seems to be a bug in which dests returned + // by cupsGetNamedDest don't have is_default set at all so we can't use that either + // so go the long route and compare our id against the defaultPrintDeviceId + return id() == QCupsPrinterSupport::staticDefaultPrintDeviceId(); } QPrint::DeviceState QPpdPrintDevice::state() const -- cgit v1.2.3 From c3a963da1f9e7b1d37e63eedded61da4fbdaaf9a Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Fri, 16 Nov 2018 17:07:33 +0100 Subject: src/3rdparty: remove xkbcommon The only reason why we bundled this library ~6 years ago was because it was not available on distributions that we supported at the time, but library was a hard dependency for XCB plugin. See: 2122e731abdb619249df89642c0800640b2fa428 Later more and more projects started to depend on it (compose input context plugin, libinput, mir, wayland). The configuration had become too complex, because some projects used bundled and some used the version from the system. Having libxkbcommon in 3rdparty sources is not necessary anymore, after RHEL 6.6 was removed from the list of supported platforms for Qt 5.12. Ubuntu 16.04 - 0.5.0 Ubuntu 18.04 - 0.8.0 openSUSE 42.3 - 0.6.1 RHEL-7.4 - 0.7.1 This will also simplify further development, e.g. QTBUG-42181 Bumped the minimal required version 0.4.1 -> 0.5.0. The patch also contains a code marked with "TRANSITION HACK", which is temporary needed so we can update the dependent wayland module. [ChangeLog][Third-Party Code] Removed xkbcommon from bundled sources. This library is present on all supported platforms. The minimal required version now is 0.5.0. Task-number: QTBUG-65503 Change-Id: Iec50829bb6f8fbb19f3c4e4ad62e332beb837de5 Reviewed-by: Lars Knoll Reviewed-by: Laszlo Agocs Reviewed-by: Oswald Buddenhagen --- src/plugins/platforminputcontexts/compose/compose.pro | 7 +------ src/plugins/platforms/mirclient/mirclient.pro | 7 +------ src/plugins/platforms/xcb/xcb_qpa_lib.pro | 14 ++++---------- 3 files changed, 6 insertions(+), 22 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforminputcontexts/compose/compose.pro b/src/plugins/platforminputcontexts/compose/compose.pro index 2f53c5b416..68bc2c3466 100644 --- a/src/plugins/platforminputcontexts/compose/compose.pro +++ b/src/plugins/platforminputcontexts/compose/compose.pro @@ -9,12 +9,7 @@ SOURCES += $$PWD/qcomposeplatforminputcontextmain.cpp \ HEADERS += $$PWD/qcomposeplatforminputcontext.h \ $$PWD/generator/qtablegenerator.h \ -# libxkbcommon -!qtConfig(xkbcommon-system) { - include(../../../3rdparty/xkbcommon.pri) -} else { - QMAKE_USE += xkbcommon -} +QMAKE_USE_PRIVATE += xkbcommon include($$OUT_PWD/../../../gui/qtgui-config.pri) diff --git a/src/plugins/platforms/mirclient/mirclient.pro b/src/plugins/platforms/mirclient/mirclient.pro index d2da7e6ca0..d9eb069200 100644 --- a/src/plugins/platforms/mirclient/mirclient.pro +++ b/src/plugins/platforms/mirclient/mirclient.pro @@ -53,12 +53,7 @@ HEADERS = \ qmirclienttheme.h \ qmirclientwindow.h -# libxkbcommon -!qtConfig(xkbcommon-system) { - include(../../../3rdparty/xkbcommon.pri) -} else { - QMAKE_USE += xkbcommon -} +QMAKE_USE_PRIVATE += xkbcommon PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = MirServerIntegrationPlugin diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index c65b145fb6..9883617ab6 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -97,21 +97,15 @@ qtConfig(vulkan) { !qtConfig(system-xcb) { QMAKE_USE += xcb-static xcb } else { - qtConfig(xkb): QMAKE_USE += xcb_xkb qtConfig(xcb-render): QMAKE_USE += xcb_render qtConfig(xcb-xinput): QMAKE_USE += xcb_xinput QMAKE_USE += xcb_syslibs } -# libxkbcommon -!qtConfig(xkbcommon-system) { - qtConfig(xkb) { - include(../../../3rdparty/xkbcommon-x11.pri) - } else { - include(../../../3rdparty/xkbcommon.pri) - } -} else { - QMAKE_USE += xkbcommon +QMAKE_USE += xkbcommon +qtConfig(xkb) { + QMAKE_USE += xkbcommon_x11 + qtConfig(system-xcb): QMAKE_USE += xcb_xkb } qtConfig(dlopen): QMAKE_USE += libdl -- cgit v1.2.3 From eab84914f1a31984f4698bcbca170556a56fd6fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Thu, 27 Sep 2018 12:26:36 +0200 Subject: macOS: make QScreen::grabWindow() fast again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 17b73b0d2b8 regressed performance by grabbing the entire screen and then copying the grab region. Move back to grabbing a minimal rectangle instead. Also handle multi-screen grabs at different device pixel ratios. Multi-screen grabbing is handled by grabbing each screen individually, and then stitching together the result. The returned pixmap is created using the highest DPR available, upscaling lower resolution parts as needed. Change-Id: I9d45c5f7ec7b342360b745f49ef2939dc588f40b Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoascreen.mm | 95 +++++++++++++++-------------- 1 file changed, 50 insertions(+), 45 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm index 0d6567070e..afe14e623c 100644 --- a/src/plugins/platforms/cocoa/qcocoascreen.mm +++ b/src/plugins/platforms/cocoa/qcocoascreen.mm @@ -428,66 +428,71 @@ QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const return window; } -QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height) const +QPixmap QCocoaScreen::grabWindow(WId view, int x, int y, int width, int height) const { - // TODO window should be handled - Q_UNUSED(window) - - const int maxDisplays = 128; // 128 displays should be enough for everyone. + // Determine the grab rect. FIXME: The rect should be bounded by the view's + // geometry, but note that for the pixeltool use case that window will be the + // desktop widgets's view, which currently gets resized to fit one screen + // only, since its NSWindow has the NSWindowStyleMaskTitled flag set. + Q_UNUSED(view); + QRect grabRect = QRect(x, y, width, height); + qCDebug(lcQpaScreen) << "input grab rect" << grabRect; + + // Find which displays to grab from, or all of them if the grab size is unspecified + const int maxDisplays = 128; CGDirectDisplayID displays[maxDisplays]; CGDisplayCount displayCount; - CGRect cgRect; - - if (width < 0 || height < 0) { - // get all displays - cgRect = CGRectInfinite; - } else { - cgRect = CGRectMake(x, y, width, height); - } + CGRect cgRect = (width < 0 || height < 0) ? CGRectInfinite : grabRect.toCGRect(); const CGDisplayErr err = CGGetDisplaysWithRect(cgRect, maxDisplays, displays, &displayCount); - - if (err && displayCount == 0) + if (err || displayCount == 0) return QPixmap(); - // calculate pixmap size - QSize windowSize(width, height); + // If the grab size is not specified, set it to be the bounding box of all screens, if (width < 0 || height < 0) { QRect windowRect; for (uint i = 0; i < displayCount; ++i) { - const CGRect cgRect = CGDisplayBounds(displays[i]); - QRect qRect(cgRect.origin.x, cgRect.origin.y, cgRect.size.width, cgRect.size.height); - windowRect = windowRect.united(qRect); + QRect displayBounds = QRectF::fromCGRect(CGDisplayBounds(displays[i])).toRect(); + windowRect = windowRect.united(displayBounds); } - if (width < 0) - windowSize.setWidth(windowRect.width()); - if (height < 0) - windowSize.setHeight(windowRect.height()); + if (grabRect.width() < 0) + grabRect.setWidth(windowRect.width()); + if (grabRect.height() < 0) + grabRect.setHeight(windowRect.height()); } - const qreal dpr = devicePixelRatio(); - QPixmap windowPixmap(windowSize * dpr); - windowPixmap.setDevicePixelRatio(dpr); - windowPixmap.fill(Qt::transparent); + qCDebug(lcQpaScreen) << "final grab rect" << grabRect << "from" << displayCount << "displays"; + // Grab images from each display + QVector images; + QVector destinations; for (uint i = 0; i < displayCount; ++i) { - const CGRect bounds = CGDisplayBounds(displays[i]); - - // Calculate the position and size of the requested area - QPoint pos(qAbs(bounds.origin.x - x), qAbs(bounds.origin.y - y)); - QSize size(qMin(width, qRound(bounds.size.width)), - qMin(height, qRound(bounds.size.height))); - pos *= dpr; - size *= dpr; - - // Take the whole screen and crop it afterwards, because CGDisplayCreateImageForRect - // has a strange behavior when mixing highDPI and non-highDPI displays - QCFType cgImage = CGDisplayCreateImage(displays[i]); - const QImage image = qt_mac_toQImage(cgImage); - - // Draw into windowPixmap only the requested size - QPainter painter(&windowPixmap); - painter.drawImage(windowPixmap.rect(), image, QRect(pos, size)); + auto display = displays[i]; + QRect displayBounds = QRectF::fromCGRect(CGDisplayBounds(display)).toRect(); + QRect grabBounds = displayBounds.intersected(grabRect); + QRect displayLocalGrabBounds = QRect(QPoint(grabBounds.topLeft() - displayBounds.topLeft()), grabBounds.size()); + QImage displayImage = qt_mac_toQImage(QCFType(CGDisplayCreateImageForRect(display, displayLocalGrabBounds.toCGRect()))); + displayImage.setDevicePixelRatio(displayImage.size().width() / displayLocalGrabBounds.size().width()); + images.append(displayImage); + QRect destBounds = QRect(QPoint(grabBounds.topLeft() - grabRect.topLeft()), grabBounds.size()); + destinations.append(destBounds); + qCDebug(lcQpaScreen) << "grab display" << i << "global" << grabBounds << "local" << displayLocalGrabBounds + << "grab image size" << displayImage.size() << "devicePixelRatio" << displayImage.devicePixelRatio(); } + + // Determine the highest dpr, which becomes the dpr for the returned pixmap. + qreal dpr = 1.0; + for (uint i = 0; i < displayCount; ++i) + dpr = qMax(dpr, images.at(i).devicePixelRatio()); + + // Alocate target pixmap and draw each screen's content + qCDebug(lcQpaScreen) << "Create grap pixmap" << grabRect.size() << "at devicePixelRatio" << dpr; + QPixmap windowPixmap(grabRect.size() * dpr); + windowPixmap.setDevicePixelRatio(dpr); + windowPixmap.fill(Qt::transparent); + QPainter painter(&windowPixmap); + for (uint i = 0; i < displayCount; ++i) + painter.drawImage(destinations.at(i), images.at(i)); + return windowPixmap; } -- cgit v1.2.3 From 0de4b326d8e02c228ebefcac1abe069c45cbb5c4 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Mon, 26 Nov 2018 15:23:27 +0100 Subject: xcb: fix issue with dialogs hidden by other windows This was a regression from Qt4, due to not setting the window group leader in WM_HINTS property. Qt4 did set this property. It was not obvious that something was missing because of the similarly named WM_CLIENT_LEADER property, which we do set. Testing revealed that setting WM_CLIENT_LEADER is sufficient on some DEs, e.g. KDE, Unity, but did not have the desired effect on e.g Gnome and XFCE. EWMH/ICCCM specs are known to be ambiguous, WM_CLIENT_LEADER is only mentioned in the section on the session management, so it is not surprising that there is this inconsistency between various WMs. This patch merely restores a lost WM hint. This solves the reported issues on major desktops. If we support calling show() on a dialog before its parent has been shown is still an open question, which should be handled in QTBUG-72040. Task-number: QTBUG-56829 Fixes: QTBUG-46626 Fixes: QTBUG-70756 Task-number: QTBUG-72040 Change-Id: Id2c575850e5f4f5af3e57963c577d33572e30b6e Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/qxcbwindow.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 891fe6b155..65e1c71531 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -501,6 +501,8 @@ void QXcbWindow::create() // from various setter functions for adjusting the hints. xcb_wm_hints_t hints; memset(&hints, 0, sizeof(hints)); + hints.flags = XCB_ICCCM_WM_HINT_WINDOW_GROUP; + hints.window_group = connection()->clientLeader(); xcb_set_wm_hints(xcb_connection(), m_window, &hints); xcb_window_t leader = connection()->clientLeader(); -- cgit v1.2.3 From f2b4462f84d0b8b28da50141163890bbf7fe6174 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Thu, 1 Nov 2018 15:29:35 +0100 Subject: xcb: remove old work-around for building with util-wm Commits that added this code: 7ce8491280990350162933a0716d1b014f65aeb6 and f005dee1b3692a09e47782dcff9b5b07aa659b51 I guess this was a work-around, before we started bundling XCB libs a year later in 21bd66e1ea06e466754ab06ee2c5f8b737bb4bd7 0.3.8 was released in 2011-04-26 and we are bundling 0.3.9, so it is safe to remove the include work-around as well. Change-Id: I5794f40d86e10ebdad984aa4b61311979aaadcf3 Reviewed-by: Oswald Buddenhagen Reviewed-by: Frederik Gladhorn Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/qxcbwindow.cpp | 83 +++++++++++--------------------- 1 file changed, 29 insertions(+), 54 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 65e1c71531..3bfcbf2adb 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -64,38 +64,13 @@ #include -// FIXME This workaround can be removed for xcb-icccm > 3.8 -#define class class_name #include -#undef class #include #include #if QT_CONFIG(xcb_xinput) #include #endif -// xcb-icccm 3.8 support -#ifdef XCB_ICCCM_NUM_WM_SIZE_HINTS_ELEMENTS -#define xcb_get_wm_hints_reply xcb_icccm_get_wm_hints_reply -#define xcb_get_wm_hints xcb_icccm_get_wm_hints -#define xcb_get_wm_hints_unchecked xcb_icccm_get_wm_hints_unchecked -#define xcb_set_wm_hints xcb_icccm_set_wm_hints -#define xcb_set_wm_normal_hints xcb_icccm_set_wm_normal_hints -#define xcb_size_hints_set_base_size xcb_icccm_size_hints_set_base_size -#define xcb_size_hints_set_max_size xcb_icccm_size_hints_set_max_size -#define xcb_size_hints_set_min_size xcb_icccm_size_hints_set_min_size -#define xcb_size_hints_set_position xcb_icccm_size_hints_set_position -#define xcb_size_hints_set_resize_inc xcb_icccm_size_hints_set_resize_inc -#define xcb_size_hints_set_size xcb_icccm_size_hints_set_size -#define xcb_size_hints_set_win_gravity xcb_icccm_size_hints_set_win_gravity -#define xcb_wm_hints_set_iconic xcb_icccm_wm_hints_set_iconic -#define xcb_wm_hints_set_normal xcb_icccm_wm_hints_set_normal -#define xcb_wm_hints_set_input xcb_icccm_wm_hints_set_input -#define xcb_wm_hints_t xcb_icccm_wm_hints_t -#define XCB_WM_STATE_ICONIC XCB_ICCCM_WM_STATE_ICONIC -#define XCB_WM_STATE_WITHDRAWN XCB_ICCCM_WM_STATE_WITHDRAWN -#endif - #include #include @@ -497,13 +472,13 @@ void QXcbWindow::create() clientMachine.size(), clientMachine.constData()); } - // Create WM_HINTS property on the window, so we can xcb_get_wm_hints*() + // Create WM_HINTS property on the window, so we can xcb_icccm_get_wm_hints*() // from various setter functions for adjusting the hints. - xcb_wm_hints_t hints; + xcb_icccm_wm_hints_t hints; memset(&hints, 0, sizeof(hints)); hints.flags = XCB_ICCCM_WM_HINT_WINDOW_GROUP; hints.window_group = connection()->clientLeader(); - xcb_set_wm_hints(xcb_connection(), m_window, &hints); + xcb_icccm_set_wm_hints(xcb_connection(), m_window, &hints); xcb_window_t leader = connection()->clientLeader(); xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, @@ -1200,7 +1175,7 @@ void QXcbWindow::setWindowState(Qt::WindowStates state) event.sequence = 0; event.window = m_window; event.type = atom(QXcbAtom::WM_CHANGE_STATE); - event.data.data32[0] = XCB_WM_STATE_ICONIC; + event.data.data32[0] = XCB_ICCCM_WM_STATE_ICONIC; event.data.data32[1] = 0; event.data.data32[2] = 0; event.data.data32[3] = 0; @@ -1214,14 +1189,14 @@ void QXcbWindow::setWindowState(Qt::WindowStates state) setNetWmState(state); - xcb_get_property_cookie_t cookie = xcb_get_wm_hints_unchecked(xcb_connection(), m_window); - xcb_wm_hints_t hints; - if (xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, nullptr)) { + xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_hints_unchecked(xcb_connection(), m_window); + xcb_icccm_wm_hints_t hints; + if (xcb_icccm_get_wm_hints_reply(xcb_connection(), cookie, &hints, nullptr)) { if (state & Qt::WindowMinimized) - xcb_wm_hints_set_iconic(&hints); + xcb_icccm_wm_hints_set_iconic(&hints); else - xcb_wm_hints_set_normal(&hints); - xcb_set_wm_hints(xcb_connection(), m_window, &hints); + xcb_icccm_wm_hints_set_normal(&hints); + xcb_icccm_set_wm_hints(xcb_connection(), m_window, &hints); } connection()->sync(); @@ -1302,14 +1277,14 @@ void QXcbWindow::setTransparentForMouseEvents(bool transparent) void QXcbWindow::updateDoesNotAcceptFocus(bool doesNotAcceptFocus) { - xcb_get_property_cookie_t cookie = xcb_get_wm_hints_unchecked(xcb_connection(), m_window); + xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_hints_unchecked(xcb_connection(), m_window); - xcb_wm_hints_t hints; - if (!xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, nullptr)) + xcb_icccm_wm_hints_t hints; + if (!xcb_icccm_get_wm_hints_reply(xcb_connection(), cookie, &hints, nullptr)) return; - xcb_wm_hints_set_input(&hints, !doesNotAcceptFocus); - xcb_set_wm_hints(xcb_connection(), m_window, &hints); + xcb_icccm_wm_hints_set_input(&hints, !doesNotAcceptFocus); + xcb_icccm_set_wm_hints(xcb_connection(), m_window, &hints); } WId QXcbWindow::winId() const @@ -1417,9 +1392,9 @@ void QXcbWindow::propagateSizeHints() QWindowPrivate *win = qt_window_private(window()); if (!win->positionAutomatic) - xcb_size_hints_set_position(&hints, true, rect.x(), rect.y()); + xcb_icccm_size_hints_set_position(&hints, true, rect.x(), rect.y()); if (rect.width() < QWINDOWSIZE_MAX || rect.height() < QWINDOWSIZE_MAX) - xcb_size_hints_set_size(&hints, true, rect.width(), rect.height()); + xcb_icccm_size_hints_set_size(&hints, true, rect.width(), rect.height()); /* Gravity describes how to interpret x and y values the next time window needs to be positioned on a screen. @@ -1428,7 +1403,7 @@ void QXcbWindow::propagateSizeHints() auto gravity = win->positionPolicy == QWindowPrivate::WindowFrameInclusive ? XCB_GRAVITY_NORTH_WEST : XCB_GRAVITY_STATIC; - xcb_size_hints_set_win_gravity(&hints, gravity); + xcb_icccm_size_hints_set_win_gravity(&hints, gravity); QSize minimumSize = windowMinimumSize(); QSize maximumSize = windowMaximumSize(); @@ -1436,21 +1411,21 @@ void QXcbWindow::propagateSizeHints() QSize sizeIncrement = windowSizeIncrement(); if (minimumSize.width() > 0 || minimumSize.height() > 0) - xcb_size_hints_set_min_size(&hints, - qMin(XCOORD_MAX,minimumSize.width()), - qMin(XCOORD_MAX,minimumSize.height())); + xcb_icccm_size_hints_set_min_size(&hints, + qMin(XCOORD_MAX,minimumSize.width()), + qMin(XCOORD_MAX,minimumSize.height())); if (maximumSize.width() < QWINDOWSIZE_MAX || maximumSize.height() < QWINDOWSIZE_MAX) - xcb_size_hints_set_max_size(&hints, - qMin(XCOORD_MAX, maximumSize.width()), - qMin(XCOORD_MAX, maximumSize.height())); + xcb_icccm_size_hints_set_max_size(&hints, + qMin(XCOORD_MAX, maximumSize.width()), + qMin(XCOORD_MAX, maximumSize.height())); if (sizeIncrement.width() > 0 || sizeIncrement.height() > 0) { - xcb_size_hints_set_base_size(&hints, baseSize.width(), baseSize.height()); - xcb_size_hints_set_resize_inc(&hints, sizeIncrement.width(), sizeIncrement.height()); + xcb_icccm_size_hints_set_base_size(&hints, baseSize.width(), baseSize.height()); + xcb_icccm_size_hints_set_resize_inc(&hints, sizeIncrement.width(), sizeIncrement.height()); } - xcb_set_wm_normal_hints(xcb_connection(), m_window, &hints); + xcb_icccm_set_wm_normal_hints(xcb_connection(), m_window, &hints); } void QXcbWindow::requestActivateWindow() @@ -2257,8 +2232,8 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::WM_STATE)) { const quint32 *data = (const quint32 *)xcb_get_property_value(reply.get()); if (reply->length != 0) - m_minimized = (data[0] == XCB_WM_STATE_ICONIC - || (data[0] == XCB_WM_STATE_WITHDRAWN && m_minimized)); + m_minimized = (data[0] == XCB_ICCCM_WM_STATE_ICONIC + || (data[0] == XCB_ICCCM_WM_STATE_WITHDRAWN && m_minimized)); } } if (m_minimized) -- cgit v1.2.3 From 2afe4a1a074096a3a6476aae21e732c418717da7 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Wed, 28 Nov 2018 14:56:45 +0100 Subject: Android: Don't use blocking queued when suspending the application If the application gets suspended when a blocking queued connection is made then it will cause the application to hang when being resumed. Therefore a check is needed to still post the event to the other thread but in a non blocking manner so that it does not cause a hang on return. Fixes: QTBUG-72101 Change-Id: I6d53c97ed6d9d500559da2a9fd195226d1fc9905 Reviewed-by: BogDan Vatra --- src/plugins/platforms/android/qandroidinputcontext.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index c5cd0b92d9..7b3546f9bb 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -99,9 +99,13 @@ static jfieldID m_selectionStartFieldID = 0; static jfieldID m_startOffsetFieldID = 0; static jfieldID m_textFieldID = 0; +Q_DECLARE_METATYPE(std::function) + static void runOnQtThread(const std::function &func) { - QMetaObject::invokeMethod(m_androidInputContext, "safeCall", Qt::BlockingQueuedConnection, Q_ARG(std::function, func)); + const bool block = QGuiApplication::applicationState() >= Qt::ApplicationInactive; + QMetaObject::invokeMethod(m_androidInputContext, "safeCall", + block ? Qt::BlockingQueuedConnection : Qt::QueuedConnection, Q_ARG(std::function, func)); } static jboolean beginBatchEdit(JNIEnv */*env*/, jobject /*thiz*/) @@ -512,6 +516,7 @@ QAndroidInputContext::QAndroidInputContext() m_handleMode = Hidden; updateSelectionHandles(); }); + qRegisterMetaType>(); } QAndroidInputContext::~QAndroidInputContext() -- cgit v1.2.3 From 58e66a2573e40cc3e12a5479575a8ecbef1be6d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 27 Nov 2018 19:13:54 +0100 Subject: CoreText: Define font smoothing gamma along with rest of relevant code Change-Id: I57909603732de6c1a91c744a358968941e64acdf Reviewed-by: Lars Knoll --- src/plugins/platforms/cocoa/qcocoaintegration.mm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 1bd1029863..f6a49dd74f 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -63,6 +63,8 @@ #include +#include + #ifdef QT_WIDGETS_LIB #include #if QT_CONFIG(filedialog) @@ -477,7 +479,7 @@ QCocoaServices *QCocoaIntegration::services() const QVariant QCocoaIntegration::styleHint(StyleHint hint) const { if (hint == QPlatformIntegration::FontSmoothingGamma) - return 2.0; + return QCoreTextFontEngine::fontSmoothingGamma(); return QPlatformIntegration::styleHint(hint); } -- cgit v1.2.3 From 49319734c11206f6993aa12b42a663d3906da26e Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Tue, 27 Nov 2018 15:25:53 +0100 Subject: ico image handler: check for out of range image size Make the decoder fail early to avoid spending time and memory on attempting to decode a corrupt image file. Change-Id: I598db817c387867a449040f5be5427c8b8746483 Reviewed-by: Lars Knoll --- src/plugins/imageformats/ico/qicohandler.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/imageformats/ico/qicohandler.cpp b/src/plugins/imageformats/ico/qicohandler.cpp index e61173db30..30935cacda 100644 --- a/src/plugins/imageformats/ico/qicohandler.cpp +++ b/src/plugins/imageformats/ico/qicohandler.cpp @@ -506,6 +506,8 @@ QImage ICOReader::iconAt(int index) icoAttrib.h = iconEntry.bHeight; if (icoAttrib.h == 0) // means 256 pixels icoAttrib.h = header.biHeight/2; + if (icoAttrib.w > 256 || icoAttrib.h > 256) // Max ico size + return img; QImage::Format format = QImage::Format_ARGB32; if (icoAttrib.nbits == 24) -- cgit v1.2.3 From 521a85395da1a2728902816c072ec46bcb0ad380 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 1 Dec 2017 20:13:08 +0100 Subject: configure: actually resolve libraries into full filepaths this considerably speeds up failures, as no doomed build is attempted, and produces more reliable results, as no second lookup (which would be subject to environment changes) is done any more during the build. in principle, this also opens up possibilities like selecting specific variants of dependencies, automatically extracting rpaths, etc. qt_helper_lib.prf also needs to create fully resolved library names now. Change-Id: I65f13564b635433030e40fa017427bbc72d1c130 Reviewed-by: Joerg Bornemann --- src/plugins/sqldrivers/configure.pri | 50 +++++++++++++----------------------- 1 file changed, 18 insertions(+), 32 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/sqldrivers/configure.pri b/src/plugins/sqldrivers/configure.pri index 24954e9514..747a47e7b8 100644 --- a/src/plugins/sqldrivers/configure.pri +++ b/src/plugins/sqldrivers/configure.pri @@ -1,29 +1,16 @@ # custom tests -defineReplace(filterLibraryPath) { - str = $${1} - for (l, QMAKE_DEFAULT_LIBDIRS): \ - str -= "-L$$l" - - return($$str) -} - defineTest(qtConfLibrary_psqlConfig) { pg_config = $$config.input.psql_config isEmpty(pg_config): \ pg_config = $$qtConfFindInPath("pg_config") !win32:!isEmpty(pg_config) { qtRunLoggedCommand("$$pg_config --libdir", libdir)|return(false) + !qtConfResolvePathLibs($${1}.libs, $$libdir, -lpq): \ + return(false) qtRunLoggedCommand("$$pg_config --includedir", includedir)|return(false) - libdir -= $$QMAKE_DEFAULT_LIBDIRS - libs = - !isEmpty(libdir): libs += "-L$$libdir" - libs += "-lpq" - $${1}.libs = $$libs - includedir -= $$QMAKE_DEFAULT_INCDIRS - $${1}.includedir = $$includedir - export($${1}.libs) - export($${1}.includedir) + !qtConfResolvePathIncs($${1}.includedir, $$includedir): \ + return(false) return(true) } qtLog("pg_config not found.") @@ -34,8 +21,9 @@ defineTest(qtConfLibrary_psqlEnv) { # Respect PSQL_LIBS if set PSQL_LIBS = $$getenv(PSQL_LIBS) !isEmpty(PSQL_LIBS) { - eval($${1}.libs = $$PSQL_LIBS) - export($${1}.libs) + eval(libs = $$PSQL_LIBS) + !qtConfResolveLibs($${1}.libs, $$libs): \ + return(false) } else { !qtConfLibrary_inline($$1, $$2): \ return(false) @@ -58,7 +46,6 @@ defineTest(qtConfLibrary_mysqlConfig) { qtRunLoggedCommand("$$mysql_config $$query", libs)|return(false) qtRunLoggedCommand("$$mysql_config --include", includedir)|return(false) eval(libs = $$libs) - libs = $$filterLibraryPath($$libs) # -rdynamic should not be returned by mysql_config, but is on RHEL 6.6 libs -= -rdynamic equals($${1}.cleanlibs, true) { @@ -69,16 +56,15 @@ defineTest(qtConfLibrary_mysqlConfig) { } libs = $$cleanlibs } - $${1}.libs = $$libs + !qtConfResolveLibs($${1}.libs, $$libs): \ + return(false) eval(rawincludedir = $$includedir) rawincludedir ~= s/^-I//g includedir = for (id, rawincludedir): \ includedir += $$clean_path($$id) - includedir -= $$QMAKE_DEFAULT_INCDIRS - $${1}.includedir = $$includedir - export($${1}.libs) - export($${1}.includedir) + !qtConfResolvePathIncs($${1}.includedir, $$includedir): \ + return(false) return(true) } qtLog("mysql_config not found.") @@ -86,14 +72,14 @@ defineTest(qtConfLibrary_mysqlConfig) { } defineTest(qtConfLibrary_sybaseEnv) { - libs = + libdir = sybase = $$getenv(SYBASE) !isEmpty(sybase): \ - libs += "-L$${sybase}/lib" - eval(libs += $$getenv(SYBASE_LIBS)) - !isEmpty(libs) { - $${1}.libs = $$libs - export($${1}.libs) - } + libdir += $${sybase}/lib + eval(libs = $$getenv(SYBASE_LIBS)) + isEmpty(libs): \ + libs = $$eval($${1}.libs) + !qtConfResolvePathLibs($${1}.libs, $$libdir, $$libs): \ + return(false) return(true) } -- cgit v1.2.3 From 7f4d0405b409b1d3aa9d91e31972669576ec698c Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 10 Oct 2018 18:58:22 +0200 Subject: Rename QList::swap(int, int) to swapItemsAt() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old name was confusing as it conflicted with QList::swap(QList &other), that was doing something completely different. Rename the method to swapItemsAt() which is a lot clearer. Change-Id: Iac77a1e790a7256766f83a24d2a243c880d875f4 Reviewed-by: Jędrzej Nowacki --- src/plugins/platforms/xcb/qxcbconnection_screens.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp index fe9e0be86d..1f44366aa0 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp @@ -208,7 +208,7 @@ void QXcbConnection::updateScreen(QXcbScreen *screen, const xcb_randr_output_cha const int idx = m_screens.indexOf(screen); if (idx > 0) { qAsConst(m_screens).first()->setPrimary(false); - m_screens.swap(0, idx); + m_screens.swapItemsAt(0, idx); } screen->virtualDesktop()->setPrimaryScreen(screen); QXcbIntegration::instance()->setPrimaryScreen(screen); @@ -260,7 +260,7 @@ void QXcbConnection::destroyScreen(QXcbScreen *screen) newPrimary->setPrimary(true); const int idx = m_screens.indexOf(newPrimary); if (idx > 0) - m_screens.swap(0, idx); + m_screens.swapItemsAt(0, idx); QXcbIntegration::instance()->setPrimaryScreen(newPrimary); } -- cgit v1.2.3 From b82559244e2dc03f1ceff66bb67630df4300dc7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 30 Nov 2018 14:51:18 +0100 Subject: macOS: Account for LC_BUILD_VERSION when checking SDK version and deployment target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The more modern LC_BUILD_VERSION load command was introduced in the 10.13 SDK to unify the various versions of the LC_*_VERSION_MIN command. When building with a deployment target of 10.14, the linker will use this load command instead. Change-Id: Ic3571fdbfdf4dfb9346128c6f6e75d1e06f86cd2 Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qcocoahelpers.mm | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 36841c77ab..d86e935788 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -402,23 +402,30 @@ QOperatingSystemVersion QMacVersion::currentRuntime() QMacVersion::VersionTuple QMacVersion::versionsForImage(const mach_header *machHeader) { + static auto makeVersionTuple = [](uint32_t dt, uint32_t sdk) { + return qMakePair( + QOperatingSystemVersion(QOperatingSystemVersion::MacOS, + dt >> 16 & 0xffff, dt >> 8 & 0xff, dt & 0xff), + QOperatingSystemVersion(QOperatingSystemVersion::MacOS, + sdk >> 16 & 0xffff, sdk >> 8 & 0xff, sdk & 0xff) + ); + }; + auto commandCursor = uintptr_t(machHeader) + sizeof(mach_header_64); for (uint32_t i = 0; i < machHeader->ncmds; ++i) { load_command *loadCommand = reinterpret_cast(commandCursor); if (loadCommand->cmd == LC_VERSION_MIN_MACOSX) { auto versionCommand = reinterpret_cast(loadCommand); - uint32_t dt = versionCommand->version; // Deployment target - uint32_t sdk = versionCommand->sdk; // Build SDK - return qMakePair( - QOperatingSystemVersion(QOperatingSystemVersion::MacOS, - dt >> 16 & 0xffff, dt >> 8 & 0xff, dt & 0xff), - QOperatingSystemVersion(QOperatingSystemVersion::MacOS, - sdk >> 16 & 0xffff, sdk >> 8 & 0xff, sdk & 0xff) - ); + return makeVersionTuple(versionCommand->version, versionCommand->sdk); +#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_13) + } else if (loadCommand->cmd == LC_BUILD_VERSION) { + auto versionCommand = reinterpret_cast(loadCommand); + return makeVersionTuple(versionCommand->minos, versionCommand->sdk); +#endif } commandCursor += loadCommand->cmdsize; } - Q_ASSERT_X(false, "QCocoaIntegration", "Could not find version-min load command"); + Q_ASSERT_X(false, "QCocoaIntegration", "Could not find any version load command"); Q_UNREACHABLE(); } -- cgit v1.2.3 From 97d8be10cd97cf997286ed0ca0a5d8b360fa942e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Vr=C3=A1til?= Date: Sat, 1 Dec 2018 17:56:41 +0100 Subject: MySQL: Free the results when QSqlQuery::finished() is called Calling mysql_stmt_free_result() frees the results of the last executed query while keeping the prepared statement valid. This allows to keep around prepared QSqlQueries without the overhead of keeping all the results in memory. Change-Id: I4589e90857cc4e9a6f9612799bfca967a67e2ab2 Reviewed-by: Thiago Macieira Reviewed-by: Andy Shaw --- src/plugins/sqldrivers/mysql/qsql_mysql.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp index f2ae3fbc47..80c0c9c522 100644 --- a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp +++ b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp @@ -197,6 +197,7 @@ protected: QSqlRecord record() const override; void virtual_hook(int id, void *data) override; bool nextResult() override; + void detachFromResultSet() override; #if MYSQL_VERSION_ID >= 40108 bool prepare(const QString &stmt) override; @@ -804,6 +805,15 @@ int QMYSQLResult::numRowsAffected() return d->rowsAffected; } +void QMYSQLResult::detachFromResultSet() +{ + Q_D(QMYSQLResult); + + if (d->preparedQuery) { + mysql_stmt_free_result(d->stmt); + } +} + QVariant QMYSQLResult::lastInsertId() const { Q_D(const QMYSQLResult); -- cgit v1.2.3 From e61028281f44b0434c8e792235417cae3d1f49b0 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Wed, 21 Nov 2018 10:11:13 +0100 Subject: macOS accessibility: Rename parentElement to accessibilityParent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The NSAccessibility protocol has a property accessibilityParent. This adds the implementation. The protocol will be adopted in a follow-up commit. Change-Id: I648cdc201950159e8268743a7fcdd24beb58c1c6 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index f9a03e5b58..f82662bdcb 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -241,7 +241,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of return [attributes autorelease]; } -- (id)parentElement { +- (id)accessibilityParent { QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); if (!iface || !iface->isValid()) return nil; @@ -254,7 +254,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of if (QAccessibleInterface *parent = iface->parent()) { if (parent->role() != QAccessible::Application) { QAccessible::Id parentId = QAccessible::uniqueId(parent); - return [QMacAccessibilityElement elementWithId: parentId]; + return NSAccessibilityUnignoredAncestor([QMacAccessibilityElement elementWithId: parentId]); } } @@ -262,13 +262,12 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of QPlatformWindow *platformWindow = window->handle(); if (platformWindow) { QCocoaWindow *win = static_cast(platformWindow); - return qnsview_cast(win->view()); + return NSAccessibilityUnignoredAncestor(qnsview_cast(win->view())); } } return nil; } - - (id) minValueAttribute:(QAccessibleInterface*)iface { if (QAccessibleValueInterface *val = iface->valueInterface()) return @(val->minimumValue().toDouble()); @@ -301,13 +300,13 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of id focusedElement = [NSApp accessibilityAttributeValue:NSAccessibilityFocusedUIElementAttribute]; return @([focusedElement isEqual:self]); } else if ([attribute isEqualToString:NSAccessibilityParentAttribute]) { - return NSAccessibilityUnignoredAncestor([self parentElement]); + return self.accessibilityParent; } else if ([attribute isEqualToString:NSAccessibilityWindowAttribute]) { // We're in the same window as our parent. - return [[self parentElement] accessibilityAttributeValue:NSAccessibilityWindowAttribute]; + return [[self accessibilityParent] accessibilityAttributeValue:NSAccessibilityWindowAttribute]; } else if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute]) { // We're in the same top level element as our parent. - return [[self parentElement] accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute]; + return [[self accessibilityParent] accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute]; } else if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) { // The position in points of the element's lower-left corner in screen-relative coordinates QPointF qtPosition = QRectF(iface->rect()).bottomLeft(); -- cgit v1.2.3 From f184f1a4817f868bd17280c95b4117f48c9b4c23 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Mon, 3 Dec 2018 20:49:06 +0100 Subject: Windows QPA: Fix QDockWindow Drag & Drop Pointer messages should not be handled when we are inside a move/resize modal loop. DefWindowProc() should handle this case instead. Fixes: QTBUG-72078 Change-Id: I5ad7283bcf0cfe0ff7d21cf5640270c361b8ad8d Reviewed-by: Friedemann Kleint --- .../platforms/windows/qwindowspointerhandler.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 0bac382a90..14559d726a 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -187,6 +187,12 @@ static bool draggingActive() bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result) { *result = 0; + + // If we are inside the move/resize modal loop, let DefWindowProc() handle it (but process NC button release). + QWindowsWindow *platformWindow = static_cast(window->handle()); + if (msg.message != WM_NCPOINTERUP && platformWindow->testFlag(QWindowsWindow::ResizeMoveActive)) + return false; + const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam); POINTER_INPUT_TYPE pointerType; @@ -195,6 +201,18 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q return false; } + // Handle non-client pen/touch as generic mouse events for compatibility with QDockWindow. + if ((pointerType == QT_PT_TOUCH || pointerType == QT_PT_PEN) && (et & QtWindows::NonClientEventFlag)) { + POINTER_INFO pointerInfo; + if (!QWindowsContext::user32dll.getPointerInfo(pointerId, &pointerInfo)) { + qWarning() << "GetPointerInfo() failed:" << qt_error_string(); + return false; + } + if (pointerInfo.pointerFlags & (POINTER_FLAG_UP | POINTER_FLAG_DOWN)) + return translateMouseTouchPadEvent(window, hwnd, et, msg, &pointerInfo); + return false; + } + switch (pointerType) { case QT_PT_POINTER: case QT_PT_MOUSE: -- cgit v1.2.3 From ec31953007126a6e0f9f3ca16b64bdfdcdf3d7b6 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 21 Nov 2018 11:25:57 -0800 Subject: Fix build using Windows SDK 10.0.17763 c:\qt\qt5\qtbase\src\3rdparty\libjpeg\src\jmorecfg.h(242): error C2371: 'boolean': redefinition; different basic types c:\program files (x86)\windows kits\10\include\10.0.17763.0\shared\rpcndr.h(193): note: see declaration of 'boolean' Instead of trying to guess if a certain header has been #included and whether that header does typedef something to boolean, let's just use the preprocessor to hide, like some people do for X11/Xlib.h's Bool (see qmetatype.h where we refused). Change-Id: I05b8d7ba19004af99f3cfffd15693a87e175f05d Reviewed-by: Eirik Aavitsland --- src/plugins/imageformats/jpeg/qjpeghandler.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp index e52a19703c..54fe857908 100644 --- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp +++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp @@ -56,13 +56,12 @@ // including jpeglib.h seems to be a little messy extern "C" { -// mingw includes rpcndr.h but does not define boolean -#if defined(Q_OS_WIN) && defined(Q_CC_GNU) -# if defined(__RPCNDR_H__) && !defined(boolean) - typedef unsigned char boolean; -# define HAVE_BOOLEAN -# endif +// jpeglib.h->jmorecfg.h tries to typedef int boolean; but this conflicts with +// some Windows headers that may or may not have been included +#ifdef HAVE_BOOLEAN +# undef HAVE_BOOLEAN #endif +#define boolean jboolean #define XMD_H // shut JPEGlib up #include -- cgit v1.2.3 From 3ee7aa72b78d892153439b668aa9f0a786d9f70e Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 21 Dec 2017 18:26:22 +0100 Subject: configure: atomize xcb-* tests properly xcb is a dependency which should be detected upfront. same for xlib. this also removes calls to functions coming from the dependencies from the tests (both because these calls prove nothing, and because at some point we will stop linking transitive deps). Change-Id: Iac77305eab33ea8ff5c71302cef980eb908d8403 Reviewed-by: Gatis Paeglis --- src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro index acbd1cc785..6b55918f03 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro @@ -8,7 +8,7 @@ DEFINES += QT_EGL_NO_X11 INCLUDEPATH += $$PWD/../../api CONFIG += egl -QMAKE_USE += xcb_xlib +QMAKE_USE += xcb_xlib xcb xlib SOURCES += $$PWD/qeglfsx11main.cpp \ $$PWD/qeglfsx11integration.cpp -- cgit v1.2.3 From 501ff0a18cff37cf0d237cd2b04b35fff1bd0837 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 21 Dec 2017 20:33:20 +0100 Subject: untangle the egl-x11 relationship in the build system egl-x11 is used in two places: - the eglfs-x11 plugin, which has a hard dependency on xcb-xlib - the xcb-egl plugin, which has a soft dependency on xcb-xlib that means that the egl-x11 configure test needs to be untangled from xcb, and that eglfs-x11 should be a separate feature with a proper dependency declaration. when the plugins that need egl-x11 are not built, it also makes no sense to build the respective integration in the egl_support module (even if it's possible to coax it into building), so adjust things accordingly. Change-Id: Ic729d0b7c893dd00844567329205c24ea2703033 Reviewed-by: Gatis Paeglis --- src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro b/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro index 919ecd01f6..360536d22f 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro +++ b/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro @@ -1,7 +1,7 @@ TEMPLATE = subdirs QT_FOR_CONFIG += gui-private -qtConfig(egl_x11): SUBDIRS += eglfs_x11 +qtConfig(eglfs_x11): SUBDIRS += eglfs_x11 qtConfig(eglfs_gbm): SUBDIRS *= eglfs_kms_support eglfs_kms qtConfig(eglfs_egldevice): SUBDIRS *= eglfs_kms_support eglfs_kms_egldevice qtConfig(eglfs_vsp2): SUBDIRS += eglfs_kms_vsp2 -- cgit v1.2.3 From 161c5693143783e0364d32c587497669747efc45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 6 Dec 2018 14:46:26 +0100 Subject: macOS: Reset font glyph caches when application theme changes Our glyph caches on 10.14 are based on the application appearance, so when the application goes from dark to light or light to dark, we need to reset and re-populate the glyph-caches to account for the new appearance. Change-Id: If019d8cfa33ffb2b14747444b2ff74b288992f55 Fixes: QTBUG-71018 Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qcocoatheme.mm | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index a2229159b5..240deeddbd 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -53,11 +53,13 @@ #include "qcocoahelpers.h" #include +#include #include #include #include #include #include +#include #include #include #include @@ -162,6 +164,11 @@ void QCocoaTheme::handleSystemThemeChange() m_systemPalette = qt_mac_createSystemPalette(); m_palettes = qt_mac_createRolePalettes(); + if (QCoreTextFontEngine::fontSmoothing() == QCoreTextFontEngine::FontSmoothing::Grayscale) { + // Re-populate glyph caches based on the new appearance's assumed text fill color + QFontCache::instance()->clear(); + } + QWindowSystemInterface::handleThemeChange(nullptr); } -- cgit v1.2.3 From ed90c306f2033eec4a6ac3aa356b2ea41e601160 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Tue, 4 Dec 2018 10:36:44 +0100 Subject: Fix addition of the wasm platform plugin Add the plugin; do not replace the whole SUBDIRS value. Fixes: QTBUG-70375 Change-Id: Id40a69f54dfde5eb88894323c7e1146b6cad5a75 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/platforms.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro index 5bf2b77421..db2a31d1a5 100644 --- a/src/plugins/platforms/platforms.pro +++ b/src/plugins/platforms/platforms.pro @@ -46,7 +46,7 @@ haiku { SUBDIRS += haiku } -wasm: SUBDIRS = wasm +wasm: SUBDIRS += wasm qtConfig(mirclient): SUBDIRS += mirclient -- cgit v1.2.3 From 3464e1e5c7b5b01ae13c99e3529dd02af1d36958 Mon Sep 17 00:00:00 2001 From: Sergio Martins Date: Wed, 5 Dec 2018 19:48:05 +0000 Subject: Add a few qAsConst() to range-for to prevent detachments places indicated by clazy As a drive-by, fixed minor styling issues in the affected lines. Change-Id: I88d3fc0c8573cde0e61f19a18dd9ea697ee40c34 Reviewed-by: Thiago Macieira Reviewed-by: Luca Beldi Reviewed-by: Friedemann Kleint --- src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp | 4 ++-- src/plugins/generic/tuiotouch/qtuiohandler.cpp | 10 +++++----- .../eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp | 2 +- src/plugins/platforms/vnc/qvnc.cpp | 10 ++++------ src/plugins/platforms/vnc/qvncscreen.cpp | 2 +- src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | 6 +++--- 6 files changed, 16 insertions(+), 18 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp index 543e66491d..e74b1cf744 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp @@ -465,7 +465,7 @@ void QNetworkManagerEngine::newConnection(const QDBusObjectPath &path, cpPriv->state |= QNetworkConfiguration::Active; if (deviceType == DEVICE_TYPE_ETHERNET) { - for (const auto *interfaceDevice : interfaceDevices) { + for (auto interfaceDevice : qAsConst(interfaceDevices)) { if (interfaceDevice->deviceType() == deviceType) { auto *wiredDevice = wiredDevices.value(interfaceDevice->path()); if (wiredDevice && wiredDevice->carrier()) { @@ -716,7 +716,7 @@ QNetworkSession::State QNetworkManagerEngine::sessionStateForId(const QString &i if (!ptr->isValid) return QNetworkSession::Invalid; - for (QNetworkManagerConnectionActive *activeConnection : activeConnectionsList) { + for (QNetworkManagerConnectionActive *activeConnection : qAsConst(activeConnectionsList)) { const QString identifier = activeConnection->connection().path(); if (id == identifier) { diff --git a/src/plugins/generic/tuiotouch/qtuiohandler.cpp b/src/plugins/generic/tuiotouch/qtuiohandler.cpp index bb18ba5085..cb82672acd 100644 --- a/src/plugins/generic/tuiotouch/qtuiohandler.cpp +++ b/src/plugins/generic/tuiotouch/qtuiohandler.cpp @@ -169,7 +169,7 @@ void QTuioHandler::processPackets() messages.push_back(msg); } - for (const QOscMessage &message : messages) { + for (const QOscMessage &message : qAsConst(messages)) { if (message.addressPattern() == "/tuio/2Dcur") { QList arguments = message.arguments(); if (arguments.count() == 0) { @@ -368,12 +368,12 @@ void QTuioHandler::process2DCurFseq(const QOscMessage &message) QList tpl; tpl.reserve(m_activeCursors.size() + m_deadCursors.size()); - for (const QTuioCursor &tc : m_activeCursors) { + for (const QTuioCursor &tc : qAsConst(m_activeCursors)) { QWindowSystemInterface::TouchPoint tp = cursorToTouchPoint(tc, win); tpl.append(tp); } - for (const QTuioCursor &tc : m_deadCursors) { + for (const QTuioCursor &tc : qAsConst(m_deadCursors)) { QWindowSystemInterface::TouchPoint tp = cursorToTouchPoint(tc, win); tp.state = Qt::TouchPointReleased; tpl.append(tp); @@ -542,12 +542,12 @@ void QTuioHandler::process2DObjFseq(const QOscMessage &message) QList tpl; tpl.reserve(m_activeTokens.size() + m_deadTokens.size()); - for (const QTuioToken & t : m_activeTokens) { + for (const QTuioToken & t : qAsConst(m_activeTokens)) { QWindowSystemInterface::TouchPoint tp = tokenToTouchPoint(t, win); tpl.append(tp); } - for (const QTuioToken & t : m_deadTokens) { + for (const QTuioToken & t : qAsConst(m_deadTokens)) { QWindowSystemInterface::TouchPoint tp = tokenToTouchPoint(t, win); tp.state = Qt::TouchPointReleased; tp.velocity = QVector2D(); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp index 24f82e7843..24051c352e 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp @@ -423,7 +423,7 @@ void QEglFSKmsGbmScreen::updateFlipStatus() if (m_flipPending) return; - for (const CloneDestination &d : m_cloneDests) { + for (const CloneDestination &d : qAsConst(m_cloneDests)) { if (d.cloneFlipPending) return; } diff --git a/src/plugins/platforms/vnc/qvnc.cpp b/src/plugins/platforms/vnc/qvnc.cpp index ffe00de2b1..32114c6443 100644 --- a/src/plugins/platforms/vnc/qvnc.cpp +++ b/src/plugins/platforms/vnc/qvnc.cpp @@ -600,7 +600,7 @@ void QVncClientCursor::changeCursor(QCursor *widgetCursor, QWindow *window) cursor = *platformImage.image(); hotspot = platformImage.hotspot(); } - for (auto client : clients) + for (auto client : qAsConst(clients)) client->setDirtyCursor(); } @@ -638,16 +638,14 @@ void QVncServer::init() QVncServer::~QVncServer() { - for (auto client : clients) { - delete client; - } + qDeleteAll(clients); } void QVncServer::setDirty() { - for (auto client : clients) { + for (auto client : qAsConst(clients)) client->setDirty(qvnc_screen->dirtyRegion); - } + qvnc_screen->clearDirty(); } diff --git a/src/plugins/platforms/vnc/qvncscreen.cpp b/src/plugins/platforms/vnc/qvncscreen.cpp index 67d33de2f0..2eca18fb4d 100644 --- a/src/plugins/platforms/vnc/qvncscreen.cpp +++ b/src/plugins/platforms/vnc/qvncscreen.cpp @@ -75,7 +75,7 @@ bool QVncScreen::initialize() mDepth = 32; mPhysicalSize = QSizeF(mGeometry.width()/96.*25.4, mGeometry.height()/96.*25.4); - for (const QString &arg : mArgs) { + for (const QString &arg : qAsConst(mArgs)) { QRegularExpressionMatch match; if (arg.contains(mmSizeRx, &match)) { mPhysicalSize = QSizeF(match.captured("width").toDouble(), match.captured("height").toDouble()); diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 04ddd3c98c..78ef7760af 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -637,7 +637,7 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo qreal nx = -1.0, ny = -1.0; qreal w = 0.0, h = 0.0; bool majorAxisIsY = touchPoint.area.height() > touchPoint.area.width(); - for (const TouchDeviceData::ValuatorClassInfo vci : dev->valuatorInfo) { + for (const TouchDeviceData::ValuatorClassInfo &vci : qAsConst(dev->valuatorInfo)) { double value; if (!xi2GetValuatorValueIfSet(xiDeviceEvent, vci.number, &value)) continue; @@ -823,7 +823,7 @@ bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab) | XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE | XCB_INPUT_XI_EVENT_MASK_TOUCH_END; - for (int id : m_xiMasterPointerIds) { + for (int id : qAsConst(m_xiMasterPointerIds)) { xcb_generic_error_t *error = nullptr; auto cookie = xcb_input_xi_grab_device(xcb_connection(), w, XCB_CURRENT_TIME, XCB_CURSOR_NONE, id, XCB_INPUT_GRAB_MODE_22_ASYNC, XCB_INPUT_GRAB_MODE_22_ASYNC, @@ -841,7 +841,7 @@ bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab) free(reply); } } else { // ungrab - for (int id : m_xiMasterPointerIds) { + for (int id : qAsConst(m_xiMasterPointerIds)) { auto cookie = xcb_input_xi_ungrab_device_checked(xcb_connection(), XCB_CURRENT_TIME, id); xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie); if (error) { -- cgit v1.2.3 From 19d7bd3d638c8962343927a161ce3f1cfdcb3e6a Mon Sep 17 00:00:00 2001 From: Sergio Martins Date: Thu, 29 Nov 2018 13:23:00 +0000 Subject: Fix a couple of unused QStrings This is needed so we can add Q_WARN_UNUSED to QString. The xcb one might even be a bug. Change-Id: Ia2d2563bdd10aa747014410df4990597969f4634 Reviewed-by: Gatis Paeglis Reviewed-by: Andy Shaw --- src/plugins/platforms/xcb/qxcbnativeinterface.cpp | 2 +- src/plugins/sqldrivers/odbc/qsql_odbc.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 524af5a2a7..4d526a6bda 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -304,7 +304,7 @@ QPlatformNativeInterface::NativeResourceForWindowFunction QXcbNativeInterface::n QPlatformNativeInterface::NativeResourceForBackingStoreFunction QXcbNativeInterface::nativeResourceFunctionForBackingStore(const QByteArray &resource) { const QByteArray lowerCaseResource = resource.toLower(); - NativeResourceForBackingStoreFunction func = handlerNativeResourceFunctionForBackingStore(resource); + NativeResourceForBackingStoreFunction func = handlerNativeResourceFunctionForBackingStore(lowerCaseResource); return func; } diff --git a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp index 1fbbcd0ef1..7f98efccba 100644 --- a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp +++ b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp @@ -345,7 +345,7 @@ static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, { int nativeCode = -1; QString message = qODBCWarn(p, &nativeCode); - return QSqlError(QLatin1String("QODBC3: ") + err, qODBCWarn(p), type, + return QSqlError(QLatin1String("QODBC3: ") + err, message, type, nativeCode != -1 ? QString::number(nativeCode) : QString()); } -- cgit v1.2.3 From 177577932e89772ef7ab281dd5771d5c66ad3a93 Mon Sep 17 00:00:00 2001 From: Ivan Komissarov Date: Sun, 21 Oct 2018 16:01:26 +0200 Subject: qwindowsxpstyle: Add std::nothrow to new There is no sense in testing the 'buf' pointer against null, as the memory was allocated using the throwing 'new' operator. However, since this function already can fail in other cases, the 'buf' pointer can be checked for nullptr after the nothrow new. Task-number: QTBUG-71156 Change-Id: Ibca5d672544d3980dd8890474e3e2fbf7443e05d Reviewed-by: Thiago Macieira --- src/plugins/styles/windowsvista/qwindowsxpstyle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp index 4b583e13d3..43e8b37f71 100644 --- a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp @@ -511,8 +511,8 @@ QRegion QWindowsXPStylePrivate::region(XPThemeData &themeData) if (numBytes == 0) return QRegion(); - char *buf = new char[numBytes]; - if (buf == 0) + char *buf = new (std::nothrow) char[numBytes]; + if (!buf) return QRegion(); RGNDATA *rd = reinterpret_cast(buf); -- cgit v1.2.3 From 6b52c1834daec628bab5a384e1dfd039937b375d Mon Sep 17 00:00:00 2001 From: "R.J.V. Bertin" Date: Wed, 5 Dec 2018 18:47:47 +0100 Subject: Offscreen QPA: use a CoreText font database on macOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without this applications using the Offscreen QPA don't have access to any fonts on macOS and thus cannot render text correctly. Task-number: QTBUG-72335 Change-Id: I8e58c066365d0231d0993ad3b480d957a32f7f7b Reviewed-by: Tor Arne Vestbø Reviewed-by: Allan Sandfeld Jensen Reviewed-by: Friedemann Kleint --- src/plugins/platforms/offscreen/qoffscreenintegration.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp index 01cd254501..9815be16a3 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp +++ b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp @@ -45,6 +45,7 @@ #include #if defined(Q_OS_MAC) #include +#include #else #include #endif @@ -67,6 +68,8 @@ QT_BEGIN_NAMESPACE +class QCoreTextFontEngine; + template class QOffscreenEventDispatcher : public BaseEventDispatcher { @@ -101,7 +104,7 @@ QOffscreenIntegration::QOffscreenIntegration() { #if defined(Q_OS_UNIX) #if defined(Q_OS_MAC) - m_fontDatabase.reset(new QPlatformFontDatabase()); + m_fontDatabase.reset(new QCoreTextFontDatabaseEngineFactory); #else m_fontDatabase.reset(new QGenericUnixFontDatabase()); #endif -- cgit v1.2.3 From e2093219665b02e9ac2a416412a371aeb60c7750 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 16 Oct 2018 15:29:58 +0200 Subject: Use Q_DISABLE_COPY_MOVE for private classes Change-Id: I3cfcfba892ff4a0ab4e31f308620b445162bb17b Reviewed-by: Giuseppe D'Angelo --- src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h | 2 +- src/plugins/platforms/xcb/qxcbsessionmanager.h | 2 -- src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h | 2 +- src/plugins/printsupport/cups/qcupsprintengine_p.h | 4 ++-- src/plugins/printsupport/windows/qwindowsprintersupport.h | 2 +- src/plugins/styles/android/qandroidstyle_p.h | 2 +- src/plugins/styles/mac/qmacstyle_mac_p.h | 2 +- src/plugins/styles/windowsvista/qwindowsvistastyle_p.h | 2 +- src/plugins/styles/windowsvista/qwindowsxpstyle_p.h | 2 +- 9 files changed, 9 insertions(+), 11 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h index 9b01c0a3fc..bc82351283 100644 --- a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h +++ b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h @@ -116,7 +116,7 @@ protected: friend GC qt_x11_get_brush_gc(QPainter *); private: - Q_DISABLE_COPY(QX11PaintEngine) + Q_DISABLE_COPY_MOVE(QX11PaintEngine) }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbsessionmanager.h b/src/plugins/platforms/xcb/qxcbsessionmanager.h index 0ad9445361..79c587b38d 100644 --- a/src/plugins/platforms/xcb/qxcbsessionmanager.h +++ b/src/plugins/platforms/xcb/qxcbsessionmanager.h @@ -85,8 +85,6 @@ public: private: QEventLoop *m_eventLoop; - - Q_DISABLE_COPY(QXcbSessionManager) }; QT_END_NAMESPACE diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h index b72e676419..2be88bb4c0 100644 --- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h +++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h @@ -82,7 +82,7 @@ public: private: QScopedPointer d_ptr; - Q_DISABLE_COPY(QXdgDesktopPortalTheme) + Q_DISABLE_COPY_MOVE(QXdgDesktopPortalTheme) }; QT_END_NAMESPACE diff --git a/src/plugins/printsupport/cups/qcupsprintengine_p.h b/src/plugins/printsupport/cups/qcupsprintengine_p.h index 2a1a83b9d7..c021b0c643 100644 --- a/src/plugins/printsupport/cups/qcupsprintengine_p.h +++ b/src/plugins/printsupport/cups/qcupsprintengine_p.h @@ -77,7 +77,7 @@ public: // end reimplementations QPdfPrintEngine private: - Q_DISABLE_COPY(QCupsPrintEngine) + Q_DISABLE_COPY_MOVE(QCupsPrintEngine) }; class QCupsPrintEnginePrivate : public QPdfPrintEnginePrivate @@ -91,7 +91,7 @@ public: void closePrintDevice() override; private: - Q_DISABLE_COPY(QCupsPrintEnginePrivate) + Q_DISABLE_COPY_MOVE(QCupsPrintEnginePrivate) void changePrinter(const QString &newPrinter); void setPageSize(const QPageSize &pageSize); diff --git a/src/plugins/printsupport/windows/qwindowsprintersupport.h b/src/plugins/printsupport/windows/qwindowsprintersupport.h index 4267701145..400701628e 100644 --- a/src/plugins/printsupport/windows/qwindowsprintersupport.h +++ b/src/plugins/printsupport/windows/qwindowsprintersupport.h @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE class QWindowsPrinterSupport : public QPlatformPrinterSupport { - Q_DISABLE_COPY(QWindowsPrinterSupport) + Q_DISABLE_COPY_MOVE(QWindowsPrinterSupport) public: QWindowsPrinterSupport(); ~QWindowsPrinterSupport() override; diff --git a/src/plugins/styles/android/qandroidstyle_p.h b/src/plugins/styles/android/qandroidstyle_p.h index 3faa08afb9..6cb30a2f79 100644 --- a/src/plugins/styles/android/qandroidstyle_p.h +++ b/src/plugins/styles/android/qandroidstyle_p.h @@ -371,7 +371,7 @@ public: void unpolish(QWidget *widget); private: - Q_DISABLE_COPY(QAndroidStyle) + Q_DISABLE_COPY_MOVE(QAndroidStyle) static ItemType qtControl(QStyle::ComplexControl control); static ItemType qtControl(QStyle::ContentsType contentsType); static ItemType qtControl(QStyle::ControlElement controlElement); diff --git a/src/plugins/styles/mac/qmacstyle_mac_p.h b/src/plugins/styles/mac/qmacstyle_mac_p.h index d6874001d3..88f104cccf 100644 --- a/src/plugins/styles/mac/qmacstyle_mac_p.h +++ b/src/plugins/styles/mac/qmacstyle_mac_p.h @@ -115,7 +115,7 @@ public: const QWidget *widget = 0) const; private: - Q_DISABLE_COPY(QMacStyle) + Q_DISABLE_COPY_MOVE(QMacStyle) Q_DECLARE_PRIVATE(QMacStyle) }; diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle_p.h b/src/plugins/styles/windowsvista/qwindowsvistastyle_p.h index 0ebb0eb41a..43a2a670f8 100644 --- a/src/plugins/styles/windowsvista/qwindowsvistastyle_p.h +++ b/src/plugins/styles/windowsvista/qwindowsvistastyle_p.h @@ -99,7 +99,7 @@ public: QPalette standardPalette() const override; private: - Q_DISABLE_COPY(QWindowsVistaStyle) + Q_DISABLE_COPY_MOVE(QWindowsVistaStyle) Q_DECLARE_PRIVATE(QWindowsVistaStyle) friend class QStyleFactory; }; diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle_p.h b/src/plugins/styles/windowsvista/qwindowsxpstyle_p.h index 7e9f4ddda6..0f70105b0e 100644 --- a/src/plugins/styles/windowsvista/qwindowsxpstyle_p.h +++ b/src/plugins/styles/windowsvista/qwindowsxpstyle_p.h @@ -96,7 +96,7 @@ public: const QWidget *widget = nullptr) const override; private: - Q_DISABLE_COPY(QWindowsXPStyle) + Q_DISABLE_COPY_MOVE(QWindowsXPStyle) Q_DECLARE_PRIVATE(QWindowsXPStyle) friend class QStyleFactory; }; -- cgit v1.2.3 From 384b9d8fedd3c32b4a8d05740cc1c4bd73e171d8 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Wed, 21 Nov 2018 11:30:37 +0100 Subject: macOS accessibility: Implement accessibilityFrame MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id78d3826eb18ff5ca306ac190543a7ff37b2f014 Reviewed-by: Tor Arne Vestbø Reviewed-by: Jan Arve Sæther --- src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index f82662bdcb..38a402fb2f 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -268,6 +268,13 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of return nil; } +- (NSRect)accessibilityFrame { + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + if (!iface || !iface->isValid()) + return NSZeroRect; + return QCocoaScreen::mapToNative(iface->rect()); +} + - (id) minValueAttribute:(QAccessibleInterface*)iface { if (QAccessibleValueInterface *val = iface->valueInterface()) return @(val->minimumValue().toDouble()); -- cgit v1.2.3 From bc997b856aa7b0b2137b568cd3fc6f190cd89f84 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Wed, 12 Dec 2018 15:42:40 +0100 Subject: Windows QPA: Fix touch message queue handling In the handling of pointer messages for touchscreen we use a queue that is flushed when mouse messages synthesized by Windows are received. However, these fake mouse messages should be otherwise ignored. Their handling was causing issues with PointHandler in QtQuick. This change fixes the part of QTBUG-71431 that causes a single touch drag to behave unexpectedly with PointHandler. Task-number: QTBUG-71431 Change-Id: Iccdd554876f411bce2dd1f922a3d889e61b7bb1c Reviewed-by: Miguel Costa --- src/plugins/platforms/windows/qwindowspointerhandler.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 7935d0c36f..3534f06971 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -641,6 +641,7 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, // Only the primary pointer will generate mouse messages. enqueueTouchEvent(window, touchPoints, QWindowsKeyMapper::queryKeyboardModifiers()); } else { + flushTouchEvents(m_touchDevice); QWindowSystemInterface::handleTouchEvent(window, m_touchDevice, touchPoints, QWindowsKeyMapper::queryKeyboardModifiers()); } @@ -766,6 +767,13 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW if (et != QtWindows::MouseWheelEvent && msg.message != WM_MOUSELEAVE && msg.message != WM_MOUSEMOVE) return false; + // Ignore messages synthesized from touch/pen (only use them for flushing queues). + const quint64 signatureMask = 0xffffff00; + const quint64 miWpSignature = 0xff515700; + const quint64 extraInfo = quint64(GetMessageExtraInfo()); + if ((extraInfo & signatureMask) == miWpSignature) + return false; + const QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)); QPoint localPos; QPoint globalPos; -- cgit v1.2.3 From e80bf655e922e9864f8843b5e7bbb47019a6d95a Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 7 Dec 2017 19:30:07 +0100 Subject: configure: verify header presence against sources in addition to the actual library resolution, also resolve the headers belonging to the library, to validate the include path, and possibly ensure that the right version of the library is present. the "include" entries were moved out of the "test" objects, and renamed to "headers". this cleanly permits libraries without compile tests. the headers were not put into the sources, because the variance among the includes is generally orthogonal to the variance among the libraries. note that this - like the library resolution - provides no support for darwin frameworks. consequently, the opengl libraries are excluded from the conversion on darwin. similarly, wasm is excluded (centrally), because emcc is magic and would need advanced wizardry to be dealt with. Change-Id: Ib390c75371efa2badcfec9b74274047ce67c3e5a Reviewed-by: Joerg Bornemann Reviewed-by: Paul Wicking --- src/plugins/sqldrivers/configure.json | 33 ++++++++++++++------------------- src/plugins/sqldrivers/configure.pri | 4 ++-- 2 files changed, 16 insertions(+), 21 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/sqldrivers/configure.json b/src/plugins/sqldrivers/configure.json index 4802d3b04d..cd20eef1df 100644 --- a/src/plugins/sqldrivers/configure.json +++ b/src/plugins/sqldrivers/configure.json @@ -39,9 +39,8 @@ "libraries": { "db2": { "label": "DB2 (IBM)", - "test": { - "include": [ "sqlcli.h", "sqlcli1.h" ] - }, + "test": {}, + "headers": [ "sqlcli.h", "sqlcli1.h" ], "sources": [ { "libs": "-ldb2cli", "condition": "config.win32" }, { "libs": "-ldb2", "condition": "!config.win32" } @@ -49,9 +48,8 @@ }, "ibase": { "label": "InterBase", - "test": { - "include": "ibase.h" - }, + "test": {}, + "headers": "ibase.h", "sources": [ { "libs": "-lgds32_ms", "condition": "config.win32" }, { "libs": "-lgds", "condition": "!config.win32" } @@ -65,9 +63,9 @@ "# include ", "#endif" ], - "include": "mysql.h", "main": "mysql_get_client_version();" }, + "headers": "mysql.h", "sources": [ { "type": "mysqlConfig", "query": "--libs_r", "cleanlibs": true }, { "type": "mysqlConfig", "query": "--libs", "cleanlibs": true }, @@ -81,12 +79,12 @@ "psql": { "label": "PostgreSQL", "test": { - "include": "libpq-fe.h", "main": [ "PQescapeBytea(0, 0, 0);", "PQunescapeBytea(0, 0);" ] }, + "headers": "libpq-fe.h", "sources": [ { "type": "pkgConfig", "args": "libpq" }, { "type": "psqlConfig" }, @@ -96,9 +94,8 @@ }, "tds": { "label": "TDS (Sybase)", - "test": { - "include": [ "sybfront.h", "sybdb.h" ] - }, + "test": {}, + "headers": [ "sybfront.h", "sybdb.h" ], "sources": [ { "type": "sybaseEnv", "libs": "-lNTWDBLIB", "condition": "config.win32" }, { "type": "sybaseEnv", "libs": "-lsybdb", "condition": "!config.win32" } @@ -106,9 +103,8 @@ }, "oci": { "label": "OCI (Oracle)", - "test": { - "include": "oci.h" - }, + "test": {}, + "headers": "oci.h", "sources": [ { "libs": "-loci", "condition": "config.win32" }, { "libs": "-lclntsh", "condition": "!config.win32" } @@ -122,12 +118,12 @@ "# include ", "#endif" ], - "include": [ "sql.h", "sqlext.h" ], "main": [ "SQLHANDLE env;", "SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);" ] }, + "headers": [ "sql.h", "sqlext.h" ], "sources": [ { "libs": "-lodbc32", "condition": "config.win32" }, { "libs": "-liodbc", "condition": "config.darwin" }, @@ -136,9 +132,8 @@ }, "sqlite2": { "label": "SQLite (version 2)", - "test": { - "include": "sqlite.h" - }, + "test": {}, + "headers": "sqlite.h", "sources": [ "-lsqlite" ] @@ -147,9 +142,9 @@ "label": "SQLite (version 3)", "export": "sqlite", "test": { - "include": "sqlite3.h", "main": "sqlite3_open_v2(0, 0, 0, 0);" }, + "headers": "sqlite3.h", "sources": [ { "type": "pkgConfig", "args": "sqlite3" }, "-lsqlite3" diff --git a/src/plugins/sqldrivers/configure.pri b/src/plugins/sqldrivers/configure.pri index 747a47e7b8..84c8114c7b 100644 --- a/src/plugins/sqldrivers/configure.pri +++ b/src/plugins/sqldrivers/configure.pri @@ -9,7 +9,7 @@ defineTest(qtConfLibrary_psqlConfig) { !qtConfResolvePathLibs($${1}.libs, $$libdir, -lpq): \ return(false) qtRunLoggedCommand("$$pg_config --includedir", includedir)|return(false) - !qtConfResolvePathIncs($${1}.includedir, $$includedir): \ + !qtConfResolvePathIncs($${1}.includedir, $$includedir, $$2): \ return(false) return(true) } @@ -63,7 +63,7 @@ defineTest(qtConfLibrary_mysqlConfig) { includedir = for (id, rawincludedir): \ includedir += $$clean_path($$id) - !qtConfResolvePathIncs($${1}.includedir, $$includedir): \ + !qtConfResolvePathIncs($${1}.includedir, $$includedir, $$2): \ return(false) return(true) } -- cgit v1.2.3 From 582237a593421b3e98470a03f29459d02662e9ec Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Mon, 26 Nov 2018 10:05:15 +1000 Subject: wasm: send mouse release to proper window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the mouse is released, it gets the current window to send the event to from the pointer position. If the release happens out of the browser viewport, that window is null and the release event essentially gets ignored. This change keeps the last known QWindow object to send the event to until the release. Also replace hardcoded emscripten events with enum names. Task-number: QTBUG-71948 Change-Id: I354d14479a43489f210cca31d6b9e0f65d083bb0 Fixes: QTBUG-71948 Reviewed-by: Edward Welbourne Reviewed-by: Mikhail Svetkin Reviewed-by: Morten Johan Sørvig --- .../platforms/wasm/qwasmeventtranslator.cpp | 27 +++++++++++++--------- src/plugins/platforms/wasm/qwasmeventtranslator.h | 1 + 2 files changed, 17 insertions(+), 11 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp index a3fdcd1025..8ab109f03c 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp @@ -63,6 +63,7 @@ EMSCRIPTEN_BINDINGS(mouse_module) { QWasmEventTranslator::QWasmEventTranslator(QObject *parent) : QObject(parent) , draggedWindow(nullptr) + , lastWindow(nullptr) , pressedButtons(Qt::NoButton) , resizeMode(QWasmWindow::ResizeNone) { @@ -370,15 +371,16 @@ void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEven Qt::KeyboardModifiers modifiers = translateMouseEventModifier(mouseEvent); QWindow *window2 = QWasmIntegration::get()->compositor()->windowAt(point, 5); + if (window2 != nullptr) + lastWindow = window2; + QWasmWindow *htmlWindow = static_cast(window2->handle()); - bool onFrame = false; - if (window2 && !window2->geometry().contains(point)) - onFrame = true; - QPoint localPoint(point.x() - window2->geometry().x(), point.y() - window2->geometry().y()); + bool interior = window2 && window2->geometry().contains(point); + QPoint localPoint(point.x() - window2->geometry().x(), point.y() - window2->geometry().y()); switch (eventType) { - case 5: //down + case EMSCRIPTEN_EVENT_MOUSEDOWN: { if (window2) window2->raise(); @@ -403,7 +405,7 @@ void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEven htmlWindow->injectMousePressed(localPoint, point, button, modifiers); break; } - case 6: //up + case EMSCRIPTEN_EVENT_MOUSEUP: { pressedButtons.setFlag(translateMouseButton(mouseEvent->button), false); buttonEventType = QEvent::MouseButtonRelease; @@ -414,7 +416,6 @@ void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEven pressedWindow = nullptr; } - if (mouseEvent->button == 0) { draggedWindow = nullptr; resizeMode = QWasmWindow::ResizeNone; @@ -424,7 +425,7 @@ void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEven oldWindow->injectMouseReleased(localPoint, point, button, modifiers); break; } - case 8://move //drag event + case EMSCRIPTEN_EVENT_MOUSEMOVE: // drag event { buttonEventType = QEvent::MouseMove; if (!(htmlWindow->m_windowState & Qt::WindowFullScreen) && !(htmlWindow->m_windowState & Qt::WindowMaximized)) { @@ -440,11 +441,15 @@ void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEven } break; } - default: + default: // MOUSELEAVE MOUSEENTER break; }; - - if (window2 && !onFrame) { + if (!window2 && buttonEventType == QEvent::MouseButtonRelease) { + window2 = lastWindow; + lastWindow = nullptr; + interior = true; + } + if (window2 && interior) { QWindowSystemInterface::handleMouseEvent( window2, timestamp, localPoint, point, pressedButtons, button, buttonEventType, modifiers); } diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.h b/src/plugins/platforms/wasm/qwasmeventtranslator.h index 11430a57a2..f3dff8e48c 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.h +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.h @@ -197,6 +197,7 @@ private: private: QWindow *draggedWindow; QWindow *pressedWindow; + QWindow *lastWindow; Qt::MouseButtons pressedButtons; QWasmWindow::ResizeMode resizeMode; -- cgit v1.2.3 From 7ec7f338bc7c14cfd68be7d743bbffeb70c5e239 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Sun, 16 Dec 2018 13:12:52 +0100 Subject: XCB plugin: replace deprecated QList::swap() QList::swap(int, int) was deprecated. Replace it with swapItemsAt() Change-Id: I077c5b7222e40b928ee9035b8cbf4ebcc91aa15e Reviewed-by: Lars Knoll --- src/plugins/platforms/xcb/qxcbscreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 57dbdc9bec..0fa0e8cd7b 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -147,7 +147,7 @@ void QXcbVirtualDesktop::setPrimaryScreen(QPlatformScreen *s) { const int idx = m_screens.indexOf(s); Q_ASSERT(idx > -1); - m_screens.swap(0, idx); + m_screens.swapItemsAt(0, idx); } QXcbXSettings *QXcbVirtualDesktop::xSettings() const -- cgit v1.2.3 From 1ef9859e7e0b0d2a88acd287b5b1e4bea8b27ae8 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 12 Dec 2017 12:21:16 +0100 Subject: configure: refactor directx checks properly atomize the libraries and express their dependencies, and adjust the project files accordingly. note that we don't try to use any additional paths, as all SDKs we currently support have built-in directx 11 support: - msvc2013 comes with win sdk 8.1; that is also used for win7 targets - mingw-64 5.3 (though this one is missing fxc, which is why the code path for using an external sdk for that remains) Change-Id: Ib44e389ef46567308293c2bbcad20a96e8ef70c7 Reviewed-by: Joerg Bornemann Reviewed-by: Oliver Wolff --- src/plugins/platforms/direct2d/direct2d.pro | 3 ++- src/plugins/platforms/platforms.pro | 6 +++--- src/plugins/platforms/windows/windows.pri | 2 ++ src/plugins/platforms/winrt/winrt.pro | 3 ++- 4 files changed, 9 insertions(+), 5 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/direct2d/direct2d.pro b/src/plugins/platforms/direct2d/direct2d.pro index 3bfd02bdc8..9764272632 100644 --- a/src/plugins/platforms/direct2d/direct2d.pro +++ b/src/plugins/platforms/direct2d/direct2d.pro @@ -8,7 +8,8 @@ QT += \ qtConfig(accessibility): QT += accessibility_support-private qtConfig(vulkan): QT += vulkan_support-private -LIBS += -ldwmapi -ld2d1 -ld3d11 -ldwrite -lversion -lgdi32 +LIBS += -ldwmapi -lversion -lgdi32 +QMAKE_USE_PRIVATE += dwrite_1 d2d1_1 d3d11_1 dxgi1_2 include(../windows/windows.pri) diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro index db2a31d1a5..acc55adf6f 100644 --- a/src/plugins/platforms/platforms.pro +++ b/src/plugins/platforms/platforms.pro @@ -14,10 +14,10 @@ qtConfig(xcb) { uikit:!watchos: SUBDIRS += ios osx: SUBDIRS += cocoa -win32:!winrt: SUBDIRS += windows -winrt: SUBDIRS += winrt +win32:!winrt:qtConfig(direct3d9): SUBDIRS += windows +winrt:qtConfig(direct3d11): SUBDIRS += winrt -qtConfig(direct2d) { +qtConfig(direct3d11_1):qtConfig(direct2d1_1):qtConfig(directwrite1) { SUBDIRS += direct2d } diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri index db06a6a2a3..7004d7e854 100644 --- a/src/plugins/platforms/windows/windows.pri +++ b/src/plugins/platforms/windows/windows.pri @@ -9,6 +9,8 @@ mingw: LIBS *= -luuid # For the dialog helpers: LIBS += -lshlwapi -lshell32 -ladvapi32 -lwtsapi32 +QMAKE_USE_PRIVATE += d3d9/nolink + DEFINES *= QT_NO_CAST_FROM_ASCII QT_NO_FOREACH SOURCES += \ diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro index 6a847465e4..43132a1a76 100644 --- a/src/plugins/platforms/winrt/winrt.pro +++ b/src/plugins/platforms/winrt/winrt.pro @@ -8,7 +8,8 @@ QT += \ DEFINES *= QT_NO_CAST_FROM_ASCII __WRL_NO_DEFAULT_LIB__ -LIBS += -lws2_32 -ld3d11 +LIBS += -lws2_32 +QMAKE_USE_PRIVATE += d3d11 SOURCES = \ main.cpp \ -- cgit v1.2.3 From 65463764f24210c755d6f48930162e67a5de7e9b Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 17 Jan 2018 12:44:45 +0100 Subject: configure: properly atomize xcb-syslibs as it is now cheap to test for individual libraries and headers, split the xcb_syslibs monster-library into its parts. the compile test remains a single blob, though, as that didn't get any cheaper. whether it's worth keeping it in the first place is debatable. Change-Id: Id7cae7925bb4d77069437512abecf14feea749f2 Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/xcb_qpa_lib.pro | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index 9883617ab6..f4ca9cc81d 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -95,12 +95,13 @@ qtConfig(vulkan) { } !qtConfig(system-xcb) { - QMAKE_USE += xcb-static xcb + QMAKE_USE += xcb-static } else { qtConfig(xcb-render): QMAKE_USE += xcb_render qtConfig(xcb-xinput): QMAKE_USE += xcb_xinput - QMAKE_USE += xcb_syslibs + QMAKE_USE += xcb_icccm xcb_image xcb_keysyms xcb_randr xcb_shape xcb_shm xcb_sync xcb_xfixes xcb_xinerama } +QMAKE_USE += xcb QMAKE_USE += xkbcommon qtConfig(xkb) { -- cgit v1.2.3 From 16aae58e2a5cc324b869568f6fb9cc4bedbc96d9 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 18 Dec 2018 08:38:43 -0800 Subject: Fix build with Clang 3.8 Commit 128a6eec065dfe683e6d776183d63908ca02e8fb replaced the static, unsorted list with a sorting implementation via templates. qmakearray_p.h:109:8: fatal error: recursive template instantiation exceeded maximum depth of 256 qmakearray_p.h:111:39: note: during template argument deduction for class template partial specialization 'QuickSortFilter >' [with Predicate = LessThan, Head = Xkb2Qt<269025163, 16777462>, Tail = ...] Fixes: QTBUG-72579 Change-Id: I548dbfddb69b4fd6a0a3fffd15717ac2bf2d7361 Reviewed-by: Gatis Paeglis Reviewed-by: Mikhail Svetkin --- src/plugins/platforms/xcb/xcb_qpa_lib.pro | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index 9883617ab6..50b7f7f97d 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -110,4 +110,8 @@ qtConfig(xkb) { qtConfig(dlopen): QMAKE_USE += libdl +# qxcbkeyboard.cpp's KeyTbl has more than 256 levels of expansion and older +# Clang uses that as a limit (it's 1024 in current versions). +clang:!intel_icc: QMAKE_CXXFLAGS += -ftemplate-depth=1024 + load(qt_module) -- cgit v1.2.3 From 3a74a3b5a644ac196942c717d31cd5f8438f3c0b Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Thu, 20 Dec 2018 09:13:26 +0100 Subject: QSQL: add support for PostgreSQL 11 Add support for PostgreSQL 11 by adding QPSQLDriver::Version11 and use it in qMakePSQLVersion(). [ChangeLog][QSQL][PostgreSQL] Added support for PostgreSQL 11 Fixes: QTBUG-71642 Change-Id: Ie3cd3a81fd00084b587457b91b4e92c2e7001172 Reviewed-by: Andy Shaw Reviewed-by: Robert Szefner --- src/plugins/sqldrivers/psql/qsql_psql.cpp | 4 +++- src/plugins/sqldrivers/psql/qsql_psql_p.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp index bf0493b0c3..7ad9db1ea8 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql.cpp +++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp @@ -1060,8 +1060,10 @@ static QPSQLDriver::Protocol qMakePSQLVersion(int vMaj, int vMin) } case 10: return QPSQLDriver::Version10; + case 11: + return QPSQLDriver::Version11; default: - if (vMaj > 10) + if (vMaj > 11) return QPSQLDriver::UnknownLaterVersion; break; } diff --git a/src/plugins/sqldrivers/psql/qsql_psql_p.h b/src/plugins/sqldrivers/psql/qsql_psql_p.h index 2873a9f851..7e1849d857 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql_p.h +++ b/src/plugins/sqldrivers/psql/qsql_psql_p.h @@ -92,6 +92,7 @@ public: Version9_5 = 21, Version9_6 = 22, Version10 = 23, + Version11 = 24, UnknownLaterVersion = 100000 }; -- cgit v1.2.3 From b45c1e1c0e3dd838543c1e8d4725d9436367a16a Mon Sep 17 00:00:00 2001 From: Sami Nurmenniemi Date: Wed, 12 Dec 2018 13:45:16 +0200 Subject: Add possibility to configure QNX display order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add environmental variable QT_QPA_QNX_DISPLAY_CONFIG for pointing to a file containing display order. Configuration file format is: { "displayOrder": [ 3, 1 ] } Task-number: QTBUG-66394 Change-Id: I8c20eb2b5cf35617d5a030213f5d4d68e62ace85 Reviewed-by: Kari Oikarinen Reviewed-by: Pasi Petäjäjärvi --- src/plugins/platforms/qnx/qqnxintegration.cpp | 114 +++++++++++++++++++++++++- src/plugins/platforms/qnx/qqnxintegration.h | 2 + 2 files changed, 112 insertions(+), 4 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp index 8c8521325c..db79780407 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.cpp +++ b/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -88,7 +88,10 @@ #include #include - +#include +#include +#include +#include #include #if defined(QQNXINTEGRATION_DEBUG) @@ -490,6 +493,108 @@ void QQnxIntegration::removeWindow(screen_window_t qnxWindow) m_windowMapper.remove(qnxWindow); } +/*! + Get display ID for given \a display + + Returns -1 for failure, otherwise returns display ID + */ +static int getIdOfDisplay(screen_display_t display) +{ + int displayId; + if (screen_get_display_property_iv(display, + SCREEN_PROPERTY_ID, + &displayId) == 0) { + return displayId; + } + return -1; +} + +/*! + Read JSON configuration file for the QNX display order + + Returns true if file was read successfully and fills \a requestedDisplays + */ +static bool getRequestedDisplays(QJsonArray &requestedDisplays) +{ + // Check if display configuration file is provided + QByteArray json = qgetenv("QT_QPA_QNX_DISPLAY_CONFIG"); + if (json.isEmpty()) + return false; + + // Check if configuration file exists + QFile file(QString::fromUtf8(json)); + if (!file.open(QFile::ReadOnly)) { + qWarning() << "Could not open config file" << json << "for reading"; + return false; + } + + // Read config file and check it's json + const QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); + if (!doc.isObject()) { + qWarning() << "Invalid config file" << json + << "- no top-level JSON object"; + return false; + } + + // Read the requested display order + const QJsonObject object = doc.object(); + requestedDisplays = object.value(QLatin1String("displayOrder")).toArray(); + + return true; +} + +/*! + Match \a availableDisplays with display order defined in a json file + pointed to by QT_QPA_QNX_DISPLAY_CONFIG. Display order must use same + identifiers as defined for displays in graphics.conf. Number of + available displays must be specified in \a displayCount + + An example configuration is below: + \badcode + { + "displayOrder": [ 3, 1 ] + } + \endcode + + Returns ordered list of displays. If no order was specified, returns + displays in the same order as in the original list. +*/ +QList QQnxIntegration::sortDisplays(screen_display_t *availableDisplays, int displayCount) +{ + // Intermediate list for sorting + QList allDisplays; + for (int i = 0; i < displayCount; i++) + allDisplays.append(&availableDisplays[i]); + + // Read requested display order if available + QJsonArray requestedDisplays; + if (!getRequestedDisplays(requestedDisplays)) + return allDisplays; + + // Go through all the requested displays IDs + QList orderedDisplays; + for (const QJsonValue &value : qAsConst(requestedDisplays)) { + int requestedValue = value.toInt(); + + // Move all displays with matching ID from the intermediate list + // to the beginning of the ordered list + QMutableListIterator iter(allDisplays); + while (iter.hasNext()) { + screen_display_t *display = iter.next(); + if (getIdOfDisplay(*display) == requestedValue) { + orderedDisplays.append(display); + iter.remove(); + break; + } + } + } + + // Place all unordered displays to the end of list + orderedDisplays.append(allDisplays); + + return orderedDisplays; +} + void QQnxIntegration::createDisplays() { qIntegrationDebug(); @@ -508,15 +613,16 @@ void QQnxIntegration::createDisplays() screen_display_t *displays = (screen_display_t *)alloca(sizeof(screen_display_t) * displayCount); result = screen_get_context_property_pv(m_screenContext, SCREEN_PROPERTY_DISPLAYS, (void **)displays); + QList orderedDisplays = sortDisplays(displays, displayCount); Q_SCREEN_CRITICALERROR(result, "Failed to query displays"); // If it's primary, we create a QScreen for it even if it's not attached // since Qt will dereference QGuiApplication::primaryScreen() - createDisplay(displays[0], /*isPrimary=*/true); + createDisplay(*orderedDisplays[0], /*isPrimary=*/true); for (int i=1; i sortDisplays(screen_display_t *displays, + int displayCount); screen_context_t m_screenContext; QQnxScreenEventThread *m_screenEventThread; -- cgit v1.2.3 From 4aac07d0237cd4895f670ae2df6a8844ab91b699 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Fri, 2 Nov 2018 10:36:20 +0100 Subject: Android: Add support for setting/getting html and uris from clipboard This also updates the used API to use ClipData and not the deprecated ClipboardManager API. [ChangeLog][Platform Specific Changes][Android] QClipboard now supports HTML and URI data. Fixes: QTBUG-47835 Fixes: QTBUG-71503 Change-Id: I43f82bfc63b3d159087c0fb6c840c186a370e20c Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../platforms/android/androidjniclipboard.cpp | 68 ++++++++++++++++------ .../platforms/android/androidjniclipboard.h | 5 +- .../android/qandroidplatformclipboard.cpp | 11 ++-- .../platforms/android/qandroidplatformclipboard.h | 5 +- 4 files changed, 59 insertions(+), 30 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/android/androidjniclipboard.cpp b/src/plugins/platforms/android/androidjniclipboard.cpp index d169035339..671d0b56d0 100644 --- a/src/plugins/platforms/android/androidjniclipboard.cpp +++ b/src/plugins/platforms/android/androidjniclipboard.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "androidjniclipboard.h" +#include #include QT_BEGIN_NAMESPACE @@ -62,27 +63,60 @@ namespace QtAndroidClipboard return; } } - - void setClipboardText(const QString &text) + void setClipboardMimeData(QMimeData *data) { - QJNIObjectPrivate::callStaticMethod(applicationClass(), - "setClipboardText", - "(Ljava/lang/String;)V", - QJNIObjectPrivate::fromString(text).object()); - } - - bool hasClipboardText() - { - return QJNIObjectPrivate::callStaticMethod(applicationClass(), - "hasClipboardText"); + QJNIObjectPrivate::callStaticMethod(applicationClass(), "clearClipData"); + if (data->hasText()) { + QJNIObjectPrivate::callStaticMethod(applicationClass(), + "setClipboardText", "(Ljava/lang/String;)V", + QJNIObjectPrivate::fromString(data->text()).object()); + } + if (data->hasHtml()) { + QJNIObjectPrivate::callStaticMethod(applicationClass(), + "setClipboardHtml", + "(Ljava/lang/String;Ljava/lang/String;)V", + QJNIObjectPrivate::fromString(data->text()).object(), + QJNIObjectPrivate::fromString(data->html()).object()); + } + if (data->hasUrls()) { + QList urls = data->urls(); + for (const auto &u : qAsConst(urls)) { + QJNIObjectPrivate::callStaticMethod(applicationClass(), "setClipboardUri", + "(Ljava/lang/String;)V", + QJNIObjectPrivate::fromString(u.toEncoded()).object()); + } + } } - QString clipboardText() + QMimeData *getClipboardMimeData() { - QJNIObjectPrivate text = QJNIObjectPrivate::callStaticObjectMethod(applicationClass(), - "getClipboardText", - "()Ljava/lang/String;"); - return text.toString(); + QMimeData *data = new QMimeData; + if (QJNIObjectPrivate::callStaticMethod(applicationClass(), "hasClipboardText")) { + data->setText(QJNIObjectPrivate::callStaticObjectMethod(applicationClass(), + "getClipboardText", + "()Ljava/lang/String;").toString()); + } + if (QJNIObjectPrivate::callStaticMethod(applicationClass(), "hasClipboardHtml")) { + data->setHtml(QJNIObjectPrivate::callStaticObjectMethod(applicationClass(), + "getClipboardHtml", + "()Ljava/lang/String;").toString()); + } + if (QJNIObjectPrivate::callStaticMethod(applicationClass(), "hasClipboardUri")) { + QJNIObjectPrivate uris = QJNIObjectPrivate::callStaticObjectMethod(applicationClass(), + "getClipboardUris", + "()[Ljava/lang/String;"); + if (uris.isValid()) { + QList urls; + QJNIEnvironmentPrivate env; + jobjectArray juris = static_cast(uris.object()); + const jint nUris = env->GetArrayLength(juris); + urls.reserve(static_cast(nUris)); + for (int i = 0; i < nUris; ++i) + urls << QUrl(QJNIObjectPrivate(env->GetObjectArrayElement(juris, i)).toString()); + data->setUrls(urls); + } + } + return data; } void onClipboardDataChanged(JNIEnv */*env*/, jobject /*thiz*/) diff --git a/src/plugins/platforms/android/androidjniclipboard.h b/src/plugins/platforms/android/androidjniclipboard.h index 2ec566e729..e83e6b555c 100644 --- a/src/plugins/platforms/android/androidjniclipboard.h +++ b/src/plugins/platforms/android/androidjniclipboard.h @@ -51,9 +51,8 @@ namespace QtAndroidClipboard { // Clipboard support void setClipboardManager(QAndroidPlatformClipboard *manager); - void setClipboardText(const QString &text); - bool hasClipboardText(); - QString clipboardText(); + void setClipboardMimeData(QMimeData *data); + QMimeData *getClipboardMimeData(); void onClipboardDataChanged(JNIEnv */*env*/, jobject /*thiz*/); // Clipboard support } diff --git a/src/plugins/platforms/android/qandroidplatformclipboard.cpp b/src/plugins/platforms/android/qandroidplatformclipboard.cpp index dc5147b259..17dfe27d12 100644 --- a/src/plugins/platforms/android/qandroidplatformclipboard.cpp +++ b/src/plugins/platforms/android/qandroidplatformclipboard.cpp @@ -52,16 +52,15 @@ QMimeData *QAndroidPlatformClipboard::mimeData(QClipboard::Mode mode) { Q_UNUSED(mode); Q_ASSERT(supportsMode(mode)); - m_mimeData.setText(QtAndroidClipboard::hasClipboardText() - ? QtAndroidClipboard::clipboardText() - : QString()); - return &m_mimeData; + QMimeData *data = QtAndroidClipboard::getClipboardMimeData(); + data->setParent(this); + return data; } void QAndroidPlatformClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) { - if (supportsMode(mode)) - QtAndroidClipboard::setClipboardText(data != 0 && data->hasText() ? data->text() : QString()); + if (data && supportsMode(mode)) + QtAndroidClipboard::setClipboardMimeData(data); if (data != 0) data->deleteLater(); } diff --git a/src/plugins/platforms/android/qandroidplatformclipboard.h b/src/plugins/platforms/android/qandroidplatformclipboard.h index dfc3629c10..3ed9d323f8 100644 --- a/src/plugins/platforms/android/qandroidplatformclipboard.h +++ b/src/plugins/platforms/android/qandroidplatformclipboard.h @@ -46,7 +46,7 @@ #ifndef QT_NO_CLIPBOARD QT_BEGIN_NAMESPACE -class QAndroidPlatformClipboard: public QPlatformClipboard +class QAndroidPlatformClipboard : public QObject, public QPlatformClipboard { public: QAndroidPlatformClipboard(); @@ -54,9 +54,6 @@ public: QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override; void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard) override; bool supportsMode(QClipboard::Mode mode) const override; - -private: - QMimeData m_mimeData; }; QT_END_NAMESPACE -- cgit v1.2.3 From 69f7115c43ef17c2d8ff3f7842e64b539da94dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 18 Dec 2018 13:17:45 +0100 Subject: macOS: Merge qt_mac_createRoleFonts into only caller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id6e61a70e4ebe47896dcbc8680d1d6b06c747871 Reviewed-by: Timur Pocheptsov Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoatheme.mm | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index 240deeddbd..c46df25b66 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -228,16 +228,12 @@ const QPalette *QCocoaTheme::palette(Palette type) const return nullptr; } -QHash qt_mac_createRoleFonts() -{ - QCoreTextFontDatabase *ctfd = static_cast(QGuiApplicationPrivate::platformIntegration()->fontDatabase()); - return ctfd->themeFonts(); -} - const QFont *QCocoaTheme::font(Font type) const { if (m_fonts.isEmpty()) { - m_fonts = qt_mac_createRoleFonts(); + const auto *platformIntegration = QGuiApplicationPrivate::platformIntegration(); + const auto *coreTextFontDb = static_cast(platformIntegration->fontDatabase()); + m_fonts = coreTextFontDb->themeFonts(); } return m_fonts.value(type, nullptr); } -- cgit v1.2.3 From fb67ac6368aeb9547cc78551708e4ed0d9e4bbfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Wed, 12 Dec 2018 13:52:52 +0100 Subject: Modernize QNSImageView implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use Objc properties instead of instance variables. Change-Id: I4bddf2c9c824467d7c42dd5bb0c3b4aacd6b27be Reviewed-by: Tor Arne Vestbø --- .../platforms/cocoa/qcocoasystemtrayicon.mm | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm index 0158895441..3a7ac60424 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm @@ -105,6 +105,8 @@ QT_USE_NAMESPACE @end @interface QT_MANGLE_NAMESPACE(QNSImageView) : NSImageView +@property (nonatomic, assign) BOOL down; +@property (nonatomic, assign) QT_MANGLE_NAMESPACE(QNSStatusItem) *parent; @end QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSStatusItem); @@ -277,36 +279,32 @@ QT_END_NAMESPACE @implementation NSStatusItem (Qt) @end -@implementation QNSImageView { - BOOL down; - QT_MANGLE_NAMESPACE(QNSStatusItem) *parent; -} - +@implementation QNSImageView - (instancetype)initWithParent:(QNSStatusItem *)myParent { self = [super init]; - parent = myParent; - down = NO; + self.parent = myParent; + self.down = NO; return self; } - (void)menuTrackingDone:(NSNotification *)__unused notification { - down = NO; + self.down = NO; [self setNeedsDisplay:YES]; } - (void)mousePressed:(NSEvent *)mouseEvent { - down = YES; + self.down = YES; int clickCount = [mouseEvent clickCount]; [self setNeedsDisplay:YES]; if (clickCount == 2) { [self menuTrackingDone:nil]; - [parent doubleClickSelector:self]; + [self.parent doubleClickSelector:self]; } else { - [parent triggerSelector:self button:cocoaButton2QtButton(mouseEvent)]; + [self.parent triggerSelector:self button:cocoaButton2QtButton(mouseEvent)]; } } @@ -344,7 +342,7 @@ QT_END_NAMESPACE } - (void)drawRect:(NSRect)rect { - [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:down]; + [[self.parent item] drawStatusBarBackgroundInRect:rect withHighlight:self.down]; [super drawRect:rect]; } @end -- cgit v1.2.3 From f0dd6655e1df27dbb10bc43e0787d9328800c93a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Wed, 12 Dec 2018 14:59:48 +0100 Subject: Fix QSystemTrayIcon stale pointer access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The child imageCell is a NSView and may be retained by Cocoa, which means it may outlive the parent QNSStatusItem. Clear its parent pointer to avoid referencing a stale pointer. Task-number: QTBUG-47929 Change-Id: I6078070b8c9f512ecd034fee4e54b1d8282dabdf Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm | 1 + 1 file changed, 1 insertion(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm index 3a7ac60424..4982f5ee05 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm @@ -372,6 +372,7 @@ QT_END_NAMESPACE - (void)dealloc { [[NSStatusBar systemStatusBar] removeStatusItem:item]; [[NSNotificationCenter defaultCenter] removeObserver:imageCell]; + imageCell.parent = nil; [imageCell release]; [item release]; [super dealloc]; -- cgit v1.2.3 From 29ea287716175b57aa7b050b70eb3eb5c9049464 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Thu, 13 Dec 2018 15:54:35 +0100 Subject: Windows QPA: Avoid duplication of mouse events The code being removed was added as a workaround to support the use of QCursor::setPos() with unit tests. This function was used to move the Windows mouse cursor, internally calling SetCursorPos(), which generates only WM_MOUSE* messages, bypassing the pointer messages. However, the workaround had the unintended effect of generating duplicated mouse events for normal mouse movement, which caused issues like the one described by QTBUG-70974. However, it seems the tests are no longer depending on it, allowing it to be removed. Fixes: QTBUG-70974 Change-Id: Iaf0d64c73951ab1b660e9bb90e7ee009e53fbd3a Reviewed-by: Friedemann Kleint --- .../platforms/windows/qwindowspointerhandler.cpp | 29 ---------------------- 1 file changed, 29 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 3534f06971..78a8083d5b 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -370,22 +370,6 @@ static Qt::MouseButtons mouseButtonsFromPointerFlags(POINTER_FLAGS pointerFlags) return result; } -static Qt::MouseButtons mouseButtonsFromKeyState(WPARAM keyState) -{ - Qt::MouseButtons result = Qt::NoButton; - if (keyState & MK_LBUTTON) - result |= Qt::LeftButton; - if (keyState & MK_RBUTTON) - result |= Qt::RightButton; - if (keyState & MK_MBUTTON) - result |= Qt::MiddleButton; - if (keyState & MK_XBUTTON1) - result |= Qt::XButton1; - if (keyState & MK_XBUTTON2) - result |= Qt::XButton2; - return result; -} - static QWindow *getWindowUnderPointer(QWindow *window, QPoint globalPos) { QWindow *currentWindowUnderPointer = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT); @@ -816,14 +800,6 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW return false; } - // Windows sends a mouse move with no buttons pressed to signal "Enter" - // when a window is shown over the cursor. Discard the event and only use - // it for generating QEvent::Enter to be consistent with other platforms - - // X11 and macOS. - static QPoint lastMouseMovePos; - const bool discardEvent = msg.wParam == 0 && (m_windowUnderPointer.isNull() || globalPos == lastMouseMovePos); - lastMouseMovePos = globalPos; - QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos); if (currentWindowUnderPointer != m_windowUnderPointer) { @@ -846,11 +822,6 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW m_windowUnderPointer = currentWindowUnderPointer; } - const Qt::MouseButtons mouseButtons = mouseButtonsFromKeyState(msg.wParam); - - if (!discardEvent) - QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, Qt::NoButton, QEvent::MouseMove, - keyModifiers, Qt::MouseEventNotSynthesized); return false; } -- cgit v1.2.3 From 7ba16f4c1ea172026da834887de1b8da797de79a Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Mon, 31 Dec 2018 16:20:48 +0100 Subject: QComboBox/WindowVistaStyle: restore focus rect The focus rect for the QComboBox was removed during the refactoring done in 5c60e4b8f9cc88e48f5e7652eefe90e1366ae23d. Readd the functionality in a similar to QWindowsStyle::drawComplexControl(). Fixes: QTBUG-69239 Change-Id: I74e4060fbe52432318e3c986fc838cf353d99843 Reviewed-by: Andre de la Rocha Reviewed-by: Friedemann Kleint --- src/plugins/styles/windowsvista/qwindowsvistastyle.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp index 7b35d1b58c..771552a121 100644 --- a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp @@ -1664,9 +1664,15 @@ void QWindowsVistaStyle::drawComplexControl(ComplexControl control, const QStyle theme.stateId = CBXS_NORMAL; d->drawBackground(theme); } + if ((sub & SC_ComboBoxEditField) && (flags & State_HasFocus)) { + QStyleOptionFocusRect fropt; + fropt.QStyleOption::operator=(*cmb); + fropt.rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxEditField, widget); + proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget); + } } - } - break; + } + break; case CC_ScrollBar: if (const QStyleOptionSlider *scrollbar = qstyleoption_cast(option)) { -- cgit v1.2.3 From f9d8762d37d83e3f3f21adfece0dbbb15886d722 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Fri, 21 Dec 2018 09:38:30 +0100 Subject: winrt: Remove yet another Windows Phone leftover Hardware and camera button handling are phone specific APIs we no longer support in Qt. Change-Id: Ib11f894a426b8e4b71acf24876437ddab2cea548 Reviewed-by: Oliver Wolff Reviewed-by: Andre de la Rocha Reviewed-by: Oswald Buddenhagen --- src/plugins/platforms/winrt/qwinrtintegration.cpp | 132 ---------------------- src/plugins/platforms/winrt/qwinrtintegration.h | 16 --- 2 files changed, 148 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index 4f37583bed..78cbc3aec3 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -75,13 +75,6 @@ #include #include -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) -# include -# include - using namespace ABI::Windows::Foundation::Metadata; -#endif - - using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::Windows::Foundation; @@ -92,27 +85,14 @@ using namespace ABI::Windows::UI::Core; using namespace ABI::Windows::UI::ViewManagement; using namespace ABI::Windows::Graphics::Display; using namespace ABI::Windows::ApplicationModel::Core; -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) -using namespace ABI::Windows::Phone::UI::Input; -#endif typedef IEventHandler ResumeHandler; typedef IEventHandler SuspendHandler; -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) -typedef IEventHandler BackPressedHandler; -typedef IEventHandler CameraButtonHandler; -#endif QT_BEGIN_NAMESPACE typedef HRESULT (__stdcall ICoreApplication::*CoreApplicationCallbackRemover)(EventRegistrationToken); uint qHash(CoreApplicationCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) -typedef HRESULT (__stdcall IHardwareButtonsStatics::*HardwareButtonsCallbackRemover)(EventRegistrationToken); -uint qHash(HardwareButtonsCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } -typedef HRESULT (__stdcall IHardwareButtonsStatics2::*HardwareButtons2CallbackRemover)(EventRegistrationToken); -uint qHash(HardwareButtons2CallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } -#endif class QWinRTIntegrationPrivate { @@ -128,15 +108,6 @@ public: ComPtr application; QHash applicationTokens; -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) - ComPtr hardwareButtons; - QHash buttonsTokens; - ComPtr cameraButtons; - QHash cameraTokens; - boolean hasHardwareButtons; - bool cameraHalfPressed : 1; - bool cameraPressed : 1; -#endif }; QWinRTIntegration::QWinRTIntegration() : d_ptr(new QWinRTIntegrationPrivate) @@ -156,45 +127,6 @@ QWinRTIntegration::QWinRTIntegration() : d_ptr(new QWinRTIntegrationPrivate) &d->applicationTokens[&ICoreApplication::remove_Resuming]); Q_ASSERT_SUCCEEDED(hr); -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) - d->hasHardwareButtons = false; - ComPtr apiInformationStatics; - hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_Metadata_ApiInformation).Get(), - IID_PPV_ARGS(&apiInformationStatics)); - - if (SUCCEEDED(hr)) { - const HStringReference valueRef(L"Windows.Phone.UI.Input.HardwareButtons"); - hr = apiInformationStatics->IsTypePresent(valueRef.Get(), &d->hasHardwareButtons); - } - - if (d->hasHardwareButtons) { - hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(), - IID_PPV_ARGS(&d->hardwareButtons)); - Q_ASSERT_SUCCEEDED(hr); - hr = d->hardwareButtons->add_BackPressed(Callback(this, &QWinRTIntegration::onBackButtonPressed).Get(), - &d->buttonsTokens[&IHardwareButtonsStatics::remove_BackPressed]); - Q_ASSERT_SUCCEEDED(hr); - - hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(), - IID_PPV_ARGS(&d->cameraButtons)); - Q_ASSERT_SUCCEEDED(hr); - if (qEnvironmentVariableIntValue("QT_QPA_ENABLE_CAMERA_KEYS")) { - hr = d->cameraButtons->add_CameraPressed(Callback(this, &QWinRTIntegration::onCameraPressed).Get(), - &d->cameraTokens[&IHardwareButtonsStatics2::remove_CameraPressed]); - Q_ASSERT_SUCCEEDED(hr); - hr = d->cameraButtons->add_CameraHalfPressed(Callback(this, &QWinRTIntegration::onCameraHalfPressed).Get(), - &d->cameraTokens[&IHardwareButtonsStatics2::remove_CameraHalfPressed]); - Q_ASSERT_SUCCEEDED(hr); - hr = d->cameraButtons->add_CameraReleased(Callback(this, &QWinRTIntegration::onCameraReleased).Get(), - &d->cameraTokens[&IHardwareButtonsStatics2::remove_CameraReleased]); - Q_ASSERT_SUCCEEDED(hr); - } - d->cameraPressed = false; - d->cameraHalfPressed = false; - } -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) - - QEventDispatcherWinRT::runOnXamlThread([d]() { d->mainScreen = new QWinRTScreen; return S_OK; @@ -214,18 +146,6 @@ QWinRTIntegration::~QWinRTIntegration() Q_D(QWinRTIntegration); HRESULT hr; -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) - if (d->hasHardwareButtons) { - for (QHash::const_iterator i = d->buttonsTokens.begin(); i != d->buttonsTokens.end(); ++i) { - hr = (d->hardwareButtons.Get()->*i.key())(i.value()); - Q_ASSERT_SUCCEEDED(hr); - } - for (QHash::const_iterator i = d->cameraTokens.begin(); i != d->cameraTokens.end(); ++i) { - hr = (d->cameraButtons.Get()->*i.key())(i.value()); - Q_ASSERT_SUCCEEDED(hr); - } - } -#endif // Do not execute this on Windows Phone as the application is already // shutting down and trying to unregister suspending/resume handler will // cause exceptions and assert in debug mode @@ -353,58 +273,6 @@ QPlatformTheme *QWinRTIntegration::createPlatformTheme(const QString &name) cons // System-level integration points -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) -HRESULT QWinRTIntegration::onBackButtonPressed(IInspectable *, IBackPressedEventArgs *args) -{ - Q_D(QWinRTIntegration); - QWindow *window = d->mainScreen->topWindow(); - QWindowSystemInterface::setSynchronousWindowSystemEvents(true); - const bool pressed = QWindowSystemInterface::handleExtendedKeyEvent(window, QEvent::KeyPress, Qt::Key_Back, Qt::NoModifier, - 0, 0, 0, QString(), false, 1, false); - const bool released = QWindowSystemInterface::handleExtendedKeyEvent(window, QEvent::KeyRelease, Qt::Key_Back, Qt::NoModifier, - 0, 0, 0, QString(), false, 1, false); - QWindowSystemInterface::setSynchronousWindowSystemEvents(false); - args->put_Handled(pressed || released); - return S_OK; -} - -HRESULT QWinRTIntegration::onCameraPressed(IInspectable *, ICameraEventArgs *) -{ - Q_D(QWinRTIntegration); - QWindow *window = d->mainScreen->topWindow(); - QWindowSystemInterface::handleExtendedKeyEvent(window, QEvent::KeyPress, Qt::Key_Camera, Qt::NoModifier, - 0, 0, 0, QString(), false, 1, false); - d->cameraPressed = true; - return S_OK; -} - -HRESULT QWinRTIntegration::onCameraHalfPressed(IInspectable *, ICameraEventArgs *) -{ - Q_D(QWinRTIntegration); - QWindow *window = d->mainScreen->topWindow(); - QWindowSystemInterface::handleExtendedKeyEvent(window, QEvent::KeyPress, Qt::Key_CameraFocus, Qt::NoModifier, - 0, 0, 0, QString(), false, 1, false); - d->cameraHalfPressed = true; - return S_OK; -} - -HRESULT QWinRTIntegration::onCameraReleased(IInspectable *, ICameraEventArgs *) -{ - Q_D(QWinRTIntegration); - QWindow *window = d->mainScreen->topWindow(); - if (d->cameraHalfPressed) - QWindowSystemInterface::handleExtendedKeyEvent(window, QEvent::KeyRelease, Qt::Key_CameraFocus, Qt::NoModifier, - 0, 0, 0, QString(), false, 1, false); - - if (d->cameraPressed) - QWindowSystemInterface::handleExtendedKeyEvent(window, QEvent::KeyRelease, Qt::Key_Camera, Qt::NoModifier, - 0, 0, 0, QString(), false, 1, false); - d->cameraHalfPressed = false; - d->cameraPressed = false; - return S_OK; -} -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) - HRESULT QWinRTIntegration::onSuspended(IInspectable *, ISuspendingEventArgs *) { QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended); diff --git a/src/plugins/platforms/winrt/qwinrtintegration.h b/src/plugins/platforms/winrt/qwinrtintegration.h index 636e594b4b..e944ed5d79 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.h +++ b/src/plugins/platforms/winrt/qwinrtintegration.h @@ -50,16 +50,6 @@ namespace ABI { namespace Foundation { struct IAsyncAction; } -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) - namespace Phone { - namespace UI { - namespace Input { - struct IBackPressedEventArgs; - struct ICameraEventArgs; - } - } - } -#endif } } struct IAsyncInfo; @@ -111,12 +101,6 @@ public: QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override; private: -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) - HRESULT onBackButtonPressed(IInspectable *, ABI::Windows::Phone::UI::Input::IBackPressedEventArgs *args); - HRESULT onCameraPressed(IInspectable *, ABI::Windows::Phone::UI::Input::ICameraEventArgs *); - HRESULT onCameraHalfPressed(IInspectable *, ABI::Windows::Phone::UI::Input::ICameraEventArgs *); - HRESULT onCameraReleased(IInspectable *, ABI::Windows::Phone::UI::Input::ICameraEventArgs *); -#endif HRESULT onSuspended(IInspectable *, ABI::Windows::ApplicationModel::ISuspendingEventArgs *); HRESULT onResume(IInspectable *, IInspectable *); -- cgit v1.2.3 From 6899117a59256082f37492d81ecaf56a0844690e Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Thu, 27 Dec 2018 01:10:29 +0100 Subject: configure: properly atomize render vs. renderutil xcb-render is a C interface for X11 extension. xcb-render-util is a utility library that complements xcb-render by providing convenience functions and interfaces which make the raw X protocol more usable. Bumped xcb-render-util version to avoid having include hacks. We were bundling 8 years old release 0.3.8 (Apr, 2011). 0.3.9 is the latest release and it was relesed 4,5 years ago (Jun, 2014). All CI machines have 0.3.9. The only thing that have changed in xcb-render-util sources since 2011 is that we don't need to have various hacks to include xcb_renderutil.h in C++ files. Upgrading bundled XCB libs was also requested in QTBUG-71109. Task-number: QTBUG-71109 Change-Id: Ib261f7584ad81be95660123b007e2200a3042f4c Reviewed-by: Oswald Buddenhagen --- src/plugins/platforms/xcb/qxcbbackingstore.cpp | 6 ------ src/plugins/platforms/xcb/qxcbimage.cpp | 6 ------ src/plugins/platforms/xcb/xcb_qpa_lib.pro | 2 +- 3 files changed, 1 insertion(+), 13 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index ba9a3e68ee..e446933dac 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -47,13 +47,7 @@ #include #if QT_CONFIG(xcb_render) #include -// 'template' is used as a function argument name in xcb_renderutil.h -#define template template_param -// extern "C" is missing too -extern "C" { #include -} -#undef template #endif #include diff --git a/src/plugins/platforms/xcb/qxcbimage.cpp b/src/plugins/platforms/xcb/qxcbimage.cpp index 44c7d22344..31c24f40b4 100644 --- a/src/plugins/platforms/xcb/qxcbimage.cpp +++ b/src/plugins/platforms/xcb/qxcbimage.cpp @@ -44,13 +44,7 @@ #include #if QT_CONFIG(xcb_render) #include -// 'template' is used as a function argument name in xcb_renderutil.h -#define template template_param -// extern "C" is missing too -extern "C" { #include -} -#undef template #endif #include "qxcbconnection.h" diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index f4ca9cc81d..1369d3496e 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -97,7 +97,7 @@ qtConfig(vulkan) { !qtConfig(system-xcb) { QMAKE_USE += xcb-static } else { - qtConfig(xcb-render): QMAKE_USE += xcb_render + qtConfig(xcb-render): QMAKE_USE += xcb_render xcb_renderutil qtConfig(xcb-xinput): QMAKE_USE += xcb_xinput QMAKE_USE += xcb_icccm xcb_image xcb_keysyms xcb_randr xcb_shape xcb_shm xcb_sync xcb_xfixes xcb_xinerama } -- cgit v1.2.3 From 7d8fe4d98fc5e05f60a91649f208b92d622a4eac Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Thu, 27 Dec 2018 01:10:29 +0100 Subject: configure: make xcb-render a hard dependency for xcb plugin Its been available by default since at least libxcb 1.5, and in Qt 5.12 we have even increased the minimal required libxcb version to 1.9. Having configure switches for extensions is a legacy from Qt 4. There are still few exceptions in Qt5, where the reason is that we have to support Linux distributions that don't ship recent enough libxcb. Task-number: QTBUG-30939 Change-Id: I0a02d93b6411119ec018b0cb8fe5c63beeab62ee Reviewed-by: Oswald Buddenhagen Reviewed-by: Allan Sandfeld Jensen --- src/plugins/platforms/xcb/qxcbbackingstore.cpp | 12 ------------ src/plugins/platforms/xcb/qxcbbackingstore.h | 3 +-- src/plugins/platforms/xcb/qxcbconnection_basic.cpp | 10 ++-------- src/plugins/platforms/xcb/qxcbcursor.cpp | 4 ---- src/plugins/platforms/xcb/qxcbimage.cpp | 11 +---------- src/plugins/platforms/xcb/xcb_qpa_lib.pro | 5 +++-- 6 files changed, 7 insertions(+), 38 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index e446933dac..f9240a45cc 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -45,10 +45,8 @@ #include #include -#if QT_CONFIG(xcb_render) #include #include -#endif #include #include @@ -956,16 +954,13 @@ QXcbSystemTrayBackingStore::QXcbSystemTrayBackingStore(QWindow *window) if (depth != 32) { platformWindow->setParentRelativeBackPixmap(); -#if QT_CONFIG(xcb_render) initXRenderMode(); -#endif m_useGrabbedBackgound = !m_usingXRenderMode; } } QXcbSystemTrayBackingStore::~QXcbSystemTrayBackingStore() { -#if QT_CONFIG(xcb_render) if (m_xrenderPicture) { xcb_render_free_picture(xcb_connection(), m_xrenderPicture); m_xrenderPicture = XCB_NONE; @@ -978,7 +973,6 @@ QXcbSystemTrayBackingStore::~QXcbSystemTrayBackingStore() xcb_render_free_picture(xcb_connection(), m_windowPicture); m_windowPicture = XCB_NONE; } -#endif // QT_CONFIG(xcb_render) } void QXcbSystemTrayBackingStore::beginPaint(const QRegion ®ion) @@ -1000,7 +994,6 @@ void QXcbSystemTrayBackingStore::render(xcb_window_t window, const QRegion ®i return; } -#if QT_CONFIG(xcb_render) m_image->put(m_xrenderPixmap, region, offset); const QRect bounds = region.boundingRect(); const QPoint target = bounds.topLeft(); @@ -1011,7 +1004,6 @@ void QXcbSystemTrayBackingStore::render(xcb_window_t window, const QRegion ®i m_xrenderPicture, 0, m_windowPicture, target.x(), target.y(), 0, 0, target.x(), target.y(), source.width(), source.height()); -#endif // QT_CONFIG(xcb_render) } void QXcbSystemTrayBackingStore::recreateImage(QXcbWindow *win, const QSize &size) @@ -1028,7 +1020,6 @@ void QXcbSystemTrayBackingStore::recreateImage(QXcbWindow *win, const QSize &siz return; } -#if QT_CONFIG(xcb_render) if (m_xrenderPicture) { xcb_render_free_picture(xcb_connection(), m_xrenderPicture); m_xrenderPicture = XCB_NONE; @@ -1051,10 +1042,8 @@ void QXcbSystemTrayBackingStore::recreateImage(QXcbWindow *win, const QSize &siz m_image->resize(size); else m_image = new QXcbBackingStoreImage(this, size, 32, QImage::Format_ARGB32_Premultiplied); -#endif // QT_CONFIG(xcb_render) } -#if QT_CONFIG(xcb_render) void QXcbSystemTrayBackingStore::initXRenderMode() { if (!connection()->hasXRender()) @@ -1098,6 +1087,5 @@ void QXcbSystemTrayBackingStore::initXRenderMode() m_usingXRenderMode = true; } -#endif // QT_CONFIG(xcb_render) QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.h b/src/plugins/platforms/xcb/qxcbbackingstore.h index b91e5c7dc2..0c30929d4e 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.h +++ b/src/plugins/platforms/xcb/qxcbbackingstore.h @@ -99,14 +99,13 @@ protected: void recreateImage(QXcbWindow *win, const QSize &size) override; private: -#if QT_CONFIG(xcb_render) void initXRenderMode(); xcb_pixmap_t m_xrenderPixmap = XCB_NONE; xcb_render_picture_t m_xrenderPicture = XCB_NONE; xcb_render_pictformat_t m_xrenderPictFormat = XCB_NONE; xcb_render_picture_t m_windowPicture = XCB_NONE; -#endif + bool m_usingXRenderMode = false; bool m_useGrabbedBackgound = false; QPixmap m_grabbedBackground; diff --git a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp index b8335d1240..c69912c361 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp @@ -44,12 +44,10 @@ #include #include #include +#include #if QT_CONFIG(xcb_xinput) #include #endif -#if QT_CONFIG(xcb_render) -#include -#endif #if QT_CONFIG(xkb) #define explicit dont_use_cxx_explicit #include @@ -139,12 +137,10 @@ QXcbBasicConnection::QXcbBasicConnection(const char *displayName) xcb_extension_t *extensions[] = { &xcb_shm_id, &xcb_xfixes_id, &xcb_randr_id, &xcb_shape_id, &xcb_sync_id, + &xcb_render_id, #if QT_CONFIG(xkb) &xcb_xkb_id, #endif -#if QT_CONFIG(xcb_render) - &xcb_render_id, -#endif #if QT_CONFIG(xcb_xinput) &xcb_input_id, #endif @@ -293,7 +289,6 @@ void QXcbBasicConnection::initializeShm() void QXcbBasicConnection::initializeXRandr() { -#if QT_CONFIG(xcb_render) const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_xcbConnection, &xcb_render_id); if (!reply || !reply->present) { qCDebug(lcQpaXcb, "XRender extension not present on the X server"); @@ -311,7 +306,6 @@ void QXcbBasicConnection::initializeXRandr() m_hasXRandr = true; m_xrenderVersion.first = xrenderQuery->major_version; m_xrenderVersion.second = xrenderQuery->minor_version; -#endif } void QXcbBasicConnection::initializeXinerama() diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp index 7831671d42..fbadab4d50 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.cpp +++ b/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -607,14 +607,10 @@ xcb_cursor_t QXcbCursor::createBitmapCursor(QCursor *cursor) QPoint spot = cursor->hotSpot(); xcb_cursor_t c = XCB_NONE; if (cursor->pixmap().depth() > 1) { -#if QT_CONFIG(xcb_render) if (connection()->hasXRender(0, 5)) c = qt_xcb_createCursorXRender(m_screen, cursor->pixmap().toImage(), spot); else qCWarning(lcQpaXcb, "xrender >= 0.5 required to create pixmap cursors"); -#else - qCWarning(lcQpaXcb, "This build of Qt does not support pixmap cursors"); -#endif } else { xcb_connection_t *conn = xcb_connection(); xcb_pixmap_t cp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->bitmap()->toImage()); diff --git a/src/plugins/platforms/xcb/qxcbimage.cpp b/src/plugins/platforms/xcb/qxcbimage.cpp index 31c24f40b4..8f33e6ed31 100644 --- a/src/plugins/platforms/xcb/qxcbimage.cpp +++ b/src/plugins/platforms/xcb/qxcbimage.cpp @@ -42,10 +42,9 @@ #include #include #include -#if QT_CONFIG(xcb_render) + #include #include -#endif #include "qxcbconnection.h" #include "qxcbintegration.h" @@ -230,7 +229,6 @@ xcb_pixmap_t qt_xcb_XPixmapFromBitmap(QXcbScreen *screen, const QImage &image) xcb_cursor_t qt_xcb_createCursorXRender(QXcbScreen *screen, const QImage &image, const QPoint &spot) { -#if QT_CONFIG(xcb_render) xcb_connection_t *conn = screen->xcb_connection(); const int w = image.width(); const int h = image.height(); @@ -283,13 +281,6 @@ xcb_cursor_t qt_xcb_createCursorXRender(QXcbScreen *screen, const QImage &image, xcb_render_free_picture(conn, pic); xcb_free_pixmap(conn, pix); return cursor; - -#else - Q_UNUSED(screen); - Q_UNUSED(image); - Q_UNUSED(spot); - return XCB_NONE; -#endif } QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index 1369d3496e..647058167b 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -97,9 +97,10 @@ qtConfig(vulkan) { !qtConfig(system-xcb) { QMAKE_USE += xcb-static } else { - qtConfig(xcb-render): QMAKE_USE += xcb_render xcb_renderutil qtConfig(xcb-xinput): QMAKE_USE += xcb_xinput - QMAKE_USE += xcb_icccm xcb_image xcb_keysyms xcb_randr xcb_shape xcb_shm xcb_sync xcb_xfixes xcb_xinerama + QMAKE_USE += \ + xcb_icccm xcb_image xcb_keysyms xcb_randr xcb_render xcb_renderutil \ + xcb_shape xcb_shm xcb_sync xcb_xfixes xcb_xinerama } QMAKE_USE += xcb -- cgit v1.2.3 From dd988e2074fa8d7d230b14ab997bcfc86dc6e1a4 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Thu, 27 Dec 2018 01:10:29 +0100 Subject: configure: add XCB GL integration features This way Qt builders can see if everything has been configured properly for XCB GL integrations at configure time, instead of at the end of the build process. Change-Id: I00740cc2edd7f6ecfcda0ddfb22649d1b4db4aa2 Reviewed-by: Oswald Buddenhagen --- src/plugins/platforms/xcb/gl_integrations/gl_integrations.pro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/gl_integrations/gl_integrations.pro b/src/plugins/platforms/xcb/gl_integrations/gl_integrations.pro index b8f878ffe8..dde176433c 100644 --- a/src/plugins/platforms/xcb/gl_integrations/gl_integrations.pro +++ b/src/plugins/platforms/xcb/gl_integrations/gl_integrations.pro @@ -1,10 +1,10 @@ TEMPLATE = subdirs QT_FOR_CONFIG += gui-private -qtConfig(egl):qtConfig(egl_x11):qtConfig(opengl) { +qtConfig(xcb-egl-plugin) { SUBDIRS += xcb_egl } -qtConfig(xcb-xlib):qtConfig(opengl):!qtConfig(opengles2) { +qtConfig(xcb-glx-plugin) { SUBDIRS += xcb_glx } -- cgit v1.2.3 From df27484fc0349bb060e023ac2dce246c1176d838 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Wed, 19 Dec 2018 20:57:25 +0100 Subject: Windows QPA: Fix mouse pointer capture and Enter/Leave events Qt expects the platform plugin to capture the mouse on any button press and keep it captured until buttons are released. The missing capture logic was causing extra Enter/Leave events to be generated. Change-Id: I5a78ea600374701c740f395b38ba5abd51f561d8 Fixes: QTBUG-72600 Reviewed-by: Friedemann Kleint --- .../platforms/windows/qwindowspointerhandler.cpp | 185 +++++++++++++++------ .../platforms/windows/qwindowspointerhandler.h | 4 + 2 files changed, 137 insertions(+), 52 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 78a8083d5b..be67eb0248 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -54,7 +54,6 @@ # include "qwindowsdrag.h" #endif -#include #include #include #include @@ -370,6 +369,22 @@ static Qt::MouseButtons mouseButtonsFromPointerFlags(POINTER_FLAGS pointerFlags) return result; } +static Qt::MouseButtons mouseButtonsFromKeyState(WPARAM keyState) +{ + Qt::MouseButtons result = Qt::NoButton; + if (keyState & MK_LBUTTON) + result |= Qt::LeftButton; + if (keyState & MK_RBUTTON) + result |= Qt::RightButton; + if (keyState & MK_MBUTTON) + result |= Qt::MiddleButton; + if (keyState & MK_XBUTTON1) + result |= Qt::XButton1; + if (keyState & MK_XBUTTON2) + result |= Qt::XButton2; + return result; +} + static QWindow *getWindowUnderPointer(QWindow *window, QPoint globalPos) { QWindow *currentWindowUnderPointer = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT); @@ -411,6 +426,15 @@ static bool isValidWheelReceiver(QWindow *candidate) return false; } +static bool isMenuWindow(QWindow *window) +{ + if (window) + if (QObject *fo = window->focusObject()) + if (fo->inherits("QMenu")) + return true; + return false; +} + static QTouchDevice *createTouchDevice() { const int digitizers = GetSystemMetrics(SM_DIGITIZER); @@ -439,6 +463,103 @@ QTouchDevice *QWindowsPointerHandler::ensureTouchDevice() return m_touchDevice; } +void QWindowsPointerHandler::handleCaptureRelease(QWindow *window, + QWindow *currentWindowUnderPointer, + HWND hwnd, + QEvent::Type eventType, + Qt::MouseButtons mouseButtons) +{ + QWindowsWindow *platformWindow = static_cast(window->handle()); + + // Qt expects the platform plugin to capture the mouse on any button press until release. + if (!platformWindow->hasMouseCapture() && eventType == QEvent::MouseButtonPress) { + + platformWindow->setMouseGrabEnabled(true); + platformWindow->setFlag(QWindowsWindow::AutoMouseCapture); + qCDebug(lcQpaEvents) << "Automatic mouse capture " << window; + + // Implement "Click to focus" for native child windows (unless it is a native widget window). + if (!window->isTopLevel() && !window->inherits("QWidgetWindow") && QGuiApplication::focusWindow() != window) + window->requestActivate(); + + } else if (platformWindow->hasMouseCapture() + && platformWindow->testFlag(QWindowsWindow::AutoMouseCapture) + && eventType == QEvent::MouseButtonRelease + && !mouseButtons) { + + platformWindow->setMouseGrabEnabled(false); + qCDebug(lcQpaEvents) << "Releasing automatic mouse capture " << window; + } + + // Enter new window: track to generate leave event. + // If there is an active capture, only track if the current window is capturing, + // so we don't get extra leave when cursor leaves the application. + if (window != m_currentWindow && + (!platformWindow->hasMouseCapture() || currentWindowUnderPointer == window)) { + trackLeave(hwnd); + m_currentWindow = window; + } +} + +void QWindowsPointerHandler::handleEnterLeave(QWindow *window, + QWindow *currentWindowUnderPointer, + QPoint globalPos) +{ + QWindowsWindow *platformWindow = static_cast(window->handle()); + const bool hasCapture = platformWindow->hasMouseCapture(); + + // No enter or leave events are sent as long as there is an autocapturing window. + if (!hasCapture || !platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)) { + + // Leave is needed if: + // 1) There is no capture and we move from a window to another window. + // Note: Leaving the application entirely is handled in translateMouseEvent(WM_MOUSELEAVE). + // 2) There is capture and we move out of the capturing window. + // 3) There is a new capture and we were over another window. + if ((m_windowUnderPointer && m_windowUnderPointer != currentWindowUnderPointer + && (!hasCapture || window == m_windowUnderPointer)) + || (hasCapture && m_previousCaptureWindow != window && m_windowUnderPointer + && m_windowUnderPointer != window)) { + + qCDebug(lcQpaEvents) << "Leaving window " << m_windowUnderPointer; + QWindowSystemInterface::handleLeaveEvent(m_windowUnderPointer); + + if (hasCapture && currentWindowUnderPointer != window) { + // Clear tracking if capturing and current window is not the capturing window + // to avoid leave when mouse actually leaves the application. + m_currentWindow = nullptr; + // We are not officially in any window, but we need to set some cursor to clear + // whatever cursor the left window had, so apply the cursor of the capture window. + platformWindow->applyCursor(); + } + } + + // Enter is needed if: + // 1) There is no capture and we move to a new window. + // 2) There is capture and we move into the capturing window. + // 3) The capture just ended and we are over non-capturing window. + if ((currentWindowUnderPointer && m_windowUnderPointer != currentWindowUnderPointer + && (!hasCapture || currentWindowUnderPointer == window)) + || (m_previousCaptureWindow && !hasCapture && currentWindowUnderPointer + && currentWindowUnderPointer != m_previousCaptureWindow)) { + + QPoint wumLocalPos; + if (QWindowsWindow *wumPlatformWindow = QWindowsWindow::windowsWindowOf(currentWindowUnderPointer)) { + wumLocalPos = wumPlatformWindow->mapFromGlobal(globalPos); + wumPlatformWindow->applyCursor(); + } + qCDebug(lcQpaEvents) << "Entering window " << currentWindowUnderPointer; + QWindowSystemInterface::handleEnterEvent(currentWindowUnderPointer, wumLocalPos, globalPos); + } + + // We need to track m_windowUnderPointer separately from m_currentWindow, as Windows + // mouse tracking will not trigger WM_MOUSELEAVE for leaving window when mouse capture is set. + m_windowUnderPointer = currentWindowUnderPointer; + } + + m_previousCaptureWindow = hasCapture ? window : nullptr; +} + bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPointerInfo) @@ -448,9 +569,7 @@ bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND h const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos); const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); const Qt::MouseButtons mouseButtons = mouseButtonsFromPointerFlags(pointerInfo->pointerFlags); - QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos); - QWindowsWindow *platformWindow = static_cast(window->handle()); switch (msg.message) { case WM_NCPOINTERDOWN: @@ -469,38 +588,17 @@ bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND h keyModifiers, Qt::MouseEventNotSynthesized); return false; // To allow window dragging, etc. } else { - if (eventType == QEvent::MouseButtonPress) { - // Implement "Click to focus" for native child windows (unless it is a native widget window). - if (!window->isTopLevel() && !window->inherits("QWidgetWindow") && QGuiApplication::focusWindow() != window) - window->requestActivate(); - } - if (currentWindowUnderPointer != m_windowUnderPointer) { - if (m_windowUnderPointer && m_windowUnderPointer == m_currentWindow) { - QWindowSystemInterface::handleLeaveEvent(m_windowUnderPointer); - m_currentWindow = nullptr; - } - - if (currentWindowUnderPointer) { - if (currentWindowUnderPointer != m_currentWindow) { - QWindowSystemInterface::handleEnterEvent(currentWindowUnderPointer, localPos, globalPos); - m_currentWindow = currentWindowUnderPointer; - if (QWindowsWindow *wumPlatformWindow = QWindowsWindow::windowsWindowOf(currentWindowUnderPointer)) - wumPlatformWindow->applyCursor(); - trackLeave(hwnd); - } - } else { - platformWindow->applyCursor(); - } - m_windowUnderPointer = currentWindowUnderPointer; - } + + handleCaptureRelease(window, currentWindowUnderPointer, hwnd, eventType, mouseButtons); + handleEnterLeave(window, currentWindowUnderPointer, globalPos); QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, button, eventType, keyModifiers, Qt::MouseEventNotSynthesized); // The initial down click over the QSizeGrip area, which posts a resize WM_SYSCOMMAND // has go to through DefWindowProc() for resizing to work, so we return false here, - // unless the mouse is captured, as it would mess with menu processing. - return msg.message != WM_POINTERDOWN || GetCapture(); + // unless the click was on a menu, as it would mess with menu processing. + return msg.message != WM_POINTERDOWN || isMenuWindow(window); } } case WM_POINTERHWHEEL: @@ -770,7 +868,6 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW } const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); - QWindowsWindow *platformWindow = static_cast(window->handle()); if (et == QtWindows::MouseWheelEvent) { @@ -792,36 +889,20 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW if (msg.message == WM_MOUSELEAVE) { if (window == m_currentWindow) { - QWindowSystemInterface::handleLeaveEvent(window); + QWindow *leaveTarget = m_windowUnderPointer ? m_windowUnderPointer : m_currentWindow; + qCDebug(lcQpaEvents) << "Leaving window " << leaveTarget; + QWindowSystemInterface::handleLeaveEvent(leaveTarget); m_windowUnderPointer = nullptr; m_currentWindow = nullptr; - platformWindow->applyCursor(); } return false; } QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos); + const Qt::MouseButtons mouseButtons = mouseButtonsFromKeyState(msg.wParam); - if (currentWindowUnderPointer != m_windowUnderPointer) { - if (m_windowUnderPointer && m_windowUnderPointer == m_currentWindow) { - QWindowSystemInterface::handleLeaveEvent(m_windowUnderPointer); - m_currentWindow = nullptr; - } - - if (currentWindowUnderPointer) { - if (currentWindowUnderPointer != m_currentWindow) { - QWindowSystemInterface::handleEnterEvent(currentWindowUnderPointer, localPos, globalPos); - m_currentWindow = currentWindowUnderPointer; - if (QWindowsWindow *wumPlatformWindow = QWindowsWindow::windowsWindowOf(currentWindowUnderPointer)) - wumPlatformWindow->applyCursor(); - trackLeave(hwnd); - } - } else { - platformWindow->applyCursor(); - } - m_windowUnderPointer = currentWindowUnderPointer; - } - + handleCaptureRelease(window, currentWindowUnderPointer, hwnd, QEvent::MouseMove, mouseButtons); + handleEnterLeave(window, currentWindowUnderPointer, globalPos); return false; } diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.h b/src/plugins/platforms/windows/qwindowspointerhandler.h index 3861ebf919..a586c7863c 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.h +++ b/src/plugins/platforms/windows/qwindowspointerhandler.h @@ -46,6 +46,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -68,11 +69,14 @@ private: bool translateMouseTouchPadEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPointerInfo); 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); + void handleCaptureRelease(QWindow *window, QWindow *currentWindowUnderPointer, HWND hwnd, QEvent::Type eventType, Qt::MouseButtons mouseButtons); + void handleEnterLeave(QWindow *window, QWindow *currentWindowUnderPointer, QPoint globalPos); QTouchDevice *m_touchDevice = nullptr; QHash m_lastTouchPositions; QPointer m_windowUnderPointer; QPointer m_currentWindow; + QWindow *m_previousCaptureWindow = nullptr; bool m_needsEnterOnPointerUpdate = false; }; -- cgit v1.2.3 From 4dc2bc323c985bdceb27f096dd6c8e7af657bb6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 2 Jan 2019 19:35:07 +0100 Subject: macOS: Remove Mojave forward-declarations now that we build with Xcode 10 Change-Id: I8528932f3744fbf3473219b6eeda7c26ac039b67 Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qcocoatheme.mm | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index c46df25b66..efe670abed 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -80,12 +80,7 @@ #include -#if !QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14) -@interface NSApplication (MojaveForwardDeclarations) -@property (readonly, strong) NSAppearance *effectiveAppearance NS_AVAILABLE_MAC(10_14); -@end -#endif - +#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14) @interface QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver) : NSObject @property (readonly, nonatomic) QCocoaTheme *theme; - (instancetype)initWithTheme:(QCocoaTheme *)theme; @@ -124,6 +119,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaThemeAppAppearanceObserver); self.theme->handleSystemThemeChange(); } @end +#endif // QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14) QT_BEGIN_NAMESPACE @@ -132,8 +128,10 @@ const char *QCocoaTheme::name = "cocoa"; QCocoaTheme::QCocoaTheme() : m_systemPalette(nullptr), m_appearanceObserver(nil) { +#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14) if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) m_appearanceObserver = [[QCocoaThemeAppAppearanceObserver alloc] initWithTheme:this]; +#endif [[NSNotificationCenter defaultCenter] addObserverForName:NSSystemColorsDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *) { -- cgit v1.2.3 From 6191249259719dee6f8f6eb42289e0582f1c02bc Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Thu, 3 Jan 2019 13:33:28 +0100 Subject: Use the AndroidDeadlockProtector when using a blockingqueued connection This amends 2afe4a1a074096a3a6476aae21e732c418717da7 to account for cases where it was crashing when it was using the QueuedConnection. The problem came from the fact it was blocking while waiting for a surface update which was pending to come later on, but the Android thread was already blocked which prevented it from being processed. Fixes: QTBUG-72101 Change-Id: I43e355cf1a7792599f23827903d065b1b1298902 Reviewed-by: BogDan Vatra --- src/plugins/platforms/android/qandroidinputcontext.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index 7b3546f9bb..394e284bb6 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -99,13 +99,12 @@ static jfieldID m_selectionStartFieldID = 0; static jfieldID m_startOffsetFieldID = 0; static jfieldID m_textFieldID = 0; -Q_DECLARE_METATYPE(std::function) - static void runOnQtThread(const std::function &func) { - const bool block = QGuiApplication::applicationState() >= Qt::ApplicationInactive; - QMetaObject::invokeMethod(m_androidInputContext, "safeCall", - block ? Qt::BlockingQueuedConnection : Qt::QueuedConnection, Q_ARG(std::function, func)); + AndroidDeadlockProtector protector; + if (!protector.acquire()) + return; + QMetaObject::invokeMethod(m_androidInputContext, "safeCall", Qt::BlockingQueuedConnection, Q_ARG(std::function, func)); } static jboolean beginBatchEdit(JNIEnv */*env*/, jobject /*thiz*/) @@ -516,7 +515,6 @@ QAndroidInputContext::QAndroidInputContext() m_handleMode = Hidden; updateSelectionHandles(); }); - qRegisterMetaType>(); } QAndroidInputContext::~QAndroidInputContext() -- cgit v1.2.3 From fe63900dc9891dd355ca1f10d6c7e5fd1516f5d5 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Mon, 5 Nov 2018 14:26:24 +0100 Subject: xcb: rework focus-in peeker so we can drop PeekFunc API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The API for registering temporary peek function was added ~7 years ago by 78264f333eb7c262380714ed6517562266f11a03. It was never been used for anything else. The solution from 78264f333 also did not work very well on KDE desktop, quoting Martin Flöser: "In case the keyboard gets grabbed by another process and immediately ungrabbed the active Qt application window receives a FocusOut and a FocusIn event. FocusOut on the grab of keyboard, FocusIn on the ungrab. Qt registers a peek function for checking the FocusIn event, but the timespan is too short: the new event is not yet queued. This causes a QEvent::WindowDeactivate being emitted, followed directly by a QEvent::WindowActivate. This has quite some side effects, for example rendering flickering in the GUI (switching to inactive/active in short time frame), hooks on WindowDeactivate being run, etc. Real world examples for such short keyboard grabs are global shortcut listener applications like kglobalaccel5. It has e.g. a passive key grab on the mute key, which is then turned into an active grab when the key is grabbed. Kglobalaccel5 immediately ungrabs the keyboard and flushes the connection if it gets a key event, but it of course causes the sequence of FocusOut and FocusIn events in the active Qt window." Reworked the code to use QTimer instead, which is more elegant solution, because it does not rely on race-conditions, but uses a concreate time to wait instead. Also the need to write focusInPeeker() caused us to duplicate event handlers that were present already elsewhere. Change-Id: I647e52fb2634fdf55a640e19b13265c356f96c95 Reviewed-by: Mikhail Svetkin Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbconnection.cpp | 26 +++++----------------- src/plugins/platforms/xcb/qxcbconnection.h | 10 ++++----- src/plugins/platforms/xcb/qxcbwindow.cpp | 33 ++++------------------------ 3 files changed, 15 insertions(+), 54 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 37ee980924..15ffaaf2e2 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -131,6 +131,12 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra if (!m_startupId.isNull()) qunsetenv("DESKTOP_STARTUP_ID"); + m_focusInTimer.setSingleShot(true); + m_focusInTimer.callOnTimeout([]() { + // No FocusIn events for us, proceed with FocusOut normally. + QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason); + }); + sync(); } @@ -731,11 +737,6 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) m_glIntegration->handleXcbEvent(event, response_type); } -void QXcbConnection::addPeekFunc(PeekFunc f) -{ - m_peekFuncs.append(f); -} - void QXcbConnection::setFocusWindow(QWindow *w) { m_focusWindow = w ? static_cast(w->handle()) : nullptr; @@ -1015,15 +1016,6 @@ void QXcbConnection::processXcbEvents(QEventLoop::ProcessEventsFlags flags) if (compressEvent(event)) continue; - auto isWaitingFor = [=](PeekFunc peekFunc) { - // These callbacks return true if the event is what they were - // waiting for, remove them from the list in that case. - return peekFunc(this, event); - }; - m_peekFuncs.erase(std::remove_if(m_peekFuncs.begin(), m_peekFuncs.end(), - isWaitingFor), - m_peekFuncs.end()); - handleXcbEvent(event); // The lock-based solution used to free the lock inside this loop, @@ -1032,12 +1024,6 @@ void QXcbConnection::processXcbEvents(QEventLoop::ProcessEventsFlags flags) m_eventQueue->flushBufferedEvents(); } - // Indicate with a null event that the event the callbacks are waiting for - // is not in the queue currently. - for (PeekFunc f : qAsConst(m_peekFuncs)) - f(this, nullptr); - m_peekFuncs.clear(); - xcb_flush(xcb_connection()); } diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 47036ca257..d63888b48f 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -43,6 +43,7 @@ #include #include +#include #include #include "qxcbexport.h" #include @@ -183,9 +184,6 @@ public: QXcbWindowEventListener *windowEventListenerFromId(xcb_window_t id); QXcbWindow *platformWindowFromId(xcb_window_t id); - typedef bool (*PeekFunc)(QXcbConnection *, xcb_generic_event_t *); - void addPeekFunc(PeekFunc f); - inline xcb_timestamp_t time() const { return m_time; } inline void setTime(xcb_timestamp_t t) { if (t > m_time) m_time = t; } @@ -247,6 +245,8 @@ public: void flush() { xcb_flush(xcb_connection()); } void processXcbEvents(QEventLoop::ProcessEventsFlags flags); + QTimer &focusInTimer() { return m_focusInTimer; }; + protected: bool event(QEvent *e) override; @@ -364,8 +364,6 @@ private: WindowMapper m_mapper; - QVector m_peekFuncs; - Qt::MouseButtons m_buttonState = 0; Qt::MouseButton m_button = Qt::NoButton; @@ -386,6 +384,8 @@ private: friend class QXcbEventQueue; QByteArray m_xdgCurrentDesktop; + QTimer m_focusInTimer; + }; #if QT_CONFIG(xcb_xinput) #if QT_CONFIG(tabletevent) diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 3bfcbf2adb..9382488b74 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -843,40 +843,12 @@ void QXcbWindow::doFocusIn() QWindowSystemInterface::handleWindowActivated(w, Qt::ActiveWindowFocusReason); } -static bool focusInPeeker(QXcbConnection *connection, xcb_generic_event_t *event) -{ - if (!event) { - // FocusIn event is not in the queue, proceed with FocusOut normally. - QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason); - return true; - } - uint response_type = event->response_type & ~0x80; - if (response_type == XCB_FOCUS_IN) { - // Ignore focus events that are being sent only because the pointer is over - // our window, even if the input focus is in a different window. - xcb_focus_in_event_t *e = (xcb_focus_in_event_t *) event; - if (e->detail != XCB_NOTIFY_DETAIL_POINTER) - return true; - } - - /* We are also interested in XEMBED_FOCUS_IN events */ - if (response_type == XCB_CLIENT_MESSAGE) { - xcb_client_message_event_t *cme = (xcb_client_message_event_t *)event; - if (cme->type == connection->atom(QXcbAtom::_XEMBED) - && cme->data.data32[1] == XEMBED_FOCUS_IN) - return true; - } - - return false; -} - void QXcbWindow::doFocusOut() { connection()->setFocusWindow(nullptr); relayFocusToModalWindow(); // Do not set the active window to nullptr if there is a FocusIn coming. - // The FocusIn handler will update QXcbConnection::setFocusWindow() accordingly. - connection()->addPeekFunc(focusInPeeker); + connection()->focusInTimer().start(400); } struct QtMotifWmHints { @@ -2264,6 +2236,8 @@ void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *event) // our window, even if the input focus is in a different window. if (event->detail == XCB_NOTIFY_DETAIL_POINTER) return; + + connection()->focusInTimer().stop(); doFocusIn(); } @@ -2491,6 +2465,7 @@ void QXcbWindow::handleXEmbedMessage(const xcb_client_message_event_t *event) xcbScreen()->windowShown(this); break; case XEMBED_FOCUS_IN: + connection()->focusInTimer().stop(); Qt::FocusReason reason; switch (event->data.data32[2]) { case XEMBED_FOCUS_FIRST: -- cgit v1.2.3 From 0c54e0251f27fab85baa03fff7213600419f491c Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Wed, 2 Jan 2019 21:54:31 +0100 Subject: ibus: send batched QInputMethodQueryEvent event Change-Id: Idc537a497569d86bb63776934d5e0bbbc39291be Reviewed-by: Mikhail Svetkin Reviewed-by: Lars Knoll --- .../ibus/qibusplatforminputcontext.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp index 3a54f33832..c0979e7864 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp @@ -217,17 +217,14 @@ void QIBusPlatformInputContext::update(Qt::InputMethodQueries q) && (q.testFlag(Qt::ImSurroundingText) || q.testFlag(Qt::ImCursorPosition) || q.testFlag(Qt::ImAnchorPosition))) { - QInputMethodQueryEvent srrndTextQuery(Qt::ImSurroundingText); - QInputMethodQueryEvent cursorPosQuery(Qt::ImCursorPosition); - QInputMethodQueryEvent anchorPosQuery(Qt::ImAnchorPosition); - QCoreApplication::sendEvent(input, &srrndTextQuery); - QCoreApplication::sendEvent(input, &cursorPosQuery); - QCoreApplication::sendEvent(input, &anchorPosQuery); + QInputMethodQueryEvent query(Qt::ImSurroundingText | Qt::ImCursorPosition | Qt::ImAnchorPosition); - QString surroundingText = srrndTextQuery.value(Qt::ImSurroundingText).toString(); - uint cursorPosition = cursorPosQuery.value(Qt::ImCursorPosition).toUInt(); - uint anchorPosition = anchorPosQuery.value(Qt::ImAnchorPosition).toUInt(); + QCoreApplication::sendEvent(input, &query); + + QString surroundingText = query.value(Qt::ImSurroundingText).toString(); + uint cursorPosition = query.value(Qt::ImCursorPosition).toUInt(); + uint anchorPosition = query.value(Qt::ImAnchorPosition).toUInt(); QIBusText text; text.text = surroundingText; -- cgit v1.2.3 From 2cd633e7eef6f67ee7ed5f23afea7e0f23c7eb03 Mon Sep 17 00:00:00 2001 From: Max Mazurov Date: Wed, 2 Jan 2019 16:55:24 +0000 Subject: XCB: Use application name for X11 selection owner name This makes it possible for clipboard managers (or other scripts) to distinguish different Qt applications and act differently. Change-Id: I5bc5a1914b51127b24a81142ca9dbdb196ffd0d8 Fixes: QTBUG-72806 Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbconnection.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 37ee980924..29acf0e86d 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -39,6 +39,7 @@ #include #include +#include #include "qxcbconnection.h" #include "qxcbkeyboard.h" @@ -817,7 +818,7 @@ xcb_window_t QXcbConnection::getQtSelectionOwner() 0); // value list QXcbWindow::setWindowTitle(connection(), m_qtSelectionOwner, - QStringLiteral("Qt Selection Window")); + QLatin1String("Qt Selection Owner for ") + QCoreApplication::applicationName()); } return m_qtSelectionOwner; } -- cgit v1.2.3 From afb08ac5dae930912768f3f0ae4352189b8c3641 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Mon, 7 Jan 2019 13:54:40 +0100 Subject: Use jint instead of jboolean where applicable and initialize variables This amends change c6af7cf666d43c68c90ad829c3a55d84ee8e4a3e which had incorrectly used jboolean to store the result of getCursorCapsMode() and thus lost the information it was passing. The variables are also initialized in case there is a lock problem when calling runOnQtThread. Fixes: QTBUG-72783 Change-Id: Ibdc21e348c25ee4fdff242d14b3722c6551b042c Reviewed-by: BogDan Vatra --- .../platforms/android/qandroidinputcontext.cpp | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index 394e284bb6..cdc52e1cb4 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -115,7 +115,7 @@ static jboolean beginBatchEdit(JNIEnv */*env*/, jobject /*thiz*/) #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug("@@@ BEGINBATCH"); #endif - jboolean res; + jboolean res = JNI_FALSE; runOnQtThread([&res]{res = m_androidInputContext->beginBatchEdit();}); return res; } @@ -129,7 +129,7 @@ static jboolean endBatchEdit(JNIEnv */*env*/, jobject /*thiz*/) qDebug("@@@ ENDBATCH"); #endif - jboolean res; + jboolean res = JNI_FALSE; runOnQtThread([&res]{res = m_androidInputContext->endBatchEdit();}); return res; } @@ -148,7 +148,7 @@ static jboolean commitText(JNIEnv *env, jobject /*thiz*/, jstring text, jint new #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug() << "@@@ COMMIT" << str << newCursorPosition; #endif - jboolean res; + jboolean res = JNI_FALSE; runOnQtThread([&]{res = m_androidInputContext->commitText(str, newCursorPosition);}); return res; } @@ -161,7 +161,7 @@ static jboolean deleteSurroundingText(JNIEnv */*env*/, jobject /*thiz*/, jint le #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug() << "@@@ DELETE" << leftLength << rightLength; #endif - jboolean res; + jboolean res = JNI_FALSE; runOnQtThread([&]{res = m_androidInputContext->deleteSurroundingText(leftLength, rightLength);}); return res; } @@ -174,7 +174,7 @@ static jboolean finishComposingText(JNIEnv */*env*/, jobject /*thiz*/) #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug("@@@ FINISH"); #endif - jboolean res; + jboolean res = JNI_FALSE; runOnQtThread([&]{res = m_androidInputContext->finishComposingText();}); return res; } @@ -184,7 +184,7 @@ static jint getCursorCapsMode(JNIEnv */*env*/, jobject /*thiz*/, jint reqModes) if (!m_androidInputContext) return 0; - jboolean res; + jint res = 0; runOnQtThread([&]{res = m_androidInputContext->getCursorCapsMode(reqModes);}); return res; } @@ -269,7 +269,7 @@ static jboolean setComposingText(JNIEnv *env, jobject /*thiz*/, jstring text, ji #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug() << "@@@ SET" << str << newCursorPosition; #endif - jboolean res; + jboolean res = JNI_FALSE; runOnQtThread([&]{res = m_androidInputContext->setComposingText(str, newCursorPosition);}); return res; } @@ -282,7 +282,7 @@ static jboolean setComposingRegion(JNIEnv */*env*/, jobject /*thiz*/, jint start #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug() << "@@@ SETR" << start << end; #endif - jboolean res; + jboolean res = JNI_FALSE; runOnQtThread([&]{res = m_androidInputContext->setComposingRegion(start, end);}); return res; } @@ -296,7 +296,7 @@ static jboolean setSelection(JNIEnv */*env*/, jobject /*thiz*/, jint start, jint #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug() << "@@@ SETSEL" << start << end; #endif - jboolean res; + jboolean res = JNI_FALSE; runOnQtThread([&]{res = m_androidInputContext->setSelection(start, end);}); return res; @@ -310,7 +310,7 @@ static jboolean selectAll(JNIEnv */*env*/, jobject /*thiz*/) #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug("@@@ SELALL"); #endif - jboolean res; + jboolean res = JNI_FALSE; runOnQtThread([&]{res = m_androidInputContext->selectAll();}); return res; } @@ -323,7 +323,7 @@ static jboolean cut(JNIEnv */*env*/, jobject /*thiz*/) #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug("@@@"); #endif - jboolean res; + jboolean res = JNI_FALSE; runOnQtThread([&]{res = m_androidInputContext->cut();}); return res; } @@ -336,7 +336,7 @@ static jboolean copy(JNIEnv */*env*/, jobject /*thiz*/) #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug("@@@"); #endif - jboolean res; + jboolean res = JNI_FALSE; runOnQtThread([&]{res = m_androidInputContext->copy();}); return res; } @@ -349,7 +349,7 @@ static jboolean copyURL(JNIEnv */*env*/, jobject /*thiz*/) #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug("@@@"); #endif - jboolean res; + jboolean res = JNI_FALSE; runOnQtThread([&]{res = m_androidInputContext->copyURL();}); return res; } @@ -362,7 +362,7 @@ static jboolean paste(JNIEnv */*env*/, jobject /*thiz*/) #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug("@@@ PASTE"); #endif - jboolean res; + jboolean res = JNI_FALSE; runOnQtThread([&]{res = m_androidInputContext->paste();}); return res; } -- cgit v1.2.3 From e70230405dce5ac03817fc564a3a8ba5f208422a Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Tue, 31 Oct 2017 14:29:37 +0100 Subject: Don't treat the ampersand in a titlebar as a mnemonic As the mnemonic has no meaning when it is in a dockwidget title, we should just treat it as a literal ampersand instead and display it as such. Fixes: QTBUG-54485 Change-Id: I96c856ce2771a68d226f48f8f47affc24f1c53cd Reviewed-by: Frederik Gladhorn --- src/plugins/styles/mac/qmacstyle_mac.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index b84448d5e2..f647b95458 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -3922,7 +3922,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter titleRect.width()); const auto text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width()); - proxy()->drawItemText(p, titleRect, Qt::AlignCenter | Qt::TextShowMnemonic, dwOpt->palette, + proxy()->drawItemText(p, titleRect, Qt::AlignCenter, dwOpt->palette, dwOpt->state & State_Enabled, text, QPalette::WindowText); } p->restore(); -- cgit v1.2.3 From 8551b7d93ce3767b2cebb0d442e72d8ad450539e Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Thu, 20 Dec 2018 09:51:30 +0100 Subject: QSQL: cleanup/modernize PostgreSQL plugin Cleanup/modernize the PostgreSQL plugin - use nullptr - use range-based for loop - use QStringLiteral or QByteArray::fromRawData instead QLatin1String/QString::fromLatin1 where possible - use QRegularExpression instead QRegExp - use QQueue instead QList - uppercase SQL keywords Change-Id: Ie22be1538328ff1e2b663066ede96741d271e050 Reviewed-by: Andy Shaw --- src/plugins/sqldrivers/psql/main.cpp | 8 +- src/plugins/sqldrivers/psql/qsql_psql.cpp | 167 ++++++++++++++++-------------- src/plugins/sqldrivers/psql/qsql_psql_p.h | 4 +- 3 files changed, 94 insertions(+), 85 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/sqldrivers/psql/main.cpp b/src/plugins/sqldrivers/psql/main.cpp index c5d546f6ff..a0862a238a 100644 --- a/src/plugins/sqldrivers/psql/main.cpp +++ b/src/plugins/sqldrivers/psql/main.cpp @@ -61,11 +61,9 @@ QPSQLDriverPlugin::QPSQLDriverPlugin() QSqlDriver* QPSQLDriverPlugin::create(const QString &name) { - if (name == QLatin1String("QPSQL") || name == QLatin1String("QPSQL7")) { - QPSQLDriver* driver = new QPSQLDriver(); - return driver; - } - return 0; + if (name == QLatin1String("QPSQL") || name == QLatin1String("QPSQL7")) + return new QPSQLDriver; + return nullptr; } QT_END_NAMESPACE diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp index 7ad9db1ea8..9fc9317da6 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql.cpp +++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include #include @@ -54,6 +54,8 @@ #include #include +#include + #include #include @@ -147,10 +149,10 @@ class QPSQLDriverPrivate final : public QSqlDriverPrivate Q_DECLARE_PUBLIC(QPSQLDriver) public: QPSQLDriverPrivate() : QSqlDriverPrivate(), - connection(0), + connection(nullptr), isUtf8(false), pro(QPSQLDriver::Version6), - sn(0), + sn(nullptr), pendingNotifyCheck(false), hasBackslashEscape(false), stmtCount(0), @@ -187,11 +189,13 @@ public: void QPSQLDriverPrivate::appendTables(QStringList &tl, QSqlQuery &t, QChar type) { - QString query = QString::fromLatin1("select pg_class.relname, pg_namespace.nspname from pg_class " - "left join pg_namespace on (pg_class.relnamespace = pg_namespace.oid) " - "where (pg_class.relkind = '%1') and (pg_class.relname !~ '^Inv') " - "and (pg_class.relname !~ '^pg_') " - "and (pg_namespace.nspname != 'information_schema')").arg(type); + const QString query = + QStringLiteral("SELECT pg_class.relname, pg_namespace.nspname FROM pg_class " + "LEFT JOIN pg_namespace ON (pg_class.relnamespace = pg_namespace.oid) " + "WHERE (pg_class.relkind = '") + type + + QStringLiteral("') AND (pg_class.relname !~ '^Inv') " + "AND (pg_class.relname !~ '^pg_') " + "AND (pg_namespace.nspname != 'information_schema')"); t.exec(query); while (t.next()) { QString schema = t.value(1).toString(); @@ -294,10 +298,10 @@ public: Q_DECLARE_SQLDRIVER_PRIVATE(QPSQLDriver) QPSQLResultPrivate(QPSQLResult *q, const QPSQLDriver *drv) : QSqlResultPrivate(q, drv), - result(0), + result(nullptr), + stmtId(InvalidStatementId), currentSize(-1), canFetchMoreRows(false), - stmtId(InvalidStatementId), preparedQueriesEnabled(false) { } @@ -305,12 +309,12 @@ public: void deallocatePreparedStmt(); PGresult *result; - QList nextResultSets; + std::queue nextResultSets; + QString preparedStmtId; + StatementId stmtId; int currentSize; bool canFetchMoreRows; - StatementId stmtId; bool preparedQueriesEnabled; - QString preparedStmtId; bool processResults(); }; @@ -423,7 +427,7 @@ static QVariant::Type qDecodePSQLType(int t) void QPSQLResultPrivate::deallocatePreparedStmt() { - const QString stmt = QLatin1String("DEALLOCATE ") + preparedStmtId; + const QString stmt = QStringLiteral("DEALLOCATE ") + preparedStmtId; PGresult *result = drv_d_func()->exec(stmt); if (PQresultStatus(result) != PGRES_COMMAND_OK) @@ -460,8 +464,10 @@ void QPSQLResult::cleanup() if (d->result) PQclear(d->result); d->result = nullptr; - while (!d->nextResultSets.isEmpty()) - PQclear(d->nextResultSets.takeFirst()); + while (!d->nextResultSets.empty()) { + PQclear(d->nextResultSets.front()); + d->nextResultSets.pop(); + } if (d->stmtId != InvalidStatementId) { if (d->drv_d_func()) d->drv_d_func()->finishQuery(d->stmtId); @@ -622,7 +628,11 @@ bool QPSQLResult::nextResult() if (d->result) PQclear(d->result); - d->result = d->nextResultSets.isEmpty() ? nullptr : d->nextResultSets.takeFirst(); + d->result = nullptr; + if (!d->nextResultSets.empty()) { + d->result = d->nextResultSets.front(); + d->nextResultSets.pop(); + } return d->processResults(); } @@ -646,9 +656,9 @@ QVariant QPSQLResult::data(int i) return d->drv_d_func()->isUtf8 ? QString::fromUtf8(val) : QString::fromLatin1(val); case QVariant::LongLong: if (val[0] == '-') - return QString::fromLatin1(val).toLongLong(); + return QByteArray::fromRawData(val, qstrlen(val)).toLongLong(); else - return QString::fromLatin1(val).toULongLong(); + return QByteArray::fromRawData(val, qstrlen(val)).toULongLong(); case QVariant::Int: return atoi(val); case QVariant::Double: { @@ -754,7 +764,7 @@ bool QPSQLResult::reset (const QString& query) if (!isForwardOnly()) { // Fetch all result sets right away while (PGresult *nextResultSet = d->drv_d_func()->getResult(d->stmtId)) - d->nextResultSets.append(nextResultSet); + d->nextResultSets.push(nextResultSet); } return d->processResults(); } @@ -768,7 +778,8 @@ int QPSQLResult::size() int QPSQLResult::numRowsAffected() { Q_D(const QPSQLResult); - return QString::fromLatin1(PQcmdTuples(d->result)).toInt(); + const char *tuples = PQcmdTuples(d->result); + return QByteArray::fromRawData(tuples, qstrlen(tuples)).toInt(); } QVariant QPSQLResult::lastInsertId() const @@ -777,7 +788,7 @@ QVariant QPSQLResult::lastInsertId() const if (d->drv_d_func()->pro >= QPSQLDriver::Version8_1) { QSqlQuery qry(driver()->createResult()); // Most recent sequence value obtained from nextval - if (qry.exec(QLatin1String("SELECT lastval();")) && qry.next()) + if (qry.exec(QStringLiteral("SELECT lastval();")) && qry.next()) return qry.value(0); } else if (isActive()) { Oid id = PQoidValue(d->result); @@ -868,15 +879,13 @@ static QString qCreateParamString(const QVector &boundValues, const QS QString params; QSqlField f; - for (int i = 0; i < boundValues.count(); ++i) { - const QVariant &val = boundValues.at(i); - + for (const QVariant &val : boundValues) { f.setType(val.type()); if (val.isNull()) f.clear(); else f.setValue(val); - if(!params.isNull()) + if (!params.isNull()) params.append(QLatin1String(", ")); params.append(driver->formatValue(f)); } @@ -886,7 +895,7 @@ static QString qCreateParamString(const QVector &boundValues, const QS QString qMakePreparedStmtId() { static QBasicAtomicInt qPreparedStmtCount = Q_BASIC_ATOMIC_INITIALIZER(0); - QString id = QLatin1String("qpsqlpstmt_") + QString::number(qPreparedStmtCount.fetchAndAddRelaxed(1) + 1, 16); + QString id = QStringLiteral("qpsqlpstmt_") + QString::number(qPreparedStmtCount.fetchAndAddRelaxed(1) + 1, 16); return id; } @@ -902,7 +911,7 @@ bool QPSQLResult::prepare(const QString &query) d->deallocatePreparedStmt(); const QString stmtId = qMakePreparedStmtId(); - const QString stmt = QString::fromLatin1("PREPARE %1 AS ").arg(stmtId).append(d->positionalToNamedBinding(query)); + const QString stmt = QStringLiteral("PREPARE %1 AS ").arg(stmtId).append(d->positionalToNamedBinding(query)); PGresult *result = d->drv_d_func()->exec(stmt); @@ -930,9 +939,9 @@ bool QPSQLResult::exec() QString stmt; const QString params = qCreateParamString(boundValues(), driver()); if (params.isEmpty()) - stmt = QString::fromLatin1("EXECUTE %1").arg(d->preparedStmtId); + stmt = QStringLiteral("EXECUTE %1").arg(d->preparedStmtId); else - stmt = QString::fromLatin1("EXECUTE %1 (%2)").arg(d->preparedStmtId, params); + stmt = QStringLiteral("EXECUTE %1 (%2)").arg(d->preparedStmtId, params); d->stmtId = d->drv_d_func()->sendQuery(stmt); if (d->stmtId == InvalidStatementId) { @@ -948,7 +957,7 @@ bool QPSQLResult::exec() if (!isForwardOnly()) { // Fetch all result sets right away while (PGresult *nextResultSet = d->drv_d_func()->getResult(d->stmtId)) - d->nextResultSets.append(nextResultSet); + d->nextResultSets.push(nextResultSet); } return d->processResults(); } @@ -994,7 +1003,7 @@ void QPSQLDriverPrivate::detectBackslashEscape() hasBackslashEscape = true; } else { hasBackslashEscape = false; - PGresult* result = exec(QLatin1String("SELECT '\\\\' x")); + PGresult* result = exec(QStringLiteral("SELECT '\\\\' x")); int status = PQresultStatus(result); if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK) if (QString::fromLatin1(PQgetvalue(result, 0, 0)) == QLatin1String("\\")) @@ -1072,20 +1081,21 @@ static QPSQLDriver::Protocol qMakePSQLVersion(int vMaj, int vMin) static QPSQLDriver::Protocol qFindPSQLVersion(const QString &versionString) { - const QRegExp rx(QStringLiteral("(\\d+)(?:\\.(\\d+))?")); - if (rx.indexIn(versionString) != -1) { + const QRegularExpression rx(QStringLiteral("(\\d+)(?:\\.(\\d+))?")); + const QRegularExpressionMatch match = rx.match(versionString); + if (match.hasMatch()) { // Beginning with PostgreSQL version 10, a major release is indicated by // increasing the first part of the version, e.g. 10 to 11. // Before version 10, a major release was indicated by increasing either // the first or second part of the version number, e.g. 9.5 to 9.6. - int vMaj = rx.cap(1).toInt(); + int vMaj = match.capturedRef(1).toInt(); int vMin; if (vMaj >= 10) { vMin = 0; } else { - if (rx.cap(2).isEmpty()) + if (match.capturedRef(2).isEmpty()) return QPSQLDriver::VersionUnknown; - vMin = rx.cap(2).toInt(); + vMin = match.capturedRef(2).toInt(); } return qMakePSQLVersion(vMaj, vMin); } @@ -1096,7 +1106,7 @@ static QPSQLDriver::Protocol qFindPSQLVersion(const QString &versionString) QPSQLDriver::Protocol QPSQLDriverPrivate::getPSQLVersion() { QPSQLDriver::Protocol serverVersion = QPSQLDriver::Version6; - PGresult* result = exec("select version()"); + PGresult* result = exec("SELECT version()"); int status = PQresultStatus(result); if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK) { serverVersion = qFindPSQLVersion( @@ -1355,8 +1365,8 @@ QStringList QPSQLDriver::tables(QSql::TableType type) const if (type & QSql::Views) const_cast(d)->appendTables(tl, t, QLatin1Char('v')); if (type & QSql::SystemTables) { - t.exec(QLatin1String("select relname from pg_class where (relkind = 'r') " - "and (relname like 'pg_%') ")); + t.exec(QStringLiteral("SELECT relname FROM pg_class WHERE (relkind = 'r') " + "AND (relname LIKE 'pg_%') ")); while (t.next()) tl.append(t.value(0).toString()); } @@ -1394,20 +1404,20 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const else schema = std::move(schema).toLower(); - QString stmt = QLatin1String("SELECT pg_attribute.attname, pg_attribute.atttypid::int, " - "pg_class.relname " - "FROM pg_attribute, pg_class " - "WHERE %1 pg_class.oid IN " - "(SELECT indexrelid FROM pg_index WHERE indisprimary = true AND indrelid IN " - "(SELECT oid FROM pg_class WHERE relname = '%2')) " - "AND pg_attribute.attrelid = pg_class.oid " - "AND pg_attribute.attisdropped = false " - "ORDER BY pg_attribute.attnum"); + QString stmt = QStringLiteral("SELECT pg_attribute.attname, pg_attribute.atttypid::int, " + "pg_class.relname " + "FROM pg_attribute, pg_class " + "WHERE %1 pg_class.oid IN " + "(SELECT indexrelid FROM pg_index WHERE indisprimary = true AND indrelid IN " + "(SELECT oid FROM pg_class WHERE relname = '%2')) " + "AND pg_attribute.attrelid = pg_class.oid " + "AND pg_attribute.attisdropped = false " + "ORDER BY pg_attribute.attnum"); if (schema.isEmpty()) - stmt = stmt.arg(QLatin1String("pg_table_is_visible(pg_class.oid) AND")); + stmt = stmt.arg(QStringLiteral("pg_table_is_visible(pg_class.oid) AND")); else - stmt = stmt.arg(QString::fromLatin1("pg_class.relnamespace = (select oid from " - "pg_namespace where pg_namespace.nspname = '%1') AND").arg(schema)); + stmt = stmt.arg(QStringLiteral("pg_class.relnamespace = (SELECT oid FROM " + "pg_namespace WHERE pg_namespace.nspname = '%1') AND").arg(schema)); i.exec(stmt.arg(tbl)); while (i.isActive() && i.next()) { @@ -1438,23 +1448,23 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const else schema = std::move(schema).toLower(); - QString stmt = QLatin1String("select pg_attribute.attname, pg_attribute.atttypid::int, " - "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, " - "pg_attrdef.adsrc " - "from pg_class, pg_attribute " - "left join pg_attrdef on (pg_attrdef.adrelid = " - "pg_attribute.attrelid and pg_attrdef.adnum = pg_attribute.attnum) " - "where %1 " - "and pg_class.relname = '%2' " - "and pg_attribute.attnum > 0 " - "and pg_attribute.attrelid = pg_class.oid " - "and pg_attribute.attisdropped = false " - "order by pg_attribute.attnum"); + QString stmt = QStringLiteral("SELECT pg_attribute.attname, pg_attribute.atttypid::int, " + "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, " + "pg_attrdef.adsrc " + "FROM pg_class, pg_attribute " + "LEFT JOIN pg_attrdef ON (pg_attrdef.adrelid = " + "pg_attribute.attrelid AND pg_attrdef.adnum = pg_attribute.attnum) " + "WHERE %1 " + "AND pg_class.relname = '%2' " + "AND pg_attribute.attnum > 0 " + "AND pg_attribute.attrelid = pg_class.oid " + "AND pg_attribute.attisdropped = false " + "ORDER BY pg_attribute.attnum"); if (schema.isEmpty()) - stmt = stmt.arg(QLatin1String("pg_table_is_visible(pg_class.oid)")); + stmt = stmt.arg(QStringLiteral("pg_table_is_visible(pg_class.oid)")); else - stmt = stmt.arg(QString::fromLatin1("pg_class.relnamespace = (select oid from " - "pg_namespace where pg_namespace.nspname = '%1')").arg(schema)); + stmt = stmt.arg(QStringLiteral("pg_class.relnamespace = (SELECT oid FROM " + "pg_namespace WHERE pg_namespace.nspname = '%1')").arg(schema)); QSqlQuery query(createResult()); query.exec(stmt.arg(tbl)); @@ -1496,9 +1506,10 @@ inline void assignSpecialPsqlFloatValue(FloatType val, QString *target) QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const { Q_D(const QPSQLDriver); + const auto nullStr = [](){ return QStringLiteral("NULL"); }; QString r; if (field.isNull()) { - r = QLatin1String("NULL"); + r = nullStr(); } else { switch (int(field.type())) { case QVariant::DateTime: @@ -1507,14 +1518,14 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const // we force the value to be considered with a timezone information, and we force it to be UTC // this is safe since postgresql stores only the UTC value and not the timezone offset (only used // while parsing), so we have correct behavior in both case of with timezone and without tz - r = QLatin1String("TIMESTAMP WITH TIME ZONE ") + QLatin1Char('\'') + - QLocale::c().toString(field.value().toDateTime().toUTC(), QLatin1String("yyyy-MM-ddThh:mm:ss.zzz")) + + r = QStringLiteral("TIMESTAMP WITH TIME ZONE ") + QLatin1Char('\'') + + QLocale::c().toString(field.value().toDateTime().toUTC(), QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz")) + QLatin1Char('Z') + QLatin1Char('\''); } else { - r = QLatin1String("NULL"); + r = nullStr(); } #else - r = QLatin1String("NULL"); + r = nullStr(); #endif // datestring break; case QVariant::Time: @@ -1524,19 +1535,19 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const } else #endif { - r = QLatin1String("NULL"); + r = nullStr(); } break; case QVariant::String: r = QSqlDriver::formatValue(field, trimStrings); if (d->hasBackslashEscape) - r.replace(QLatin1String("\\"), QLatin1String("\\\\")); + r.replace(QLatin1Char('\\'), QLatin1String("\\\\")); break; case QVariant::Bool: if (field.value().toBool()) - r = QLatin1String("TRUE"); + r = QStringLiteral("TRUE"); else - r = QLatin1String("FALSE"); + r = QStringLiteral("FALSE"); break; case QVariant::ByteArray: { QByteArray ba(field.value().toByteArray()); @@ -1615,7 +1626,7 @@ bool QPSQLDriver::subscribeToNotification(const QString &name) // Add the name to the list of subscriptions here so that QSQLDriverPrivate::exec knows // to check for notifications immediately after executing the LISTEN d->seid << name; - QString query = QLatin1String("LISTEN ") + escapeIdentifier(name, QSqlDriver::TableName); + QString query = QStringLiteral("LISTEN ") + escapeIdentifier(name, QSqlDriver::TableName); PGresult *result = d->exec(query); if (PQresultStatus(result) != PGRES_COMMAND_OK) { d->seid.removeLast(); @@ -1651,7 +1662,7 @@ bool QPSQLDriver::unsubscribeFromNotification(const QString &name) return false; } - QString query = QLatin1String("UNLISTEN ") + escapeIdentifier(name, QSqlDriver::TableName); + QString query = QStringLiteral("UNLISTEN ") + escapeIdentifier(name, QSqlDriver::TableName); PGresult *result = d->exec(query); if (PQresultStatus(result) != PGRES_COMMAND_OK) { setLastError(qMakeError(tr("Unable to unsubscribe"), QSqlError::StatementError, d, result)); diff --git a/src/plugins/sqldrivers/psql/qsql_psql_p.h b/src/plugins/sqldrivers/psql/qsql_psql_p.h index 7e1849d857..4f372346c6 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql_p.h +++ b/src/plugins/sqldrivers/psql/qsql_psql_p.h @@ -96,8 +96,8 @@ public: UnknownLaterVersion = 100000 }; - explicit QPSQLDriver(QObject *parent=0); - explicit QPSQLDriver(PGconn *conn, QObject *parent=0); + explicit QPSQLDriver(QObject *parent = nullptr); + explicit QPSQLDriver(PGconn *conn, QObject *parent = nullptr); ~QPSQLDriver(); bool hasFeature(DriverFeature f) const override; bool open(const QString & db, -- cgit v1.2.3 From 5dadc3d807af89c37b002749d3b39bfc94b10acd Mon Sep 17 00:00:00 2001 From: Andreas Date: Fri, 11 Jan 2019 11:01:04 +0100 Subject: xcb: fix initialization of XRandr and XRender Fixes: QTBUG-72957 Change-Id: Ia698eef5dae4e2d35ca2e565fbdc23da40c83d8a Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbconnection_basic.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp index c69912c361..af72285135 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp @@ -287,7 +287,7 @@ void QXcbBasicConnection::initializeShm() logging->setEnabled(QtMsgType::QtWarningMsg, true); } -void QXcbBasicConnection::initializeXRandr() +void QXcbBasicConnection::initializeXRender() { const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_xcbConnection, &xcb_render_id); if (!reply || !reply->present) { @@ -303,7 +303,7 @@ void QXcbBasicConnection::initializeXRandr() return; } - m_hasXRandr = true; + m_hasXRender = true; m_xrenderVersion.first = xrenderQuery->major_version; m_xrenderVersion.second = xrenderQuery->minor_version; } @@ -337,7 +337,7 @@ void QXcbBasicConnection::initializeXFixes() m_xfixesFirstEvent = reply->first_event; } -void QXcbBasicConnection::initializeXRender() +void QXcbBasicConnection::initializeXRandr() { const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_xcbConnection, &xcb_randr_id); if (!reply || !reply->present) @@ -352,7 +352,7 @@ void QXcbBasicConnection::initializeXRender() return; } - m_hasXRender = true; + m_hasXRandr = true; m_xrandrFirstEvent = reply->first_event; } -- cgit v1.2.3 From af99497bdbcfb5202bd226b76910de9fd82e0625 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Mon, 7 Jan 2019 16:56:11 +0100 Subject: Windows QPA: Support "press and hold for right-clicking" Windows sends a fake WM_RBUTTONUP/WM_RBUTTONDOWN when the user presses and holds the pen/finger on a tablet/touchscreen, e.g., in order to show a context menu. Windows only sends already synthesized legacy mouse messages for this condition, instead of anything detectable in the pointer messages. So we need to handle these legacy messages in the Windows QPA. Task-number: QTBUG-36162 Change-Id: Ia93c423601e2e8a8baac3f9b7791bf8a3113885a Reviewed-by: Friedemann Kleint --- .../platforms/windows/qwindowspointerhandler.cpp | 53 ++++++++++++++++------ .../platforms/windows/qwindowspointerhandler.h | 1 + 2 files changed, 39 insertions(+), 15 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index be67eb0248..e428a8cf63 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -200,6 +200,8 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q return false; } + m_lastPointerType = pointerType; + // Handle non-client pen/touch as generic mouse events for compatibility with QDockWindow. if ((pointerType == QT_PT_TOUCH || pointerType == QT_PT_PEN) && (et & QtWindows::NonClientEventFlag)) { POINTER_INFO pointerInfo; @@ -838,6 +840,16 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin #endif } +static inline bool isMouseEventSynthesizedFromPenOrTouch() +{ + // For details, see + // https://docs.microsoft.com/en-us/windows/desktop/tablet/system-events-and-mouse-messages + const LONG_PTR SIGNATURE_MASK = 0xFFFFFF00; + const LONG_PTR MI_WP_SIGNATURE = 0xFF515700; + + return ((::GetMessageExtraInfo() & SIGNATURE_MASK) == MI_WP_SIGNATURE); +} + // Process old-style mouse messages here. bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result) { @@ -846,15 +858,6 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW flushTabletEvents(); *result = 0; - if (et != QtWindows::MouseWheelEvent && msg.message != WM_MOUSELEAVE && msg.message != WM_MOUSEMOVE) - return false; - - // Ignore messages synthesized from touch/pen (only use them for flushing queues). - const quint64 signatureMask = 0xffffff00; - const quint64 miWpSignature = 0xff515700; - const quint64 extraInfo = quint64(GetMessageExtraInfo()); - if ((extraInfo & signatureMask) == miWpSignature) - return false; const QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)); QPoint localPos; @@ -868,6 +871,26 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW } const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); + const Qt::MouseButtons mouseButtons = mouseButtonsFromKeyState(msg.wParam); + + // Handle "press and hold for right-clicking". + // We have to synthesize it here as it only comes from Windows as a fake RMB. + // MS docs say we could use bit 7 from extraInfo to distinguish pen from touch, + // but on the Surface it is set for both. So we use the last pointer type. + if (isMouseEventSynthesizedFromPenOrTouch()) { + if ((msg.message == WM_RBUTTONDOWN || msg.message == WM_RBUTTONUP) + && (((m_lastPointerType == QT_PT_PEN) + && QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents)) + || ((m_lastPointerType == QT_PT_TOUCH) + && QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)))) { + QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, Qt::RightButton, + (msg.message == WM_RBUTTONDOWN) ? QEvent::MouseButtonPress + : QEvent::MouseButtonRelease, + keyModifiers, Qt::MouseEventSynthesizedBySystem); + } + // Messages synthesized from touch/pen are only used for flushing queues and press&hold. + return false; + } if (et == QtWindows::MouseWheelEvent) { @@ -888,6 +911,7 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW } if (msg.message == WM_MOUSELEAVE) { + if (window == m_currentWindow) { QWindow *leaveTarget = m_windowUnderPointer ? m_windowUnderPointer : m_currentWindow; qCDebug(lcQpaEvents) << "Leaving window " << leaveTarget; @@ -895,14 +919,13 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW m_windowUnderPointer = nullptr; m_currentWindow = nullptr; } - return false; - } - QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos); - const Qt::MouseButtons mouseButtons = mouseButtonsFromKeyState(msg.wParam); + } else if (msg.message == WM_MOUSEMOVE) { - handleCaptureRelease(window, currentWindowUnderPointer, hwnd, QEvent::MouseMove, mouseButtons); - handleEnterLeave(window, currentWindowUnderPointer, globalPos); + QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos); + handleCaptureRelease(window, currentWindowUnderPointer, hwnd, QEvent::MouseMove, mouseButtons); + handleEnterLeave(window, currentWindowUnderPointer, globalPos); + } return false; } diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.h b/src/plugins/platforms/windows/qwindowspointerhandler.h index a586c7863c..ec3179e821 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.h +++ b/src/plugins/platforms/windows/qwindowspointerhandler.h @@ -78,6 +78,7 @@ private: QPointer m_currentWindow; QWindow *m_previousCaptureWindow = nullptr; bool m_needsEnterOnPointerUpdate = false; + DWORD m_lastPointerType = 0; }; QT_END_NAMESPACE -- cgit v1.2.3 From 8961493b4036af018842820238c4eda0c0717e64 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Fri, 11 Jan 2019 10:37:46 +0100 Subject: QMacStyle - take into account that native controls are transparent now MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use NSButton to emulate tabs in QTabWidget. Starting from 10.14 in dark theme those button objects tend to be somewhat transparent, thus widget's frame is visible through tab buttons. This is true for native controls also - NSButton, NSSegmentedControl, NSTabView - they all show the similar behavior. The only difference is NSTabView, which is the closest control to our QTabWidget - tab buttons are transparent, but they (AppKit) it would appear just do not draw the frame under this area. Let's do the same, but using clipping. Task-number: QTBUG-71741 Change-Id: I9f19014d0db5f36bacf76ee0068fae6eee793c0f Reviewed-by: Tor Arne Vestbø --- src/plugins/styles/mac/qmacstyle_mac.mm | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index b84448d5e2..c2b6fbfead 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -130,6 +130,7 @@ #include #endif #include +#include #include #include #include @@ -314,6 +315,26 @@ static QLinearGradient titlebarGradientInactive() return qt_mac_applicationIsInDarkMode() ? darkGradient : lightGradient; } +static void clipTabBarFrame(const QStyleOption *option, const QMacStyle *style, CGContextRef ctx) +{ + Q_ASSERT(option); + Q_ASSERT(style); + Q_ASSERT(ctx); + + if (qt_mac_applicationIsInDarkMode()) { + QTabWidget *tabWidget = qobject_cast(option->styleObject); + Q_ASSERT(tabWidget); + + const QRect tabBarRect = style->subElementRect(QStyle::SE_TabWidgetTabBar, option, tabWidget).adjusted(2, 2, -3, -2); + const QRegion clipPath = QRegion(option->rect) - tabBarRect; + QVarLengthArray cgRects; + for (const QRect &qtRect : clipPath) + cgRects.push_back(qtRect.toCGRect()); + if (cgRects.size()) + CGContextClipToRects(ctx, &cgRects[0], size_t(cgRects.size())); + } +} + static const QColor titlebarSeparatorLineActive(111, 111, 111); static const QColor titlebarSeparatorLineInactive(131, 131, 131); static const QColor darkModeSeparatorLine(88, 88, 88); @@ -2976,6 +2997,8 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai // QDarkNSBox, of type NSBoxCustom. Its appearance is close enough to the real thing so // we can use this for now. d->drawNSViewInRect(box, opt->rect, p, ^(CGContextRef ctx, const CGRect &rect) { + if (QTabWidget *tabWidget = qobject_cast(opt->styleObject)) + clipTabBarFrame(opt, this, ctx); CGContextTranslateCTM(ctx, 0, rect.origin.y + rect.size.height); CGContextScaleCTM(ctx, 1, -1); if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSMojave @@ -3699,6 +3722,12 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter // inFrame:withView:], -[drawRect:] or anything in between. Besides, // there's no public API do draw the pressed state, AFAICS. We'll use // a push NSButton instead and clip the CGContext. + // NOTE/TODO: this is not true. On 10.13 NSSegmentedControl works with + // some (black?) magic/magic dances, on 10.14 it simply works (was + // it fixed in AppKit?). But, indeed, we cannot make a tab 'pressed' + // with NSSegmentedControl (only selected), so we stay with buttons + // (mixing buttons and NSSegmentedControl for such a simple thing + // is too much work). const auto cs = d->effectiveAquaSizeConstrain(opt, w); // Extra hacks to get the proper pressed appreance when not selected or selected and inactive -- cgit v1.2.3 From 30e665f7471859cd88f5d5be4008e7b0632bb5c3 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Thu, 27 Dec 2018 01:10:29 +0100 Subject: eglfs_kms: Fix build with -no-opengl This patch amends 259adc5e77a40bc8f0b7e4c17f7a38bfc4ad511b Change-Id: Ie8d8a8e0817cea455eb1fe14501e8429d29428b8 Reviewed-by: Laszlo Agocs --- .../eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp | 2 ++ .../eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp index 402338197d..1e4f4e72c8 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp @@ -118,6 +118,8 @@ QPlatformCursor *QEglFSKmsGbmIntegration::createCursor(QPlatformScreen *screen) qCDebug(qLcEglfsKmsDebug, "Using plain OpenGL mouse cursor"); return new QEglFSCursor(screen); } +#else + Q_UNUSED(screen); #endif return nullptr; } diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp index a67457a6a5..ab39af6b80 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp @@ -289,7 +289,9 @@ QPlatformCursor *QEglFSKmsEglDeviceIntegration::createCursor(QPlatformScreen *sc { #if QT_CONFIG(opengl) if (screenConfig()->separateScreens()) - return new QEglFSCursor(screen); + return new QEglFSCursor(screen); +#else + Q_UNUSED(screen); #endif return nullptr; } -- cgit v1.2.3 From 730f0df17db53b249b8680a14c40d12107c8e24e Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 22 Jan 2019 12:57:52 +0100 Subject: Windows: Set opengl swap interval whenever we make a new window current Apparently the windows OpenGL implementation associates the swap interval not with the context, but with the window. Fixes: QTBUG-59660 Change-Id: I78c4cc9f8a5815779a7489edfd731a1debb1e590 Reviewed-by: Friedemann Kleint Reviewed-by: Laszlo Agocs Reviewed-by: Simon Hausmann --- src/plugins/platforms/windows/qwindowsglcontext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index 851a6c961e..21cb794196 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -1350,10 +1350,10 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) // Set the swap interval if (m_staticContext->wglSwapInternalExt) { const int interval = surface->format().swapInterval(); - if (interval >= 0 && m_swapInterval != interval) { + if (m_swapInterval != interval) m_swapInterval = interval; + if (interval >= 0) m_staticContext->wglSwapInternalExt(interval); - } } return success; -- cgit v1.2.3 From 76ee79b8b9c412a77bb51f127ab102f2451a7bbb Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Thu, 17 Jan 2019 13:32:40 +0100 Subject: qtbearer networkmanager: fix whitespace Change-Id: I7802e33e21fa882468b4c8e68677d4881b95d15c Reviewed-by: Lars Knoll --- src/plugins/bearer/networkmanager/qnetworkmanagerservice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h index 65e618d15f..c879083faf 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h @@ -243,7 +243,7 @@ public: // bool setConnections(); Q_SIGNALS: - void propertiesChanged(QMap ); + void propertiesChanged(QMap); void propertiesReady(); private Q_SLOTS: -- cgit v1.2.3 From 8c0a7a46c691f7acad169f5949d3b3d76a227614 Mon Sep 17 00:00:00 2001 From: Samuli Piippo Date: Wed, 9 Jan 2019 13:01:01 +0000 Subject: egl_viv: cast EGLNative return types from vivante functions All vivante functions return void* even when the actual native type (EGLNativeDisplayType, EGLNativeWindowType, etc.) might be typedef'ed as something else, as they do when the CFLAGS from egl.pc are now used. Task-number: QTBUG-73038 Change-Id: I7650b691663201d03d8c15ead155aa3c231fba29 Reviewed-by: Laszlo Agocs --- .../eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp | 4 ++-- .../eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp index 763a4a462b..2fc076ad0c 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp @@ -65,7 +65,7 @@ void QEglFSVivIntegration::platformInit() VivanteInit(); mNativeDisplay = fbGetDisplay(); #else - mNativeDisplay = fbGetDisplayByIndex(framebufferIndex()); + mNativeDisplay = static_cast(fbGetDisplayByIndex(framebufferIndex())); #endif fbGetDisplayGeometry(mNativeDisplay, &width, &height); @@ -88,7 +88,7 @@ EGLNativeWindowType QEglFSVivIntegration::createNativeWindow(QPlatformWindow *wi Q_UNUSED(window) Q_UNUSED(format) - EGLNativeWindowType eglWindow = fbCreateWindow(mNativeDisplay, 0, 0, size.width(), size.height()); + EGLNativeWindowType eglWindow = static_cast(fbCreateWindow(mNativeDisplay, 0, 0, size.width(), size.height())); return eglWindow; } diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp index 61e2f17766..3bdae239cd 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.cpp @@ -60,7 +60,7 @@ void QEglFSVivWaylandIntegration::platformInit() } mWaylandDisplay = wl_display_create(); - mNativeDisplay = fbGetDisplay(mWaylandDisplay); + mNativeDisplay = static_cast(fbGetDisplay(mWaylandDisplay)); fbGetDisplayGeometry(mNativeDisplay, &width, &height); mScreenSize.setHeight(height); mScreenSize.setWidth(width); @@ -81,7 +81,7 @@ EGLNativeWindowType QEglFSVivWaylandIntegration::createNativeWindow(QPlatformWin Q_UNUSED(window) Q_UNUSED(format) - EGLNativeWindowType eglWindow = fbCreateWindow(mNativeDisplay, 0, 0, size.width(), size.height()); + EGLNativeWindowType eglWindow = static_cast(fbCreateWindow(mNativeDisplay, 0, 0, size.width(), size.height())); return eglWindow; } -- cgit v1.2.3 From e0dc6dce222173bfa8fe20e1f33d24de70ea9fdd Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 17 Dec 2018 08:18:08 +0100 Subject: Android: Set minimum supported version to android-21 With the current distribution, this is 90% of active devices, and it was released in 2014. Qt 5.12 is LTS and will continue to support older Android versions for a long time to come. This is to reduce the testing needed on outdated platforms and allow ourselves to use some newer APIs unconditionally in Qt. Android 21 was chosen because it is the minimum version that supports 64 bit builds. [ChangeLog][Android] Increased the minimum supported Android version to Android 5.0 (API level 21). Fixes: QTBUG-70508 Change-Id: Ia7b4345e42ca05a25a292f11ccbb8cbd692cf8f0 Reviewed-by: BogDan Vatra --- .../platforms/android/androidjniaccessibility.cpp | 5 +-- src/plugins/platforms/android/extract-dummy.cpp | 10 ------ src/plugins/platforms/android/extract.cpp | 40 ---------------------- 3 files changed, 1 insertion(+), 54 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp index 309e41bfd6..d4b7f38bf6 100644 --- a/src/plugins/platforms/android/androidjniaccessibility.cpp +++ b/src/plugins/platforms/android/androidjniaccessibility.cpp @@ -329,10 +329,7 @@ if (!clazz) { \ GET_AND_CHECK_STATIC_METHOD(m_setFocusedMethodID, nodeInfoClass, "setFocused", "(Z)V"); GET_AND_CHECK_STATIC_METHOD(m_setScrollableMethodID, nodeInfoClass, "setScrollable", "(Z)V"); GET_AND_CHECK_STATIC_METHOD(m_setVisibleToUserMethodID, nodeInfoClass, "setVisibleToUser", "(Z)V"); - - if (QtAndroidPrivate::androidSdkVersion() >= 18) { - GET_AND_CHECK_STATIC_METHOD(m_setTextSelectionMethodID, nodeInfoClass, "setTextSelection", "(II)V"); - } + GET_AND_CHECK_STATIC_METHOD(m_setTextSelectionMethodID, nodeInfoClass, "setTextSelection", "(II)V"); return true; } diff --git a/src/plugins/platforms/android/extract-dummy.cpp b/src/plugins/platforms/android/extract-dummy.cpp index d07fbe1ba7..fdce8ec64c 100644 --- a/src/plugins/platforms/android/extract-dummy.cpp +++ b/src/plugins/platforms/android/extract-dummy.cpp @@ -40,16 +40,6 @@ #include #include -extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo(JNIEnv *, jobject, Res_png_9patch*) -{ - return 0; -} - -extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractChunkInfo(JNIEnv *, jobject, jbyteArray) -{ - return 0; -} - extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo20(JNIEnv *, jobject, long) { return 0; diff --git a/src/plugins/platforms/android/extract.cpp b/src/plugins/platforms/android/extract.cpp index 2f2ffa7126..acffa353f1 100644 --- a/src/plugins/platforms/android/extract.cpp +++ b/src/plugins/platforms/android/extract.cpp @@ -48,46 +48,6 @@ #define LOG_TAG "extractSyleInfo" #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) -extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo(JNIEnv * env, jobject, Res_png_9patch* chunk) -{ - Res_png_9patch::deserialize(chunk); - //printChunkInformation(chunk); - jintArray result; - size_t size = 3+chunk->numXDivs+chunk->numYDivs+chunk->numColors; - result = env->NewIntArray(size); - if (!result) - return 0; - - jint *data = (jint*)malloc(sizeof(jint)*size); - size_t pos = 0; - data[pos++]=chunk->numXDivs; - data[pos++]=chunk->numYDivs; - data[pos++]=chunk->numColors; - for (int x = 0; x numXDivs; x ++) - data[pos++]=chunk->xDivs[x]; - for (int y = 0; y numYDivs; y ++) - data[pos++]=chunk->yDivs[y]; - for (int c = 0; c numColors; c ++) - data[pos++]=chunk->colors[c]; - env->SetIntArrayRegion(result, 0, size, data); - free(data); - return result; -} - -extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractChunkInfo(JNIEnv * env, jobject obj, jbyteArray chunkObj) -{ - size_t chunkSize = env->GetArrayLength(chunkObj); - void* storage = alloca(chunkSize); - env->GetByteArrayRegion(chunkObj, 0, chunkSize, - reinterpret_cast(storage)); - - if (!env->ExceptionCheck()) - return Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo(env, obj, static_cast(storage)); - else - env->ExceptionClear(); - return 0; -} - // The following part was shamelessly stolen from ResourceTypes.cpp from Android's sources /* * Copyright (C) 2005 The Android Open Source Project -- cgit v1.2.3 From 461ef575bcf778ba24b0be6b775098d4b80ae5e1 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Tue, 16 Jan 2018 09:54:01 +0100 Subject: Always escape the table names when creating the SQL statement Since some databases are case sensitive if part of the query is quoted, then we should ensure that all instances of the table name are escaped unless the test is delibrately testing the non-escaped case. As a result, this commit also removes some expected failures pertaining to PostgreSQL and also adds an entry to the list of tables being dropped when a test is finished. [ChangeLog][Sql][PostgreSQL] QSqlDatabase is now stricter about table names when used with record() and primaryIndex(). If the tablename was not quoted when it was created, then the table name passed to record() and primaryIndex() needs to be in lower case so that PostgreSQL is able to find it. Fixes: QTBUG-65788 Change-Id: Id1f54cb66b761c39edf858501b730ede7eec1fd3 Reviewed-by: Paul Wicking Reviewed-by: Edward Welbourne --- src/plugins/sqldrivers/mysql/qsql_mysql.cpp | 2 +- src/plugins/sqldrivers/psql/qsql_psql.cpp | 24 ++++-------------------- 2 files changed, 5 insertions(+), 21 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp index 80c0c9c522..febbe58506 100644 --- a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp +++ b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp @@ -1551,7 +1551,7 @@ QSqlIndex QMYSQLDriver::primaryIndex(const QString& tablename) const QSqlQuery i(createResult()); QString stmt(QLatin1String("show index from %1;")); QSqlRecord fil = record(tablename); - i.exec(stmt.arg(tablename)); + i.exec(stmt.arg(escapeIdentifier(tablename, QSqlDriver::TableName))); while (i.isActive() && i.next()) { if (i.value(2).toString() == QLatin1String("PRIMARY")) { idx.append(fil.field(i.value(4).toString())); diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp index 9fc9317da6..49b793ce38 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql.cpp +++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp @@ -1393,16 +1393,8 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const QString tbl = tablename; QString schema; qSplitTableName(tbl, schema); - - if (isIdentifierEscaped(tbl, QSqlDriver::TableName)) - tbl = stripDelimiters(tbl, QSqlDriver::TableName); - else - tbl = std::move(tbl).toLower(); - - if (isIdentifierEscaped(schema, QSqlDriver::TableName)) - schema = stripDelimiters(schema, QSqlDriver::TableName); - else - schema = std::move(schema).toLower(); + schema = stripDelimiters(schema, QSqlDriver::TableName); + tbl = stripDelimiters(tbl, QSqlDriver::TableName); QString stmt = QStringLiteral("SELECT pg_attribute.attname, pg_attribute.atttypid::int, " "pg_class.relname " @@ -1437,16 +1429,8 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const QString tbl = tablename; QString schema; qSplitTableName(tbl, schema); - - if (isIdentifierEscaped(tbl, QSqlDriver::TableName)) - tbl = stripDelimiters(tbl, QSqlDriver::TableName); - else - tbl = std::move(tbl).toLower(); - - if (isIdentifierEscaped(schema, QSqlDriver::TableName)) - schema = stripDelimiters(schema, QSqlDriver::TableName); - else - schema = std::move(schema).toLower(); + schema = stripDelimiters(schema, QSqlDriver::TableName); + tbl = stripDelimiters(tbl, QSqlDriver::TableName); QString stmt = QStringLiteral("SELECT pg_attribute.attname, pg_attribute.atttypid::int, " "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, " -- cgit v1.2.3 From 19d1fdc5a52039d771d520d0f6c5b98a0e0c4c60 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 24 Jan 2019 09:39:38 +0100 Subject: Windows QPA: Use member initialization in struct WindowCreationData Change-Id: I165e795ea75a8d5cb5d3256b3ef377239d24a245 Reviewed-by: Oliver Wolff --- src/plugins/platforms/windows/qwindowswindow.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index f340f16679..7efefa9458 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -482,26 +482,22 @@ struct WindowCreationData typedef QWindowsWindowData WindowData; enum Flags { ForceChild = 0x1, ForceTopLevel = 0x2 }; - WindowCreationData() : parentHandle(0), type(Qt::Widget), style(0), exStyle(0), - topLevel(false), popup(false), dialog(false), - tool(false), embedded(false), hasAlpha(false) {} - void fromWindow(const QWindow *w, const Qt::WindowFlags flags, unsigned creationFlags = 0); inline WindowData create(const QWindow *w, const WindowData &data, QString title) const; inline void applyWindowFlags(HWND hwnd) const; void initialize(const QWindow *w, HWND h, bool frameChange, qreal opacityLevel) const; Qt::WindowFlags flags; - HWND parentHandle; - Qt::WindowType type; - unsigned style; - unsigned exStyle; - bool topLevel; - bool popup; - bool dialog; - bool tool; - bool embedded; - bool hasAlpha; + HWND parentHandle = nullptr; + Qt::WindowType type = Qt::Widget; + unsigned style = 0; + unsigned exStyle = 0; + bool topLevel = false; + bool popup = false; + bool dialog = false; + bool tool = false; + bool embedded = false; + bool hasAlpha = false; }; QDebug operator<<(QDebug debug, const WindowCreationData &d) -- cgit v1.2.3 From 4aa0bcf5f5266b33faf236e8c914fcf5379abf5b Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 22 Jan 2019 14:48:37 +0100 Subject: Windows QPA: Fix tray icon becoming visible before show Use the NIS_HIDDEN flag of the NOTIFYICONDATA structure to prevent it from becoming visible before show when calling NIM_ADD with the icon data. Fixes: QTBUG-73185 Change-Id: If5cc5a4930a889623a5cac84138185ad04765ece Reviewed-by: Oliver Wolff --- .../platforms/windows/qwindowssystemtrayicon.cpp | 26 +++++++++++++++++++++- .../platforms/windows/qwindowssystemtrayicon.h | 2 ++ 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp index 3c27f2914d..2b728338ae 100644 --- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp +++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp @@ -103,6 +103,13 @@ static void setIconContents(NOTIFYICONDATA &tnd, const QString &tip, HICON hIcon qStringToLimitedWCharArray(tip, tnd.szTip, sizeof(tnd.szTip) / sizeof(wchar_t)); } +static void setIconVisibility(NOTIFYICONDATA &tnd, bool v) +{ + tnd.uFlags |= NIF_STATE; + tnd.dwStateMask = NIS_HIDDEN; + tnd.dwState = v ? 0 : NIS_HIDDEN; +} + // Match the HWND of the dummy window to the instances struct QWindowsHwndSystemTrayIconEntry { @@ -193,12 +200,15 @@ QWindowsSystemTrayIcon::~QWindowsSystemTrayIcon() void QWindowsSystemTrayIcon::init() { qCDebug(lcQpaTrayIcon) << __FUNCTION__ << this; - ensureInstalled(); + m_visible = true; + if (!setIconVisible(m_visible)) + ensureInstalled(); } void QWindowsSystemTrayIcon::cleanup() { qCDebug(lcQpaTrayIcon) << __FUNCTION__ << this; + m_visible = false; ensureCleanup(); } @@ -333,6 +343,18 @@ void QWindowsSystemTrayIcon::ensureCleanup() m_toolTip.clear(); } +bool QWindowsSystemTrayIcon::setIconVisible(bool visible) +{ + if (!isInstalled()) + return false; + NOTIFYICONDATA tnd; + initNotifyIconData(tnd); + tnd.uID = q_uNOTIFYICONID; + tnd.hWnd = m_hwnd; + setIconVisibility(tnd, visible); + return Shell_NotifyIcon(NIM_MODIFY, &tnd) == TRUE; +} + bool QWindowsSystemTrayIcon::sendTrayMessage(DWORD msg) { NOTIFYICONDATA tnd; @@ -340,6 +362,8 @@ bool QWindowsSystemTrayIcon::sendTrayMessage(DWORD msg) tnd.uID = q_uNOTIFYICONID; tnd.hWnd = m_hwnd; tnd.uFlags = NIF_SHOWTIP; + if (msg != NIM_DELETE && !m_visible) + setIconVisibility(tnd, m_visible); if (msg == NIM_ADD || msg == NIM_MODIFY) setIconContents(tnd, m_toolTip, m_hIcon); if (!Shell_NotifyIcon(msg, &tnd)) diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.h b/src/plugins/platforms/windows/qwindowssystemtrayicon.h index a8adb9641f..44e1bcc761 100644 --- a/src/plugins/platforms/windows/qwindowssystemtrayicon.h +++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.h @@ -84,6 +84,7 @@ private: bool ensureInstalled(); void ensureCleanup(); bool sendTrayMessage(DWORD msg); + bool setIconVisible(bool visible); HICON createIcon(const QIcon &icon); QIcon m_icon; @@ -92,6 +93,7 @@ private: HICON m_hIcon = nullptr; mutable QPointer m_menu; bool m_ignoreNextMouseRelease = false; + bool m_visible = false; }; #ifndef QT_NO_DEBUG_STREAM -- cgit v1.2.3 From c154766630db37dc7d6f8090609d2d1a5076a733 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 23 Jan 2019 08:38:08 +0100 Subject: Windows QPA: Move the code installing the filter for WM_TASKBARCREATED Previously, the code was in the constructor, where hwnd was 0 and ChangeWindowMessageFilterEx() failed. Move it into QWindowsSystemTrayIcon::ensureInstalled() after the creation of the message window. Change-Id: Iff4c6d6d6b11bdcace7514ad421c96c94e52bbba Reviewed-by: Oliver Wolff --- src/plugins/platforms/windows/qwindowssystemtrayicon.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp index 2b728338ae..b738007f0e 100644 --- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp +++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp @@ -183,12 +183,6 @@ static inline HWND createTrayIconMessageWindow() QWindowsSystemTrayIcon::QWindowsSystemTrayIcon() { - // For restoring the tray icon after explorer crashes - if (!MYWM_TASKBARCREATED) - MYWM_TASKBARCREATED = RegisterWindowMessage(L"TaskbarCreated"); - // Allow the WM_TASKBARCREATED message through the UIPI filter - ChangeWindowMessageFilterEx(m_hwnd, MYWM_TASKBARCREATED, MSGFLT_ALLOW, 0); - qCDebug(lcQpaTrayIcon) << __FUNCTION__ << this << "MYWM_TASKBARCREATED=" << MYWM_TASKBARCREATED; } QWindowsSystemTrayIcon::~QWindowsSystemTrayIcon() @@ -320,6 +314,13 @@ bool QWindowsSystemTrayIcon::ensureInstalled() m_hwnd = createTrayIconMessageWindow(); if (Q_UNLIKELY(m_hwnd == nullptr)) return false; + // For restoring the tray icon after explorer crashes + if (!MYWM_TASKBARCREATED) + MYWM_TASKBARCREATED = RegisterWindowMessage(L"TaskbarCreated"); + // Allow the WM_TASKBARCREATED message through the UIPI filter + ChangeWindowMessageFilterEx(m_hwnd, MYWM_TASKBARCREATED, MSGFLT_ALLOW, nullptr); + qCDebug(lcQpaTrayIcon) << __FUNCTION__ << this << "MYWM_TASKBARCREATED=" << MYWM_TASKBARCREATED; + QWindowsHwndSystemTrayIconEntry entry{m_hwnd, this}; hwndTrayIconEntries()->append(entry); sendTrayMessage(NIM_ADD); -- cgit v1.2.3 From 4c46e3189ac96c8ebcbe1caa47227c4e086d12ff Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Tue, 22 Jan 2019 20:28:49 +0100 Subject: Windows QPA: Cache "forcedScreenForGLWindow" to avoid overhead The fix for QTBUG-50371 caused an overhead when you hover over a secondary window like a tool tip, menu or combo box due to the forcedScreenForGLWindow() function being called, which loads dx9.dll and sub-dlls and unloads them afterwards. This fix caches the required info on the first call, and only refreshes it when required by a display/settings change. Fixes: QTBUG-73008 Change-Id: Ie604ba4034ad8041b971f5aa46bd43ae03decd55 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowscontext.cpp | 2 ++ src/plugins/platforms/windows/qwindowswindow.cpp | 30 +++++++++++++++++------ src/plugins/platforms/windows/qwindowswindow.h | 5 ++++ 3 files changed, 30 insertions(+), 7 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 1f80ac5872..fee093f675 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -1115,8 +1115,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::DisplayChangedEvent: if (QWindowsTheme *t = QWindowsTheme::instance()) t->displayChanged(); + QWindowsWindow::displayChanged(); return d->m_screenManager.handleDisplayChange(wParam, lParam); case QtWindows::SettingChangedEvent: + QWindowsWindow::settingsChanged(); return d->m_screenManager.handleScreenChanges(); default: break; diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 7efefa9458..54a4f237ff 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -551,12 +551,6 @@ static QScreen *screenForName(const QWindow *w, const QString &name) return winScreen; } -static QScreen *forcedScreenForGLWindow(const QWindow *w) -{ - const QString forceToScreen = GpuDescription::detect().gpuSuitableScreen; - return forceToScreen.isEmpty() ? nullptr : screenForName(w, forceToScreen); -} - static QPoint calcPosition(const QWindow *w, const QWindowCreationContextPtr &context, const QMargins &invMargins) { const QPoint orgPos(context->frameX - invMargins.left(), context->frameY - invMargins.top()); @@ -565,7 +559,7 @@ static QPoint calcPosition(const QWindow *w, const QWindowCreationContextPtr &co return orgPos; // Workaround for QTBUG-50371 - const QScreen *screenForGL = forcedScreenForGLWindow(w); + const QScreen *screenForGL = QWindowsWindow::forcedScreenForGLWindow(w); if (!screenForGL) return orgPos; @@ -1359,6 +1353,28 @@ void QWindowsWindow::setDropSiteEnabled(bool dropEnabled) #endif // QT_CONFIG(clipboard) && QT_CONFIG(draganddrop) } +bool QWindowsWindow::m_screenForGLInitialized = false; + +void QWindowsWindow::displayChanged() +{ + m_screenForGLInitialized = false; +} + +void QWindowsWindow::settingsChanged() +{ + m_screenForGLInitialized = false; +} + +QScreen *QWindowsWindow::forcedScreenForGLWindow(const QWindow *w) +{ + static QString forceToScreen; + if (!m_screenForGLInitialized) { + forceToScreen = GpuDescription::detect().gpuSuitableScreen; + m_screenForGLInitialized = true; + } + return forceToScreen.isEmpty() ? nullptr : screenForName(w, forceToScreen); +} + // Returns topmost QWindowsWindow ancestor even if there are embedded windows in the chain. // Returns this window if it is the topmost ancestor. QWindow *QWindowsWindow::topLevelOf(QWindow *w) diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index e8c30bd44b..b9b398b67b 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -297,6 +297,9 @@ public: void handleHidden(); void handleCompositionSettingsChanged(); + static void displayChanged(); + static void settingsChanged(); + static QScreen *forcedScreenForGLWindow(const QWindow *w); static QWindowsWindow *windowsWindowOf(const QWindow *w); static QWindow *topLevelOf(QWindow *w); static inline void *userDataOf(HWND hwnd); @@ -377,6 +380,8 @@ private: HICON m_iconBig = 0; void *m_surface = nullptr; + static bool m_screenForGLInitialized; + #if QT_CONFIG(vulkan) // note: intentionally not using void * in order to avoid breaking x86 VkSurfaceKHR m_vkSurface = 0; -- cgit v1.2.3 From c4e7f3ab6555c87fb41c5f341524445283720e6a Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Wed, 23 Jan 2019 10:40:18 +0100 Subject: QMacStyle: fix PE_PanelLineEdit and PE_FrameLineEdit handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NSTextField (or its cell) that we use to paint PE_FrameLineEdit overpaints whatever fill color QCommonStyle::drawPrimitive(PE_PanelLineEdit) found in opt->palette and using for PE_PanelLineEdit. As a result the ability to customize widget's colors is lost - we always use the system default colors on top of the custom background color. It's not a problem in 'Dark' mode apparently (controls are transparent there anyway). If it's not 'Dark' mode and common style, indeed, wants from QMacStyle to draw PE_FrameLineEdit - we set the correct background color there. Change-Id: Idad853257f637b028af4bd1181d78afdf079f455 Fixes: QTBUG-73183 Fixes: QTBUG-72662 Fixes: QTBUG-72428 Reviewed-by: Morten Johan Sørvig --- src/plugins/styles/mac/qmacstyle_mac.mm | 62 ++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 12 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index c2b6fbfead..2b40a9a952 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -3217,6 +3217,29 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai static_cast(tf.cell).bezelStyle = isRounded ? NSTextFieldRoundedBezel : NSTextFieldSquareBezel; tf.frame = opt->rect.toCGRect(); d->drawNSViewInRect(tf, opt->rect, p, ^(CGContextRef, const CGRect &rect) { + if (!qt_mac_applicationIsInDarkMode()) { + // In 'Dark' mode controls are transparent, so we do not + // over-paint the (potentially custom) color in the background. + // In 'Light' mode we have to care about the correct + // background color. See the comments below for PE_PanelLineEdit. + CGContextRef cgContext = NSGraphicsContext.currentContext.CGContext; + // See QMacCGContext, here we expect bitmap context created with + // color space 'kCGColorSpaceSRGB', if it's something else - we + // give up. + if (cgContext ? bool(CGBitmapContextGetColorSpace(cgContext)) : false) { + tf.drawsBackground = YES; + const QColor bgColor = frame->palette.brush(QPalette::Base).color(); + tf.backgroundColor = [NSColor colorWithSRGBRed:bgColor.redF() + green:bgColor.greenF() + blue:bgColor.blueF() + alpha:bgColor.alphaF()]; + if (bgColor.alpha() != 255) { + // No way we can have it bezeled and transparent ... + tf.bordered = YES; + } + } + } + [tf.cell drawWithFrame:rect inView:tf]; }); } else { @@ -3225,21 +3248,36 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai } break; case PE_PanelLineEdit: - QCommonStyle::drawPrimitive(pe, opt, p, w); - // Draw the focus frame for widgets other than QLineEdit (e.g. for line edits in Webkit). - // Focus frame is drawn outside the rectangle passed in the option-rect. - if (const QStyleOptionFrame *panel = qstyleoption_cast(opt)) { -#if QT_CONFIG(lineedit) - if ((opt->state & State_HasFocus) && !qobject_cast(w)) { - int vmargin = pixelMetric(QStyle::PM_FocusFrameVMargin); - int hmargin = pixelMetric(QStyle::PM_FocusFrameHMargin); - QStyleOptionFrame focusFrame = *panel; - focusFrame.rect = panel->rect.adjusted(-hmargin, -vmargin, hmargin, vmargin); - drawControl(CE_FocusFrame, &focusFrame, p, w); + { + const QStyleOptionFrame *panel = qstyleoption_cast(opt); + if (qt_mac_applicationIsInDarkMode() || (panel && panel->lineWidth <= 0)) { + // QCommonStyle::drawPrimitive(PE_PanelLineEdit) fill the background with + // a proper color, defined in opt->palette and then, if lineWidth > 0, it + // calls QMacStyle::drawPrimitive(PE_FrameLineEdit). We use NSTextFieldCell + // to handle PE_FrameLineEdit, which will use system-default background. + // In 'Dark' mode it's transparent and thus it's not over-painted. + QCommonStyle::drawPrimitive(pe, opt, p, w); + } else { + // In 'Light' mode, if panel->lineWidth > 0, we have to use the correct + // background color when drawing PE_FrameLineEdit, so let's call it + // directly and set the proper color there. + drawPrimitive(PE_FrameLineEdit, opt, p, w); } + + // Draw the focus frame for widgets other than QLineEdit (e.g. for line edits in Webkit). + // Focus frame is drawn outside the rectangle passed in the option-rect. + if (panel) { +#if QT_CONFIG(lineedit) + if ((opt->state & State_HasFocus) && !qobject_cast(w)) { + int vmargin = pixelMetric(QStyle::PM_FocusFrameVMargin); + int hmargin = pixelMetric(QStyle::PM_FocusFrameHMargin); + QStyleOptionFrame focusFrame = *panel; + focusFrame.rect = panel->rect.adjusted(-hmargin, -vmargin, hmargin, vmargin); + drawControl(CE_FocusFrame, &focusFrame, p, w); + } #endif + } } - break; case PE_PanelScrollAreaCorner: { const QBrush brush(opt->palette.brush(QPalette::Base)); -- cgit v1.2.3 From c9b9a0ea2f274688da26af20102d349336fdb2a0 Mon Sep 17 00:00:00 2001 From: Elena Zaretskaya Date: Fri, 11 Jan 2019 10:11:03 -0500 Subject: Ability to switch language under platform eglfs/linuxfb I need to change keymap under platforms eglfs and linuxfb (without wayland). I use the function QEglFSFunctions::loadKeymap(const QString&), but there's no way to switch between english and another language than to press AltGr as a modifier. I added the function that allows to change the language. And also added the ability to switch the keymap and language for the platform linuxfb and also added the ability to switch the keymap and language for the platform linuxfb Task-number: QTBUG-72452 Change-Id: I37432cf60d375555bea2bf668ec1387322b4964f Reviewed-by: Laszlo Agocs --- .../platforms/eglfs/api/qeglfsintegration.cpp | 13 ++++++ .../platforms/eglfs/api/qeglfsintegration_p.h | 1 + .../platforms/linuxfb/qlinuxfbintegration.cpp | 49 +++++++++++++++++++--- .../platforms/linuxfb/qlinuxfbintegration.h | 8 +++- 4 files changed, 65 insertions(+), 6 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp index 72420199e3..8ccb0ef2cd 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp @@ -429,6 +429,8 @@ QFunctionPointer QEglFSIntegration::platformFunction(const QByteArray &function) #if QT_CONFIG(evdev) if (function == QEglFSFunctions::loadKeymapTypeIdentifier()) return QFunctionPointer(loadKeymapStatic); + else if (function == QEglFSFunctions::switchLangTypeIdentifier()) + return QFunctionPointer(switchLangStatic); #endif return qt_egl_device_integration()->platformFunction(function); @@ -447,6 +449,17 @@ void QEglFSIntegration::loadKeymapStatic(const QString &filename) #endif } +void QEglFSIntegration::switchLangStatic() +{ +#if QT_CONFIG(evdev) + QEglFSIntegration *self = static_cast(QGuiApplicationPrivate::platformIntegration()); + if (self->m_kbdMgr) + self->m_kbdMgr->switchLang(); + else + qWarning("QEglFSIntegration: Cannot switch language, no keyboard handler found"); +#endif +} + void QEglFSIntegration::createInputHandlers() { #if QT_CONFIG(libinput) diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h index c288876678..4b4585d33c 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h +++ b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h @@ -110,6 +110,7 @@ private: EGLNativeDisplayType nativeDisplay() const; void createInputHandlers(); static void loadKeymapStatic(const QString &filename); + static void switchLangStatic(); EGLDisplay m_display; QPlatformInputContext *m_inputContext; diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp index f835dbf6d4..9e38900bcd 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp @@ -69,12 +69,15 @@ #include #endif +#include + QT_BEGIN_NAMESPACE QLinuxFbIntegration::QLinuxFbIntegration(const QStringList ¶mList) : m_primaryScreen(nullptr), m_fontDb(new QGenericUnixFontDatabase), - m_services(new QGenericUnixServices) + m_services(new QGenericUnixServices), + m_kbdMgr(0) { #if QT_CONFIG(kms) if (qEnvironmentVariableIntValue("QT_QPA_FB_DRM") != 0) @@ -98,8 +101,6 @@ void QLinuxFbIntegration::initialize() m_inputContext = QPlatformInputContextFactory::create(); - m_nativeInterface.reset(new QPlatformNativeInterface); - m_vtHandler.reset(new QFbVtHandler); if (!qEnvironmentVariableIntValue("QT_QPA_FB_DISABLE_INPUT")) @@ -163,7 +164,7 @@ void QLinuxFbIntegration::createInputHandlers() #endif #if QT_CONFIG(evdev) - new QEvdevKeyboardManager(QLatin1String("EvdevKeyboard"), QString(), this); + m_kbdMgr = new QEvdevKeyboardManager(QLatin1String("EvdevKeyboard"), QString(), this); new QEvdevMouseManager(QLatin1String("EvdevMouse"), QString(), this); #if QT_CONFIG(tslib) if (!useTslib) @@ -174,7 +175,45 @@ void QLinuxFbIntegration::createInputHandlers() QPlatformNativeInterface *QLinuxFbIntegration::nativeInterface() const { - return m_nativeInterface.data(); + return const_cast(this); +} + +QFunctionPointer QLinuxFbIntegration::platformFunction(const QByteArray &function) const +{ +#if QT_CONFIG(evdev) + if (function == QLinuxFbFunctions::loadKeymapTypeIdentifier()) + return QFunctionPointer(loadKeymapStatic); + else if (function == QLinuxFbFunctions::switchLangTypeIdentifier()) + return QFunctionPointer(switchLangStatic); +#else + Q_UNUSED(function) +#endif + + return 0; +} + +void QLinuxFbIntegration::loadKeymapStatic(const QString &filename) +{ +#if QT_CONFIG(evdev) + QLinuxFbIntegration *self = static_cast(QGuiApplicationPrivate::platformIntegration()); + if (self->m_kbdMgr) + self->m_kbdMgr->loadKeymap(filename); + else + qWarning("QLinuxFbIntegration: Cannot load keymap, no keyboard handler found"); +#else + Q_UNUSED(filename); +#endif +} + +void QLinuxFbIntegration::switchLangStatic() +{ +#if QT_CONFIG(evdev) + QLinuxFbIntegration *self = static_cast(QGuiApplicationPrivate::platformIntegration()); + if (self->m_kbdMgr) + self->m_kbdMgr->switchLang(); + else + qWarning("QLinuxFbIntegration: Cannot switch language, no keyboard handler found"); +#endif } QT_END_NAMESPACE diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h index 22578bf980..7a871b3812 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h @@ -48,6 +48,7 @@ QT_BEGIN_NAMESPACE class QAbstractEventDispatcher; class QFbScreen; class QFbVtHandler; +class QEvdevKeyboardManager; class QLinuxFbIntegration : public QPlatformIntegration, public QPlatformNativeInterface { @@ -71,15 +72,20 @@ public: QList screens() const; + QFunctionPointer platformFunction(const QByteArray &function) const Q_DECL_OVERRIDE; + private: void createInputHandlers(); + static void loadKeymapStatic(const QString &filename); + static void switchLangStatic(); QFbScreen *m_primaryScreen; QPlatformInputContext *m_inputContext; QScopedPointer m_fontDb; QScopedPointer m_services; QScopedPointer m_vtHandler; - QScopedPointer m_nativeInterface; + + QEvdevKeyboardManager *m_kbdMgr; }; QT_END_NAMESPACE -- cgit v1.2.3 From 730cbad8824bcfcb7ab60371a6563cfb6dd5658d Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Thu, 24 Jan 2019 15:53:28 +0300 Subject: xcb: Avoid repaint lags with DnD The lags can be seen when dragged data is requested for a MIME type. This leads to calling QXcbClipboard::waitForClipboardEvent() which runs a loop in the GUI thread and processes events from QXcbEventQueue. The loop ends when a corresponding event is received, otherwise it makes a delay of 50 ms before the next iteration. Sync with QXcbEventQueue thread by QWaitCondition instead of using the delay. This way the loop will end as soon as possible and Expose events will be processed with minimal delay. Task-number: QTBUG-44849 Fixes: QTBUG-55442 Fixes: QTBUG-62344 Fixes: QTBUG-73253 Change-Id: Ie18d63b51a7260c83d53ffe1169b25e5135dd73b Reviewed-by: Mikhail Svetkin Reviewed-by: Gatis Paeglis Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/qxcbclipboard.cpp | 5 +++-- src/plugins/platforms/xcb/qxcbeventqueue.cpp | 9 +++++++++ src/plugins/platforms/xcb/qxcbeventqueue.h | 7 +++++++ 3 files changed, 19 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index bc92f82d5f..ac8b029916 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -810,8 +810,9 @@ xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t window, i connection()->flush(); - // sleep 50 ms, so we don't use up CPU cycles all the time. - QThread::msleep(50); + const auto elapsed = timer.elapsed(); + if (elapsed < clipboard_timeout) + queue->waitForNewEvents(clipboard_timeout - elapsed); } while (timer.elapsed() < clipboard_timeout); return nullptr; diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.cpp b/src/plugins/platforms/xcb/qxcbeventqueue.cpp index f6158d3127..acec0486c2 100644 --- a/src/plugins/platforms/xcb/qxcbeventqueue.cpp +++ b/src/plugins/platforms/xcb/qxcbeventqueue.cpp @@ -229,6 +229,8 @@ void QXcbEventQueue::run() enqueueEvent(event); while (!m_closeConnectionDetected && (event = xcb_poll_for_queued_event(connection))) enqueueEvent(event); + + m_newEventsCondition.wakeOne(); wakeUpDispatcher(); } @@ -346,6 +348,13 @@ bool QXcbEventQueue::peekEventQueue(PeekerCallback peeker, void *peekerData, return result; } +void QXcbEventQueue::waitForNewEvents(unsigned long time) +{ + m_newEventsMutex.lock(); + m_newEventsCondition.wait(&m_newEventsMutex, time); + m_newEventsMutex.unlock(); +} + void QXcbEventQueue::sendCloseConnectionEvent() const { // A hack to close XCB connection. Apparently XCB does not have any APIs for this? diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.h b/src/plugins/platforms/xcb/qxcbeventqueue.h index 235f2824be..11d0b8e963 100644 --- a/src/plugins/platforms/xcb/qxcbeventqueue.h +++ b/src/plugins/platforms/xcb/qxcbeventqueue.h @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include @@ -104,6 +106,8 @@ public: bool peekEventQueue(PeekerCallback peeker, void *peekerData = nullptr, PeekOptions option = PeekDefault, qint32 peekerId = -1); + void waitForNewEvents(unsigned long time = ULONG_MAX); + private: QXcbEventNode *qXcbEventNodeFactory(xcb_generic_event_t *event); void dequeueNode(); @@ -131,6 +135,9 @@ private: // debug stats quint64 m_nodesOnHeap = 0; + + QMutex m_newEventsMutex; + QWaitCondition m_newEventsCondition; }; template -- cgit v1.2.3 From de3716f0ba97778f59ab85822acc7f3e26c21399 Mon Sep 17 00:00:00 2001 From: Samuel Gaist Date: Sat, 12 Jan 2019 23:32:45 +0100 Subject: Fix QMacStyle QPalette warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code was still using QPalette::background. It's now using window. Change-Id: I9a47018d559d638ff69b1e4b2d7e2335e04a2a3a Reviewed-by: Tor Arne Vestbø --- src/plugins/styles/mac/qmacstyle_mac.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 2b40a9a952..50a657e774 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -4214,7 +4214,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter case CE_MenuBarEmptyArea: if (const QStyleOptionMenuItem *mi = qstyleoption_cast(opt)) { const bool selected = (opt->state & State_Selected) && (opt->state & State_Enabled) && (opt->state & State_Sunken); - const QBrush bg = selected ? mi->palette.highlight() : mi->palette.background(); + const QBrush bg = selected ? mi->palette.highlight() : mi->palette.window(); p->fillRect(mi->rect, bg); if (ce != CE_MenuBarItem) -- cgit v1.2.3 From 3b514f853595c686d4ed8830567c1f27ea533faf Mon Sep 17 00:00:00 2001 From: Mikhail Svetkin Date: Fri, 4 Jan 2019 16:01:46 +0100 Subject: qtlite: Fix build libs with -no-feature-regularexpression Change-Id: I427ff1f8f4986fbf466aba60a9d3de614c1e006f Reviewed-by: Lars Knoll --- src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp | 4 +++- .../platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp index f151713400..0a3a37863a 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp @@ -51,7 +51,9 @@ #include #include #include -#include +#if QT_CONFIG(regularexpression) +# include +#endif #include #if defined(Q_OS_LINUX) diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp index ddb8f45188..d42a33c22b 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -48,7 +48,9 @@ #undef register #include -#include +#if QT_CONFIG(regularexpression) +# include +#endif #include #include @@ -722,6 +724,7 @@ void QGLXContext::queryDummyContext() // The issue was fixed in Xcb 1.11, but we can't check for that // at runtime, so instead assume it fixed with recent Mesa versions // released several years after the Xcb fix. +#if QT_CONFIG(regularexpression) QRegularExpression versionTest(QStringLiteral("Mesa (\\d+)")); QRegularExpressionMatch result = versionTest.match(QString::fromLatin1(mesaVersionStr)); int versionNr = 0; @@ -731,6 +734,7 @@ void QGLXContext::queryDummyContext() // White-listed m_supportsThreading = true; } +#endif } if (!m_supportsThreading) { qCDebug(lcQpaGl).nospace() << "Multithreaded OpenGL disabled: " -- cgit v1.2.3 From cf184f1dd4e6c17b4c1a8a915cf9c2613739467e Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Tue, 22 Jan 2019 14:36:04 +0100 Subject: Android: If there is no surrounding text then don't try to delete it If there is no surrounding text then we can save time by not sending an event to delete it as there is nothing to be deleted. This prevents the underlying widget from being confused as to where the cursor and anchor is later on when entering in new text. Fixes: QTBUG-65584 Change-Id: Ic6325c119327048dffd2baa68520871fb56370d5 Reviewed-by: BogDan Vatra --- src/plugins/platforms/android/qandroidinputcontext.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index cdc52e1cb4..c31e43e0bb 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -978,6 +978,10 @@ jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint right m_composingText.clear(); m_composingTextStart = -1; + QString text = query->value(Qt::ImSurroundingText).toString(); + if (text.isEmpty()) + return JNI_TRUE; + if (leftLength < 0) { rightLength += -leftLength; leftLength = 0; -- cgit v1.2.3 From 850858cce6191593aaab3176932bc04a6f97f202 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Mon, 28 Jan 2019 14:01:48 +0100 Subject: Windows QPA: handle pointer messages received during a drag and drop It seems the pointer message handler was skipping the handling of touch and pen messages during a drag and drop operation, preventing the generation of events that quick was expecting and triggering a crash inside MouseArea. Fixes: QTBUG-73120 Change-Id: I2921e38dd7e44846607e6c614d7393cfa5664c69 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowspointerhandler.cpp | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index e428a8cf63..203d803a1b 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -174,15 +174,6 @@ static void flushTabletEvents() } } -static bool draggingActive() -{ -#if QT_CONFIG(draganddrop) - return QWindowsDrag::isDragging(); -#else - return false; -#endif -} - bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result) { *result = 0; @@ -636,9 +627,6 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, if (et & QtWindows::NonClientEventFlag) return false; // Let DefWindowProc() handle Non Client messages. - if (draggingActive()) - return false; // Let DoDragDrop() loop handle it. - if (count < 1) return false; @@ -739,9 +727,6 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin if (et & QtWindows::NonClientEventFlag) return false; // Let DefWindowProc() handle Non Client messages. - if (draggingActive()) - return false; // Let DoDragDrop() loop handle it. - POINTER_PEN_INFO *penInfo = static_cast(vPenInfo); RECT pRect, dRect; -- cgit v1.2.3 From 61d50cbc96e5331218a6a4e5614f50211f06c718 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 24 Jan 2019 08:54:38 +0100 Subject: Windows/Direct2d QPA: Use nullptr Change-Id: I6ce01caa58de78e0eb61e243ee1e7b05cc1f5568 Reviewed-by: Oliver Wolff --- .../platforms/direct2d/qwindowsdirect2dbitmap.cpp | 11 ++-- .../platforms/direct2d/qwindowsdirect2dcontext.cpp | 6 +- .../direct2d/qwindowsdirect2dintegration.cpp | 8 +-- .../direct2d/qwindowsdirect2dnativeinterface.cpp | 6 +- .../direct2d/qwindowsdirect2dpaintengine.cpp | 26 ++++---- .../direct2d/qwindowsdirect2dplatformplugin.cpp | 2 +- .../platforms/direct2d/qwindowsdirect2dwindow.cpp | 16 ++--- src/plugins/platforms/windows/main.cpp | 2 +- .../platforms/windows/qwindowsbackingstore.cpp | 5 +- .../platforms/windows/qwindowsclipboard.cpp | 18 +++--- src/plugins/platforms/windows/qwindowscontext.cpp | 59 ++++++++--------- src/plugins/platforms/windows/qwindowscursor.cpp | 16 ++--- .../platforms/windows/qwindowsdialoghelpers.cpp | 74 +++++++++++----------- src/plugins/platforms/windows/qwindowsdrag.cpp | 12 ++-- .../platforms/windows/qwindowseglcontext.cpp | 30 ++++----- .../windows/qwindowsgdinativeinterface.cpp | 4 +- .../platforms/windows/qwindowsglcontext.cpp | 46 +++++++------- .../platforms/windows/qwindowsinputcontext.cpp | 10 +-- .../platforms/windows/qwindowsintegration.cpp | 4 +- .../platforms/windows/qwindowsinternalmimedata.cpp | 2 +- .../platforms/windows/qwindowskeymapper.cpp | 18 +++--- src/plugins/platforms/windows/qwindowsmenu.cpp | 2 +- src/plugins/platforms/windows/qwindowsmime.cpp | 18 +++--- .../platforms/windows/qwindowsmousehandler.cpp | 18 +++--- .../platforms/windows/qwindowsnativeinterface.cpp | 12 ++-- src/plugins/platforms/windows/qwindowsole.cpp | 16 ++--- .../platforms/windows/qwindowsopengltester.cpp | 22 +++---- src/plugins/platforms/windows/qwindowsscreen.cpp | 14 ++-- src/plugins/platforms/windows/qwindowsservices.cpp | 12 ++-- .../platforms/windows/qwindowssystemtrayicon.cpp | 5 +- src/plugins/platforms/windows/qwindowstheme.cpp | 24 +++---- src/plugins/platforms/windows/qwindowswindow.cpp | 52 +++++++-------- .../windows/uiautomation/qwindowsuiautils.cpp | 2 +- 33 files changed, 289 insertions(+), 283 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp index 2151f3ae95..587bae3598 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp @@ -54,7 +54,8 @@ QT_BEGIN_NAMESPACE class QWindowsDirect2DBitmapPrivate { public: - QWindowsDirect2DBitmapPrivate(ID2D1DeviceContext *dc = 0, ID2D1Bitmap1 *bm = 0) + QWindowsDirect2DBitmapPrivate(ID2D1DeviceContext *dc = nullptr, + ID2D1Bitmap1 *bm = nullptr) : deviceContext(new QWindowsDirect2DDeviceContext(dc)) , bitmap(bm) @@ -75,9 +76,9 @@ public: } - bool resize(int width, int height, const void *data = 0, int pitch = 0) + bool resize(int width, int height, const void *data = nullptr, int pitch = 0) { - deviceContext->get()->SetTarget(0); + deviceContext->get()->SetTarget(nullptr); bitmap.Reset(); D2D1_SIZE_U size = { @@ -108,14 +109,14 @@ public: D2D1_BITMAP_PROPERTIES1 properties = bitmapProperties(); properties.bitmapOptions = D2D1_BITMAP_OPTIONS_CANNOT_DRAW | D2D1_BITMAP_OPTIONS_CPU_READ; - hr = deviceContext->get()->CreateBitmap(size, NULL, 0, + hr = deviceContext->get()->CreateBitmap(size, nullptr, 0, properties, &mappingCopy); if (FAILED(hr)) { qWarning("%s: Could not create bitmap: %#lx", __FUNCTION__, hr); return QImage(); } - hr = mappingCopy->CopyFromBitmap(NULL, bitmap.Get(), NULL); + hr = mappingCopy->CopyFromBitmap(nullptr, bitmap.Get(), nullptr); if (FAILED(hr)) { qWarning("%s: Could not copy from bitmap: %#lx", __FUNCTION__, hr); return QImage(); diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp index a5817016e6..a31477ded9 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp @@ -68,11 +68,11 @@ public: const int ntypes = int(sizeof(typeAttempts) / sizeof(typeAttempts[0])); for (int i = 0; i < ntypes; i++) { - hr = D3D11CreateDevice(NULL, + hr = D3D11CreateDevice(nullptr, typeAttempts[i], - NULL, + nullptr, D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_BGRA_SUPPORT, - NULL, + nullptr, 0, D3D11_SDK_VERSION, &d3dDevice, diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp index 173d79cf2b..86c863ec50 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp @@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE class QWindowsDirect2DEventDispatcher : public QWindowsGuiEventDispatcher { public: - QWindowsDirect2DEventDispatcher(QObject *parent = 0) + QWindowsDirect2DEventDispatcher(QObject *parent = nullptr) : QWindowsGuiEventDispatcher(parent) { uninstallMessageHook(); // ### Workaround for QTBUG-42428 @@ -82,7 +82,7 @@ static QVersionNumber systemD2DVersion() UINT i = GetSystemDirectory(filename, bufSize); if (i > 0 && i < bufSize) { if (_tcscat_s(filename, bufSize, __TEXT("\\d2d1.dll")) == 0) { - DWORD versionInfoSize = GetFileVersionInfoSize(filename, NULL); + DWORD versionInfoSize = GetFileVersionInfoSize(filename, nullptr); if (versionInfoSize) { QVarLengthArray info(static_cast(versionInfoSize)); if (GetFileVersionInfo(filename, 0, versionInfoSize, info.data())) { @@ -132,7 +132,7 @@ QWindowsDirect2DIntegration *QWindowsDirect2DIntegration::create(const QStringLi QString caption = QCoreApplication::translate("QWindowsDirect2DIntegration", "Cannot load direct2d platform plugin"); - MessageBoxW(NULL, + MessageBoxW(nullptr, msg.toStdWString().c_str(), caption.toStdWString().c_str(), MB_OK | MB_ICONERROR); @@ -144,7 +144,7 @@ QWindowsDirect2DIntegration *QWindowsDirect2DIntegration::create(const QStringLi if (!integration->init()) { delete integration; - integration = 0; + integration = nullptr; } return integration; diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp index f763c4f7ab..220302d041 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp @@ -47,15 +47,15 @@ void *QWindowsDirect2DNativeInterface::nativeResourceForBackingStore(const QByte { if (!bs || !bs->handle()) { qWarning("%s: '%s' requested for null backingstore or backingstore without handle.", __FUNCTION__, resource.constData()); - return 0; + return nullptr; } // getDC is so common we don't want to print an "invalid key" line for it if (resource == "getDC") - return 0; + return nullptr; qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); - return 0; + return nullptr; } diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index d3e1d4dd12..fa201c784e 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -385,9 +385,9 @@ public: antialiasMode(), D2D1::IdentityMatrix(), 1.0, - NULL, + nullptr, layerOptions()), - NULL); + nullptr); pushedClips.push(LayerClip); } } @@ -602,7 +602,7 @@ public: hr = dc()->CreateBitmapBrush(bitmap.bitmap(), bitmapBrushProperties, &pen.dashBrush); pen.dashLength = bitmap.size().width(); } else { - hr = factory()->CreateStrokeStyle(props, NULL, 0, &pen.strokeStyle); + hr = factory()->CreateStrokeStyle(props, nullptr, 0, &pen.strokeStyle); } if (FAILED(hr)) @@ -816,7 +816,7 @@ public: Direct2DPathGeometryWriter writer; if (!writer.begin()) - return NULL; + return nullptr; writer.setWindingFillEnabled(path.hasWindingFill()); writer.setAliasingEnabled(alias); @@ -932,7 +932,7 @@ public: dc()->DrawGlyphRun(pos, &glyphRun, - NULL, + nullptr, pen.brush.Get(), DWRITE_MEASURING_MODE_GDI_CLASSIC); } @@ -990,7 +990,7 @@ public: dashOffset = pen.dashLength - fmod(lineLength - dashOffset, pen.dashLength); } dc()->DrawLine(to_d2d_point_2f(p1), to_d2d_point_2f(p2), - brush, FLOAT(pen.qpen.widthF()), NULL); + brush, FLOAT(pen.qpen.widthF()), nullptr); if (skipJoin) continue; @@ -1102,9 +1102,9 @@ bool QWindowsDirect2DPaintEngine::begin(QPaintDevice * pdev) d->antialiasMode(), D2D1::IdentityMatrix(), 1.0, - NULL, + nullptr, d->layerOptions()), - NULL); + nullptr); } else { QRect clip(0, 0, pdev->width(), pdev->height()); if (!systemClip().isEmpty()) @@ -1474,7 +1474,7 @@ void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r, r.x() + r.width(), r.y() + r.height(), r.x(), r.y() + r.height() }; - const QVectorPath vp(points, 4, 0, QVectorPath::RectangleHint); + const QVectorPath vp(points, 4, nullptr, QVectorPath::RectangleHint); QBrush brush(sr.isValid() ? pm.copy(sr.toRect()) : pm); brush.setTransform(QTransform::fromTranslate(r.x(), r.y())); rasterFill(vp, brush); @@ -1511,7 +1511,7 @@ void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r, } D2D1_RECT_U d2d_sr = to_d2d_rect_u(sr.toRect()); - HRESULT hr = intermediate.bitmap()->CopyFromBitmap(NULL, + HRESULT hr = intermediate.bitmap()->CopyFromBitmap(nullptr, bitmap->bitmap(), &d2d_sr); if (FAILED(hr)) { @@ -1526,9 +1526,9 @@ void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r, return; } - HRESULT hr = intermediate.bitmap()->CopyFromBitmap(NULL, + HRESULT hr = intermediate.bitmap()->CopyFromBitmap(nullptr, bitmap->bitmap(), - NULL); + nullptr); if (FAILED(hr)) { qWarning("%s: Could not copy source bitmap to intermediate bitmap: %#lx", __FUNCTION__, hr); return; @@ -1708,7 +1708,7 @@ void QWindowsDirect2DPaintEngine::rasterFill(const QVectorPath &path, const QBru right, info.rectf.y(), right, bottom, info.rectf.x(), bottom }; - QVectorPath vp(pts, 4, 0, QVectorPath::RectangleHint); + QVectorPath vp(pts, 4, nullptr, QVectorPath::RectangleHint); extended->clip(vp, info.operation); break; } diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp index 6c56d356b7..b2fb4ba551 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp @@ -56,7 +56,7 @@ QPlatformIntegration *QWindowsDirect2DIntegrationPlugin::create(const QString& s { if (system.compare(system, QLatin1String("direct2d"), Qt::CaseInsensitive) == 0) return QWindowsDirect2DIntegration::create(paramList); - return 0; + return nullptr; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp index f81182e0b1..239e5f3087 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp @@ -171,12 +171,12 @@ void QWindowsDirect2DWindow::present(const QRegion ®ion) const BLENDFUNCTION blend = { AC_SRC_OVER, 0, BYTE(255.0 * opacity()), AC_SRC_ALPHA }; const QRect r = region.boundingRect(); const RECT dirty = { r.left(), r.top(), r.left() + r.width(), r.top() + r.height() }; - UPDATELAYEREDWINDOWINFO info = { sizeof(UPDATELAYEREDWINDOWINFO), NULL, + UPDATELAYEREDWINDOWINFO info = { sizeof(UPDATELAYEREDWINDOWINFO), nullptr, &ptDst, &size, hdc, &ptSrc, 0, &blend, ULW_ALPHA, &dirty }; if (!UpdateLayeredWindowIndirect(handle(), &info)) qErrnoWarning(int(GetLastError()), "Failed to update the layered window"); - hr = dxgiSurface->ReleaseDC(NULL); + hr = dxgiSurface->ReleaseDC(nullptr); if (FAILED(hr)) qErrnoWarning(hr, "Failed to release the DC for presentation"); } @@ -195,8 +195,8 @@ void QWindowsDirect2DWindow::setupSwapChain() QWindowsDirect2DContext::instance()->d3dDevice(), // [in] IUnknown *pDevice handle(), // [in] HWND hWnd &desc, // [in] const DXGI_SWAP_CHAIN_DESC1 *pDesc - NULL, // [in] const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *pFullscreenDesc - NULL, // [in] IDXGIOutput *pRestrictToOutput + nullptr, // [in] const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *pFullscreenDesc + nullptr, // [in] IDXGIOutput *pRestrictToOutput m_swapChain.ReleaseAndGetAddressOf()); // [out] IDXGISwapChain1 **ppSwapChain if (FAILED(hr)) @@ -244,14 +244,14 @@ QSharedPointer QWindowsDirect2DWindow::copyBackBuffer() nullptr // _Field_size_opt_(1) ID2D1ColorContext *colorContext; }; ComPtr copy; - HRESULT hr = m_deviceContext.Get()->CreateBitmap(size, NULL, 0, properties, ©); + HRESULT hr = m_deviceContext.Get()->CreateBitmap(size, nullptr, 0, properties, ©); if (FAILED(hr)) { qWarning("%s: Could not create staging bitmap: %#lx", __FUNCTION__, hr); return null_result; } - hr = copy.Get()->CopyFromBitmap(NULL, m_bitmap->bitmap(), NULL); + hr = copy.Get()->CopyFromBitmap(nullptr, m_bitmap->bitmap(), nullptr); if (FAILED(hr)) { qWarning("%s: Could not copy from bitmap! %#lx", __FUNCTION__, hr); return null_result; @@ -285,7 +285,7 @@ void QWindowsDirect2DWindow::setupBitmap() backBufferDesc.BindFlags = D3D11_BIND_RENDER_TARGET; backBufferDesc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE; ComPtr backBufferTexture; - HRESULT hr = QWindowsDirect2DContext::instance()->d3dDevice()->CreateTexture2D(&backBufferDesc, NULL, &backBufferTexture); + HRESULT hr = QWindowsDirect2DContext::instance()->d3dDevice()->CreateTexture2D(&backBufferDesc, nullptr, &backBufferTexture); if (FAILED(hr)) { qErrnoWarning(hr, "Failed to create backing texture for indirect rendering"); return; @@ -299,7 +299,7 @@ void QWindowsDirect2DWindow::setupBitmap() } ComPtr backBufferBitmap; - hr = m_deviceContext->CreateBitmapFromDxgiSurface(backBufferSurface.Get(), NULL, backBufferBitmap.GetAddressOf()); + hr = m_deviceContext->CreateBitmapFromDxgiSurface(backBufferSurface.Get(), nullptr, backBufferBitmap.GetAddressOf()); if (FAILED(hr)) { qWarning("%s: Could not create Direct2D Bitmap from DXGI Surface: %#lx", __FUNCTION__, hr); return; diff --git a/src/plugins/platforms/windows/main.cpp b/src/plugins/platforms/windows/main.cpp index 8bde87c975..1929f800a4 100644 --- a/src/plugins/platforms/windows/main.cpp +++ b/src/plugins/platforms/windows/main.cpp @@ -112,7 +112,7 @@ QPlatformIntegration *QWindowsIntegrationPlugin::create(const QString& system, c { if (system.compare(system, QLatin1String("windows"), Qt::CaseInsensitive) == 0) return new QWindowsGdiIntegration(paramList); - return 0; + return nullptr; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp index 03b44458ac..68807fabdd 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -102,7 +102,8 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, BLENDFUNCTION blend = {AC_SRC_OVER, 0, BYTE(qRound(255.0 * rw->opacity())), AC_SRC_ALPHA}; RECT dirty = {dirtyRect.x(), dirtyRect.y(), dirtyRect.x() + dirtyRect.width(), dirtyRect.y() + dirtyRect.height()}; - UPDATELAYEREDWINDOWINFO info = {sizeof(info), NULL, &ptDst, &size, m_image->hdc(), &ptSrc, 0, &blend, ULW_ALPHA, &dirty}; + UPDATELAYEREDWINDOWINFO info = {sizeof(info), nullptr, &ptDst, &size, + m_image->hdc(), &ptSrc, 0, &blend, ULW_ALPHA, &dirty}; const BOOL result = UpdateLayeredWindowIndirect(rw->handle(), &info); if (!result) qErrnoWarning("UpdateLayeredWindowIndirect failed for ptDst=(%d, %d)," @@ -207,7 +208,7 @@ HDC QWindowsBackingStore::getDC() const { if (!m_image.isNull()) return m_image->hdc(); - return 0; + return nullptr; } QImage QWindowsBackingStore::toImage() const diff --git a/src/plugins/platforms/windows/qwindowsclipboard.cpp b/src/plugins/platforms/windows/qwindowsclipboard.cpp index 8b386da9f7..b87e43f3f7 100644 --- a/src/plugins/platforms/windows/qwindowsclipboard.cpp +++ b/src/plugins/platforms/windows/qwindowsclipboard.cpp @@ -115,13 +115,13 @@ static QDebug operator<<(QDebug d, const QMimeData *mimeData) IDataObject *QWindowsClipboardRetrievalMimeData::retrieveDataObject() const { - IDataObject * pDataObj = 0; + IDataObject * pDataObj = nullptr; if (OleGetClipboard(&pDataObj) == S_OK) { if (QWindowsContext::verbose > 1) qCDebug(lcQpaMime) << __FUNCTION__ << pDataObj; return pDataObj; } - return 0; + return nullptr; } void QWindowsClipboardRetrievalMimeData::releaseDataObject(IDataObject *dataObject) const @@ -148,7 +148,7 @@ static void cleanClipboardPostRoutine() cl->cleanup(); } -QWindowsClipboard *QWindowsClipboard::m_instance = 0; +QWindowsClipboard *QWindowsClipboard::m_instance = nullptr; QWindowsClipboard::QWindowsClipboard() { @@ -159,7 +159,7 @@ QWindowsClipboard::QWindowsClipboard() QWindowsClipboard::~QWindowsClipboard() { cleanup(); - QWindowsClipboard::m_instance = 0; + QWindowsClipboard::m_instance = nullptr; } void QWindowsClipboard::cleanup() @@ -174,7 +174,7 @@ void QWindowsClipboard::releaseIData() delete m_data->mimeData(); m_data->releaseQt(); m_data->Release(); - m_data = 0; + m_data = nullptr; } } @@ -207,10 +207,10 @@ void QWindowsClipboard::unregisterViewer() m_formatListenerRegistered = false; } else { ChangeClipboardChain(m_clipboardViewer, m_nextClipboardViewer); - m_nextClipboardViewer = 0; + m_nextClipboardViewer = nullptr; } DestroyWindow(m_clipboardViewer); - m_clipboardViewer = 0; + m_clipboardViewer = nullptr; } } @@ -300,7 +300,7 @@ QMimeData *QWindowsClipboard::mimeData(QClipboard::Mode mode) { qCDebug(lcQpaMime) << __FUNCTION__ << mode; if (mode != QClipboard::Clipboard) - return 0; + return nullptr; if (ownsClipboard()) return m_data->mimeData(); return &m_retrievalData; @@ -341,7 +341,7 @@ void QWindowsClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode) void QWindowsClipboard::clear() { - const HRESULT src = OleSetClipboard(0); + const HRESULT src = OleSetClipboard(nullptr); if (src != S_OK) qErrnoWarning("OleSetClipboard: Failed to clear the clipboard: 0x%lx", src); } diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index fee093f675..2b96fb3a5e 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -112,7 +112,7 @@ static inline bool useRTL_Extensions() { // Since the IsValidLanguageGroup/IsValidLocale functions always return true on // Vista, check the Keyboard Layouts for enabling RTL. - if (const int nLayouts = GetKeyboardLayoutList(0, 0)) { + if (const int nLayouts = GetKeyboardLayoutList(0, nullptr)) { QScopedArrayPointer lpList(new HKL[nLayouts]); GetKeyboardLayoutList(nLayouts, lpList.data()); for (int i = 0; i < nLayouts; ++i) { @@ -237,7 +237,7 @@ void QWindowsShcoreDLL::init() QWindowsUser32DLL QWindowsContext::user32dll; QWindowsShcoreDLL QWindowsContext::shcoredll; -QWindowsContext *QWindowsContext::m_instance = 0; +QWindowsContext *QWindowsContext::m_instance = nullptr; /*! \class QWindowsContext @@ -257,7 +257,7 @@ struct QWindowsContextPrivate { unsigned m_systemInfo = 0; QSet m_registeredWindowClassNames; HandleBaseWindowHash m_windows; - HDC m_displayContext = 0; + HDC m_displayContext = nullptr; int m_defaultDPI = 96; QWindowsKeyMapper m_keyMapper; QWindowsMouseHandler m_mouseHandler; @@ -274,14 +274,14 @@ struct QWindowsContextPrivate { }; QWindowsContextPrivate::QWindowsContextPrivate() - : m_oleInitializeResult(OleInitialize(NULL)) + : m_oleInitializeResult(OleInitialize(nullptr)) { QWindowsContext::user32dll.init(); QWindowsContext::shcoredll.init(); if (m_pointerHandler.touchDevice() || m_mouseHandler.touchDevice()) m_systemInfo |= QWindowsContext::SI_SupportsTouch; - m_displayContext = GetDC(0); + m_displayContext = GetDC(nullptr); m_defaultDPI = GetDeviceCaps(m_displayContext, LOGPIXELSY); if (useRTL_Extensions()) { m_systemInfo |= QWindowsContext::SI_RTL_Extensions; @@ -316,7 +316,7 @@ QWindowsContext::~QWindowsContext() OleUninitialize(); d->m_screenManager.clearScreens(); // Order: Potentially calls back to the windows. - m_instance = 0; + m_instance = nullptr; } bool QWindowsContext::initTouch() @@ -400,7 +400,7 @@ int QWindowsContext::processDpiAwareness() { int result; if (QWindowsContext::shcoredll.getProcessDpiAwareness - && SUCCEEDED(QWindowsContext::shcoredll.getProcessDpiAwareness(NULL, &result))) { + && SUCCEEDED(QWindowsContext::shcoredll.getProcessDpiAwareness(nullptr, &result))) { return result; } return -1; @@ -549,7 +549,7 @@ QString QWindowsContext::registerWindowClass(QString cname, // add an instance-specific ID, the address of the window proc. static int classExists = -1; - const HINSTANCE appInstance = static_cast(GetModuleHandle(0)); + const HINSTANCE appInstance = static_cast(GetModuleHandle(nullptr)); if (classExists == -1) { WNDCLASS wcinfo; classExists = GetClassInfo(appInstance, reinterpret_cast(cname.utf16()), &wcinfo); @@ -569,7 +569,7 @@ QString QWindowsContext::registerWindowClass(QString cname, wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = appInstance; - wc.hCursor = 0; + wc.hCursor = nullptr; wc.hbrBackground = brush; if (icon) { wc.hIcon = static_cast(LoadImage(appInstance, L"IDI_ICON1", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE)); @@ -578,15 +578,15 @@ QString QWindowsContext::registerWindowClass(QString cname, int sh = GetSystemMetrics(SM_CYSMICON); wc.hIconSm = static_cast(LoadImage(appInstance, L"IDI_ICON1", IMAGE_ICON, sw, sh, 0)); } else { - wc.hIcon = static_cast(LoadImage(0, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED)); - wc.hIconSm = 0; + wc.hIcon = static_cast(LoadImage(nullptr, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED)); + wc.hIconSm = nullptr; } } else { - wc.hIcon = 0; - wc.hIconSm = 0; + wc.hIcon = nullptr; + wc.hIconSm = nullptr; } - wc.lpszMenuName = 0; + wc.lpszMenuName = nullptr; wc.lpszClassName = reinterpret_cast(cname.utf16()); ATOM atom = RegisterClassEx(&wc); if (!atom) @@ -602,7 +602,7 @@ QString QWindowsContext::registerWindowClass(QString cname, void QWindowsContext::unregisterWindowClasses() { - const HINSTANCE appInstance = static_cast(GetModuleHandle(0)); + const HINSTANCE appInstance = static_cast(GetModuleHandle(nullptr)); for (const QString &name : qAsConst(d->m_registeredWindowClassNames)) { if (!UnregisterClass(reinterpret_cast(name.utf16()), appInstance) && QWindowsContext::verbose) @@ -623,7 +623,7 @@ QString QWindowsContext::windowsErrorMessage(unsigned long errorCode) const DWORD len = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, errorCode, 0, reinterpret_cast(&lpMsgBuf), 0, NULL); + nullptr, errorCode, 0, reinterpret_cast(&lpMsgBuf), 0, nullptr); if (len) { rc = QString::fromUtf16(lpMsgBuf, int(len)); LocalFree(lpMsgBuf); @@ -643,7 +643,7 @@ void QWindowsContext::removeWindow(HWND hwnd) const HandleBaseWindowHash::iterator it = d->m_windows.find(hwnd); if (it != d->m_windows.end()) { if (d->m_keyMapper.keyGrabber() == it.value()->window()) - d->m_keyMapper.setKeyGrabber(0); + d->m_keyMapper.setKeyGrabber(nullptr); d->m_windows.erase(it); } } @@ -683,7 +683,7 @@ QWindow *QWindowsContext::findWindow(HWND hwnd) const { if (const QWindowsWindow *bw = findPlatformWindow(hwnd)) return bw->window(); - return 0; + return nullptr; } QWindow *QWindowsContext::windowUnderMouse() const @@ -750,7 +750,7 @@ QWindowsWindow *QWindowsContext::findPlatformWindowAt(HWND parent, const QPoint &screenPointIn, unsigned cwex_flags) const { - QWindowsWindow *result = 0; + QWindowsWindow *result = nullptr; const POINT screenPoint = { screenPointIn.x(), screenPointIn.y() }; while (findPlatformWindowHelper(screenPoint, cwex_flags, this, &parent, &result)) {} return result; @@ -822,7 +822,7 @@ HWND QWindowsContext::createDummyWindow(const QString &classNameIn, windowName, style, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - HWND_MESSAGE, NULL, static_cast(GetModuleHandle(0)), NULL); + HWND_MESSAGE, nullptr, static_cast(GetModuleHandle(nullptr)), nullptr); } // Re-engineered from the inline function _com_error::ErrorMessage(). @@ -832,8 +832,8 @@ static inline QString errorMessageFromComError(const _com_error &comError) { TCHAR *message = nullptr; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, DWORD(comError.Error()), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), - message, 0, NULL); + nullptr, DWORD(comError.Error()), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), + message, 0, nullptr); if (message) { const QString result = QString::fromWCharArray(message).trimmed(); LocalFree(static_cast(message)); @@ -1323,7 +1323,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, return false; platformWindow->setFlag(QWindowsWindow::WithinDpiChanged); const RECT *prcNewWindow = reinterpret_cast(lParam); - SetWindowPos(hwnd, NULL, prcNewWindow->left, prcNewWindow->top, + SetWindowPos(hwnd, nullptr, prcNewWindow->left, prcNewWindow->top, prcNewWindow->right - prcNewWindow->left, prcNewWindow->bottom - prcNewWindow->top, SWP_NOZORDER | SWP_NOACTIVATE); platformWindow->clearFlag(QWindowsWindow::WithinDpiChanged); @@ -1345,7 +1345,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, qGuiAppPriv->commitData(); if (lParam & ENDSESSION_LOGOFF) - fflush(NULL); + fflush(nullptr); *result = sessionManager->wasCanceled() ? 0 : 1; return true; @@ -1363,7 +1363,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, if (endsession && !qGuiAppPriv->aboutToQuitEmitted) { qGuiAppPriv->aboutToQuitEmitted = true; int index = QGuiApplication::staticMetaObject.indexOfSignal("aboutToQuit()"); - qApp->qt_metacall(QMetaObject::InvokeMetaMethod, index,0); + qApp->qt_metacall(QMetaObject::InvokeMetaMethod, index, nullptr); // since the process will be killed immediately quit() has no real effect QGuiApplication::quit(); } @@ -1384,10 +1384,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, void QWindowsContext::handleFocusEvent(QtWindows::WindowsEventType et, QWindowsWindow *platformWindow) { - QWindow *nextActiveWindow = 0; + QWindow *nextActiveWindow = nullptr; if (et == QtWindows::FocusInEvent) { QWindow *topWindow = QWindowsWindow::topLevelOf(platformWindow->window()); - QWindow *modalWindow = 0; + QWindow *modalWindow = nullptr; if (QGuiApplicationPrivate::instance()->isWindowBlocked(topWindow, &modalWindow) && topWindow != modalWindow) { modalWindow->requestActivate(); return; @@ -1500,10 +1500,11 @@ static DWORD readDwordRegistrySetting(const wchar_t *regKey, const wchar_t *subK HKEY handle; if (RegOpenKeyEx(HKEY_CURRENT_USER, regKey, 0, KEY_READ, &handle) == ERROR_SUCCESS) { DWORD type; - if (RegQueryValueEx(handle, subKey, 0, &type, 0, 0) == ERROR_SUCCESS && type == REG_DWORD) { + if (RegQueryValueEx(handle, subKey, nullptr, &type, nullptr, nullptr) == ERROR_SUCCESS + && type == REG_DWORD) { DWORD value; DWORD size = sizeof(result); - if (RegQueryValueEx(handle, subKey, 0, 0, reinterpret_cast(&value), &size) == ERROR_SUCCESS) + if (RegQueryValueEx(handle, subKey, nullptr, nullptr, reinterpret_cast(&value), &size) == ERROR_SUCCESS) result = value; } RegCloseKey(handle); diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index 4f669a5509..00d011ccec 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -102,7 +102,7 @@ QWindowsPixmapCursorCacheKey::QWindowsPixmapCursorCacheKey(const QCursor &c) HCURSOR QWindowsCursor::createPixmapCursor(QPixmap pixmap, const QPoint &hotSpot, qreal scaleFactor) { - HCURSOR cur = 0; + HCURSOR cur = nullptr; const qreal pixmapScaleFactor = scaleFactor / pixmap.devicePixelRatioF(); if (!qFuzzyCompare(pixmapScaleFactor, 1)) { pixmap = pixmap.scaled((pixmapScaleFactor * QSizeF(pixmap.size())).toSize(), @@ -161,7 +161,7 @@ static HCURSOR createBitmapCursor(const QImage &bbits, const QImage &mbits, ++x; } } - return CreateCursor(GetModuleHandle(0), hotSpot.x(), hotSpot.y(), width, height, + return CreateCursor(GetModuleHandle(nullptr), hotSpot.x(), hotSpot.y(), width, height, xBits.data(), xMask.data()); } @@ -456,7 +456,7 @@ QWindowsCursor::PixmapCursor QWindowsCursor::customCursor(Qt::CursorShape cursor const QSize cursorSize = systemCursorSize(screen); const QWindowsCustomPngCursor *sEnd = pngCursors + sizeof(pngCursors) / sizeof(pngCursors[0]); - const QWindowsCustomPngCursor *bestFit = 0; + const QWindowsCustomPngCursor *bestFit = nullptr; int sizeDelta = INT_MAX; for (const QWindowsCustomPngCursor *s = pngCursors; s < sEnd; ++s) { if (s->shape != cursorShape) @@ -532,7 +532,7 @@ HCURSOR QWindowsCursor::createCursorFromShape(Qt::CursorShape cursorShape, const } qWarning("%s: Invalid cursor shape %d", __FUNCTION__, cursorShape); - return 0; + return nullptr; } /*! @@ -741,10 +741,10 @@ QPixmap QWindowsCursor::dragDefaultCursor(Qt::DropAction action) const "...............XXXX....."}; if (m_ignoreDragCursor.isNull()) { - HCURSOR cursor = LoadCursor(NULL, IDC_NO); - ICONINFO iconInfo = {0, 0, 0, 0, 0}; + HCURSOR cursor = LoadCursor(nullptr, IDC_NO); + ICONINFO iconInfo = {0, 0, 0, nullptr, nullptr}; GetIconInfo(cursor, &iconInfo); - BITMAP bmColor = {0, 0, 0, 0, 0, 0, 0}; + BITMAP bmColor = {0, 0, 0, 0, 0, 0, nullptr}; if (iconInfo.hbmColor && GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmColor) @@ -780,7 +780,7 @@ HCURSOR QWindowsCursor::hCursor(const QCursor &c) const if (sit != m_standardCursorCache.constEnd()) return sit.value()->handle(); } - return HCURSOR(0); + return HCURSOR(nullptr); } /*! diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index b629cc00a3..6da7265cfd 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -133,8 +133,8 @@ namespace QWindowsDialogs void eatMouseMove() { - MSG msg = {0, 0, 0, 0, 0, {0, 0} }; - while (PeekMessage(&msg, 0, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE)) + MSG msg = {nullptr, 0, 0, 0, 0, {0, 0} }; + while (PeekMessage(&msg, nullptr, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE)) ; if (msg.message == WM_MOUSEMOVE) PostMessage(msg.hwnd, msg.message, 0, msg.lParam); @@ -180,7 +180,7 @@ class QWindowsNativeDialogBase : public QObject public: virtual void setWindowTitle(const QString &title) = 0; bool executed() const { return m_executed; } - void exec(HWND owner = 0) { doExec(owner); m_executed = true; } + void exec(HWND owner = nullptr) { doExec(owner); m_executed = true; } signals: void accepted(); @@ -193,7 +193,7 @@ protected: QWindowsNativeDialogBase() : m_executed(false) {} private: - virtual void doExec(HWND owner = 0) = 0; + virtual void doExec(HWND owner = nullptr) = 0; bool m_executed; }; @@ -229,7 +229,7 @@ void QWindowsDialogHelperBase::cleanupThread() qCWarning(lcQpaDialogs) << __FUNCTION__ << "Thread terminated."; } delete m_thread; - m_thread = 0; + m_thread = nullptr; } } @@ -238,7 +238,7 @@ QWindowsNativeDialogBase *QWindowsDialogHelperBase::nativeDialog() co { if (m_nativeDialog.isNull()) { qWarning("%s invoked with no native dialog present.", __FUNCTION__); - return 0; + return nullptr; } return m_nativeDialog.data(); } @@ -300,7 +300,7 @@ bool QWindowsDialogHelperBase::show(Qt::WindowFlags, if (parent) { m_ownerWindow = QWindowsWindow::handleOf(parent); } else { - m_ownerWindow = 0; + m_ownerWindow = nullptr; } qCDebug(lcQpaDialogs) << __FUNCTION__ << "modal=" << modal << " modal supported? " << supportsNonModalDialog(parent) @@ -347,7 +347,7 @@ void QWindowsDialogHelperBase::stopTimer() struct FindDialogContext { explicit FindDialogContext(const QString &titleIn) - : title(qStringToWCharArray(titleIn)), processId(GetCurrentProcessId()), hwnd(0) {} + : title(qStringToWCharArray(titleIn)), processId(GetCurrentProcessId()), hwnd(nullptr) {} const QScopedArrayPointer title; const DWORD processId; @@ -382,7 +382,7 @@ void QWindowsDialogHelperBase::hide() { if (m_nativeDialog) m_nativeDialog->close(); - m_ownerWindow = 0; + m_ownerWindow = nullptr; } template @@ -534,7 +534,7 @@ IFileDialogEvents *QWindowsNativeFileDialogEventHandler::create(QWindowsNativeFi QWindowsNativeFileDialogEventHandler *eventHandler = new QWindowsNativeFileDialogEventHandler(nativeFileDialog); if (FAILED(eventHandler->QueryInterface(IID_IFileDialogEvents, reinterpret_cast(&result)))) { qErrnoWarning("Unable to obtain IFileDialogEvents"); - return 0; + return nullptr; } eventHandler->Release(); return result; @@ -671,7 +671,7 @@ bool QWindowsShellItem::copyData(QIODevice *out) if (!canCopy() || !canStream()) return false; IStream *istream = nullptr; - HRESULT hr = m_item->BindToHandler(NULL, BHID_Stream, IID_PPV_ARGS(&istream)); + HRESULT hr = m_item->BindToHandler(nullptr, BHID_Stream, IID_PPV_ARGS(&istream)); if (FAILED(hr)) return false; enum : ULONG { bufSize = 102400 }; @@ -702,7 +702,7 @@ static IShellLibrary *sHLoadLibraryFromItem(IShellItem *libraryItem, DWORD mode) IShellLibrary *helper = nullptr; IShellLibrary *result = nullptr; - if (SUCCEEDED(CoCreateInstance(classId_ShellLibrary, NULL, CLSCTX_INPROC_SERVER, iId_IShellLibrary, reinterpret_cast(&helper)))) + if (SUCCEEDED(CoCreateInstance(classId_ShellLibrary, nullptr, CLSCTX_INPROC_SERVER, iId_IShellLibrary, reinterpret_cast(&helper)))) if (SUCCEEDED(helper->LoadLibraryFromItem(libraryItem, mode))) helper->QueryInterface(iId_IShellLibrary, reinterpret_cast(&result)); if (helper) @@ -800,7 +800,7 @@ public: inline void setDirectory(const QUrl &directory); inline void updateDirectory() { setDirectory(m_data.directory()); } inline QString directory() const; - void doExec(HWND owner = 0) override; + void doExec(HWND owner = nullptr) override; virtual void setNameFilters(const QStringList &f); inline void selectNameFilter(const QString &filter); inline void updateSelectedNameFilter() { selectNameFilter(m_data.selectedNameFilter()); } @@ -869,7 +869,7 @@ QWindowsNativeFileDialogBase::~QWindowsNativeFileDialogBase() bool QWindowsNativeFileDialogBase::init(const CLSID &clsId, const IID &iid) { - HRESULT hr = CoCreateInstance(clsId, NULL, CLSCTX_INPROC_SERVER, + HRESULT hr = CoCreateInstance(clsId, nullptr, CLSCTX_INPROC_SERVER, iid, reinterpret_cast(&m_fileDialog)); if (FAILED(hr)) { qErrnoWarning("CoCreateInstance failed"); @@ -902,7 +902,7 @@ IShellItem *QWindowsNativeFileDialogBase::shellItem(const QUrl &url) const QString native = QDir::toNativeSeparators(url.toLocalFile()); const HRESULT hr = SHCreateItemFromParsingName(reinterpret_cast(native.utf16()), - NULL, IID_IShellItem, + nullptr, IID_IShellItem, reinterpret_cast(&result)); if (FAILED(hr)) { qErrnoWarning("%s: SHCreateItemFromParsingName(%s)) failed", __FUNCTION__, qPrintable(url.toString())); @@ -920,7 +920,7 @@ IShellItem *QWindowsNativeFileDialogBase::shellItem(const QUrl &url) return nullptr; } PIDLIST_ABSOLUTE idList; - HRESULT hr = SHGetKnownFolderIDList(uuid, 0, 0, &idList); + HRESULT hr = SHGetKnownFolderIDList(uuid, 0, nullptr, &idList); if (FAILED(hr)) { qErrnoWarning("%s: SHGetKnownFolderIDList(%s)) failed", __FUNCTION__, qPrintable(url.toString())); return nullptr; @@ -935,7 +935,7 @@ IShellItem *QWindowsNativeFileDialogBase::shellItem(const QUrl &url) } else { qWarning() << __FUNCTION__ << ": Unhandled scheme: " << url.scheme(); } - return 0; + return nullptr; } void QWindowsNativeFileDialogBase::setDirectory(const QUrl &directory) @@ -951,7 +951,7 @@ void QWindowsNativeFileDialogBase::setDirectory(const QUrl &directory) QString QWindowsNativeFileDialogBase::directory() const { QString result; - IShellItem *item = 0; + IShellItem *item = nullptr; if (m_fileDialog && SUCCEEDED(m_fileDialog->GetFolder(&item)) && item) { result = QWindowsShellItem(item).path(); item->Release(); @@ -1339,7 +1339,7 @@ void QWindowsNativeSaveFileDialog::setNameFilters(const QStringList &f) QList QWindowsNativeSaveFileDialog::dialogResult() const { QList result; - IShellItem *item = 0; + IShellItem *item = nullptr; if (SUCCEEDED(fileDialog()->GetResult(&item)) && item) result.append(QWindowsShellItem(item).url()); return result; @@ -1348,7 +1348,7 @@ QList QWindowsNativeSaveFileDialog::dialogResult() const QList QWindowsNativeSaveFileDialog::selectedFiles() const { QList result; - IShellItem *item = 0; + IShellItem *item = nullptr; const HRESULT hr = fileDialog()->GetCurrentSelection(&item); if (SUCCEEDED(hr) && item) { result.append(QWindowsShellItem(item).url()); @@ -1419,7 +1419,7 @@ static QString createTemporaryItemCopy(QWindowsShellItem &qItem) QList QWindowsNativeOpenFileDialog::dialogResult() const { QList result; - IShellItemArray *items = 0; + IShellItemArray *items = nullptr; if (SUCCEEDED(openFileDialog()->GetResults(&items)) && items) { for (IShellItem *item : QWindowsShellItem::itemsFromItemArray(items)) { QWindowsShellItem qItem(item); @@ -1441,7 +1441,7 @@ QList QWindowsNativeOpenFileDialog::dialogResult() const QList QWindowsNativeOpenFileDialog::selectedFiles() const { QList result; - IShellItemArray *items = 0; + IShellItemArray *items = nullptr; const HRESULT hr = openFileDialog()->GetSelectedItems(&items); if (SUCCEEDED(hr) && items) { for (IShellItem *item : QWindowsShellItem::itemsFromItemArray(items)) { @@ -1465,18 +1465,18 @@ QList QWindowsNativeOpenFileDialog::selectedFiles() const QWindowsNativeFileDialogBase *QWindowsNativeFileDialogBase::create(QFileDialogOptions::AcceptMode am, const QWindowsFileDialogSharedData &data) { - QWindowsNativeFileDialogBase *result = 0; + QWindowsNativeFileDialogBase *result = nullptr; if (am == QFileDialogOptions::AcceptOpen) { result = new QWindowsNativeOpenFileDialog(data); if (!result->init(CLSID_FileOpenDialog, IID_IFileOpenDialog)) { delete result; - return 0; + return nullptr; } } else { result = new QWindowsNativeSaveFileDialog(data); if (!result->init(CLSID_FileSaveDialog, IID_IFileSaveDialog)) { delete result; - return 0; + return nullptr; } } return result; @@ -1497,7 +1497,7 @@ class QWindowsFileDialogHelper : public QWindowsDialogHelperBaseacceptMode(), m_data); if (!result) - return 0; + return nullptr; QObject::connect(result, &QWindowsNativeDialogBase::accepted, this, &QPlatformDialogHelper::accept); QObject::connect(result, &QWindowsNativeDialogBase::rejected, this, &QPlatformDialogHelper::reject); QObject::connect(result, &QWindowsNativeFileDialogBase::directoryEntered, @@ -1638,7 +1638,7 @@ public: static QWindowsXpNativeFileDialog *create(const OptionsPtr &options, const QWindowsFileDialogSharedData &data); void setWindowTitle(const QString &t) override { m_title = t; } - void doExec(HWND owner = 0) override; + void doExec(HWND owner = nullptr) override; int existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam); @@ -1663,8 +1663,8 @@ private: static PtrGetSaveFileNameW m_getSaveFileNameW; }; -QWindowsXpNativeFileDialog::PtrGetOpenFileNameW QWindowsXpNativeFileDialog::m_getOpenFileNameW = 0; -QWindowsXpNativeFileDialog::PtrGetSaveFileNameW QWindowsXpNativeFileDialog::m_getSaveFileNameW = 0; +QWindowsXpNativeFileDialog::PtrGetOpenFileNameW QWindowsXpNativeFileDialog::m_getOpenFileNameW = nullptr; +QWindowsXpNativeFileDialog::PtrGetSaveFileNameW QWindowsXpNativeFileDialog::m_getSaveFileNameW = nullptr; QWindowsXpNativeFileDialog *QWindowsXpNativeFileDialog::create(const OptionsPtr &options, const QWindowsFileDialogSharedData &data) { @@ -1678,7 +1678,7 @@ QWindowsXpNativeFileDialog *QWindowsXpNativeFileDialog::create(const OptionsPtr } if (m_getOpenFileNameW && m_getSaveFileNameW) return new QWindowsXpNativeFileDialog(options, data); - return 0; + return nullptr; } QWindowsXpNativeFileDialog::QWindowsXpNativeFileDialog(const OptionsPtr &options, @@ -1755,8 +1755,8 @@ QList QWindowsXpNativeFileDialog::execExistingDir(HWND owner) wchar_t initPath[MAX_PATH]; initPath[0] = 0; bi.hwndOwner = owner; - bi.pidlRoot = NULL; - bi.lpszTitle = 0; + bi.pidlRoot = nullptr; + bi.lpszTitle = nullptr; bi.pszDisplayName = initPath; bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE; bi.lpfn = xpFileDialogGetExistingDirCallbackProc; @@ -1879,7 +1879,7 @@ class QWindowsXpFileDialogHelper : public QWindowsDialogHelperBaseoptions() & QWindowsIntegration::NoNativeDialogs) - return 0; + return nullptr; switch (type) { case QPlatformTheme::FileDialog: if (QWindowsIntegration::instance()->options() & QWindowsIntegration::XpNativeDialogs) @@ -2107,7 +2107,7 @@ QPlatformDialogHelper *createHelper(QPlatformTheme::DialogType type) default: break; } - return 0; + return nullptr; } } // namespace QWindowsDialogs diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index ee82b2f022..95d1fc8b7d 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -80,7 +80,7 @@ QT_BEGIN_NAMESPACE class QWindowsDragCursorWindow : public QRasterWindow { public: - explicit QWindowsDragCursorWindow(QWindow *parent = 0); + explicit QWindowsDragCursorWindow(QWindow *parent = nullptr); void setPixmap(const QPixmap &p); @@ -264,7 +264,7 @@ QWindowsOleDropSource::QWindowsOleDropSource(QWindowsDrag *drag) , m_drag(drag) , m_windowUnderMouse(QWindowsContext::instance()->windowUnderMouse()) , m_currentButtons(Qt::NoButton) - , m_touchDragWindow(0) + , m_touchDragWindow(nullptr) { qCDebug(lcQpaMime) << __FUNCTION__ << m_mode; } @@ -572,7 +572,7 @@ QWindowsOleDropTarget::DragLeave() qCDebug(lcQpaMime) << __FUNCTION__ << ' ' << m_window; - QWindowSystemInterface::handleDrag(m_window, 0, QPoint(), Qt::IgnoreAction, + QWindowSystemInterface::handleDrag(m_window, nullptr, QPoint(), Qt::IgnoreAction, Qt::NoButton, Qt::NoModifier); if (!QDragManager::self()->source()) @@ -626,7 +626,7 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, FORMATETC format; format.cfFormat = CLIPFORMAT(RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT)); format.tymed = TYMED_HGLOBAL; - format.ptd = 0; + format.ptd = nullptr; format.dwAspect = 1; format.lindex = -1; windowsDrag->dropDataObject()->SetData(&format, &medium, true); @@ -678,7 +678,7 @@ QMimeData *QWindowsDrag::dropData() */ IDropTargetHelper* QWindowsDrag::dropHelper() { if (!m_cachedDropTargetHelper) { - CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER, + CoCreateInstance(CLSID_DragDropHelper, nullptr, CLSCTX_INPROC_SERVER, IID_IDropTargetHelper, reinterpret_cast(&m_cachedDropTargetHelper)); } @@ -739,7 +739,7 @@ void QWindowsDrag::releaseDropDataObject() qCDebug(lcQpaMime) << __FUNCTION__ << m_dropDataObject; if (m_dropDataObject) { m_dropDataObject->Release(); - m_dropDataObject = 0; + m_dropDataObject = nullptr; } } diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index 52f3c56beb..70ba2784e9 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -103,7 +103,7 @@ static inline void *resolveFunc(HMODULE lib, const char *name) void *QWindowsLibEGL::resolve(const char *name) { - return m_lib ? resolveFunc(m_lib, name) : 0; + return m_lib ? resolveFunc(m_lib, name) : nullptr; } #endif // !QT_STATIC @@ -155,7 +155,7 @@ bool QWindowsLibEGL::init() if (!eglGetError || !eglGetDisplay || !eglInitialize || !eglGetProcAddress) return false; - eglGetPlatformDisplayEXT = 0; + eglGetPlatformDisplayEXT = nullptr; #ifdef EGL_ANGLE_platform_angle eglGetPlatformDisplayEXT = reinterpret_cast(eglGetProcAddress("eglGetPlatformDisplayEXT")); #endif @@ -166,7 +166,7 @@ bool QWindowsLibEGL::init() #if !defined(QT_STATIC) || defined(QT_OPENGL_DYNAMIC) void *QWindowsLibGLESv2::resolve(const char *name) { - return m_lib ? resolveFunc(m_lib, name) : 0; + return m_lib ? resolveFunc(m_lib, name) : nullptr; } #endif // !QT_STATIC @@ -213,7 +213,7 @@ bool QWindowsEGLStaticContext::initializeAngle(QWindowsOpenGLTester::Renderers p { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE, EGL_NONE } }; - const EGLint *attributes = 0; + const EGLint *attributes = nullptr; if (preferredType & QWindowsOpenGLTester::AngleRendererD3d11) attributes = anglePlatformAttributes[0]; else if (preferredType & QWindowsOpenGLTester::AngleRendererD3d9) @@ -245,16 +245,16 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester: const HDC dc = QWindowsContext::instance()->displayContext(); if (!dc){ qWarning("%s: No Display", __FUNCTION__); - return 0; + return nullptr; } if (!libEGL.init()) { qWarning("%s: Failed to load and resolve libEGL functions", __FUNCTION__); - return 0; + return nullptr; } if (!libGLESv2.init()) { qWarning("%s: Failed to load and resolve libGLESv2 functions", __FUNCTION__); - return 0; + return nullptr; } EGLDisplay display = EGL_NO_DISPLAY; @@ -271,7 +271,7 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester: display = libEGL.eglGetDisplay(dc); if (!display) { qWarning("%s: Could not obtain EGL display", __FUNCTION__); - return 0; + return nullptr; } if (!major && !libEGL.eglInitialize(display, &major, &minor)) { @@ -279,7 +279,7 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester: qWarning("%s: Could not initialize EGL display: error 0x%x", __FUNCTION__, err); if (err == 0x3001) qWarning("%s: When using ANGLE, check if d3dcompiler_4x.dll is available", __FUNCTION__); - return 0; + return nullptr; } qCDebug(lcQpaGl) << __FUNCTION__ << "Created EGL display" << display << 'v' <(nativeWindow), 0); + static_cast(nativeWindow), nullptr); if (surface == EGL_NO_SURFACE) { *err = libEGL.eglGetError(); qWarning("%s: Could not create the EGL window surface: 0x%x", __FUNCTION__, *err); @@ -390,7 +390,7 @@ QWindowsEGLContext::QWindowsEGLContext(QWindowsEGLStaticContext *staticContext, m_eglConfig = chooseConfig(format); m_format = m_staticContext->formatFromConfig(m_eglDisplay, m_eglConfig, format); - m_shareContext = share ? static_cast(share)->m_eglContext : 0; + m_shareContext = share ? static_cast(share)->m_eglContext : nullptr; QVector contextAttrs; contextAttrs.append(EGL_CONTEXT_CLIENT_VERSION); @@ -400,8 +400,8 @@ QWindowsEGLContext::QWindowsEGLContext(QWindowsEGLStaticContext *staticContext, QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); m_eglContext = QWindowsEGLStaticContext::libEGL.eglCreateContext(m_eglDisplay, m_eglConfig, m_shareContext, contextAttrs.constData()); if (m_eglContext == EGL_NO_CONTEXT && m_shareContext != EGL_NO_CONTEXT) { - m_shareContext = 0; - m_eglContext = QWindowsEGLStaticContext::libEGL.eglCreateContext(m_eglDisplay, m_eglConfig, 0, contextAttrs.constData()); + m_shareContext = nullptr; + m_eglContext = QWindowsEGLStaticContext::libEGL.eglCreateContext(m_eglDisplay, m_eglConfig, nullptr, contextAttrs.constData()); } if (m_eglContext == EGL_NO_CONTEXT) { @@ -862,11 +862,11 @@ EGLConfig QWindowsEGLContext::chooseConfig(const QSurfaceFormat &format) configureAttributes.append(EGL_NONE); EGLDisplay display = m_staticContext->display(); - EGLConfig cfg = 0; + EGLConfig cfg = nullptr; do { // Get the number of matching configurations for this set of properties. EGLint matching = 0; - if (!QWindowsEGLStaticContext::libEGL.eglChooseConfig(display, configureAttributes.constData(), 0, 0, &matching) || !matching) + if (!QWindowsEGLStaticContext::libEGL.eglChooseConfig(display, configureAttributes.constData(), nullptr, 0, &matching) || !matching) continue; // Fetch all of the matching configurations and find the diff --git a/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp b/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp index 4ba7108f45..08e11c5e39 100644 --- a/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp @@ -48,13 +48,13 @@ void *QWindowsGdiNativeInterface::nativeResourceForBackingStore(const QByteArray { if (!bs || !bs->handle()) { qWarning("%s: '%s' requested for null backingstore or backingstore without handle.", __FUNCTION__, resource.constData()); - return 0; + return nullptr; } QWindowsBackingStore *wbs = static_cast(bs->handle()); if (resource == "getDC") return wbs->getDC(); qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); - return 0; + return nullptr; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index 21cb794196..e95eaef420 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -322,7 +322,7 @@ static inline bool static void describeFormats(HDC hdc) { - const int pfiMax = DescribePixelFormat(hdc, 0, 0, NULL); + const int pfiMax = DescribePixelFormat(hdc, 0, 0, nullptr); for (int i = 0; i < pfiMax; i++) { PIXELFORMATDESCRIPTOR pfd; initPixelFormatDescriptor(&pfd); @@ -335,7 +335,7 @@ static void describeFormats(HDC hdc) namespace GDI { static QSurfaceFormat qSurfaceFormatFromPixelFormat(const PIXELFORMATDESCRIPTOR &pfd, - QWindowsOpenGLAdditionalFormat *additionalIn = 0) + QWindowsOpenGLAdditionalFormat *additionalIn = nullptr) { QSurfaceFormat format; format.setRenderableType(QSurfaceFormat::OpenGL); @@ -437,7 +437,7 @@ static int choosePixelFormat(HDC hdc, const QSurfaceFormat &format, return pixelFormat; } // 2) No matching format found, manual search loop. - const int pfiMax = DescribePixelFormat(hdc, 0, 0, NULL); + const int pfiMax = DescribePixelFormat(hdc, 0, 0, nullptr); int bestScore = -1; int bestPfi = -1; const bool stereoRequested = format.stereo(); @@ -479,7 +479,7 @@ static inline HGLRC createContext(HDC hdc, HGLRC shared) HGLRC result = QOpenGLStaticContext::opengl32.wglCreateContext(hdc); if (!result) { qErrnoWarning("%s: wglCreateContext failed.", __FUNCTION__); - return 0; + return nullptr; } if (shared && !QOpenGLStaticContext::opengl32.wglShareLists(shared, result)) qErrnoWarning("%s: wglShareLists() failed.", __FUNCTION__); @@ -590,7 +590,7 @@ static int choosePixelFormat(HDC hdc, uint numFormats = 0; while (true) { const bool valid = - staticContext.wglChoosePixelFormatARB(hdc, iAttributes, 0, 1, + staticContext.wglChoosePixelFormatARB(hdc, iAttributes, nullptr, 1, &pixelFormat, &numFormats) && numFormats >= 1; if (valid || (!sampleBuffersRequested && !srgbRequested)) @@ -646,7 +646,7 @@ static int choosePixelFormat(HDC hdc, static QSurfaceFormat qSurfaceFormatFromHDC(const QOpenGLStaticContext &staticContext, HDC hdc, int pixelFormat, - QWindowsOpenGLAdditionalFormat *additionalIn = 0) + QWindowsOpenGLAdditionalFormat *additionalIn = nullptr) { enum { attribSize = 42 }; @@ -720,12 +720,12 @@ static HGLRC createContext(const QOpenGLStaticContext &staticContext, HDC hdc, const QSurfaceFormat &format, const QWindowsOpenGLAdditionalFormat &, - HGLRC shared = 0) + HGLRC shared = nullptr) { enum { attribSize = 11 }; if (!staticContext.hasExtensions()) - return 0; + return nullptr; int attributes[attribSize]; int attribIndex = 0; std::fill(attributes, attributes + attribSize, int(0)); @@ -797,14 +797,14 @@ static inline HWND createDummyGLWindow() { return QWindowsContext::instance()-> createDummyWindow(QStringLiteral("QtOpenGLDummyWindow"), - L"OpenGLDummyWindow", 0, WS_OVERLAPPED | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); + L"OpenGLDummyWindow", nullptr, WS_OVERLAPPED | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); } // Create a dummy GL context (see QOpenGLTemporaryContext). static inline HGLRC createDummyGLContext(HDC dc) { if (!dc) - return 0; + return nullptr; PIXELFORMATDESCRIPTOR pixelFormDescriptor; initPixelFormatDescriptor(&pixelFormDescriptor); pixelFormDescriptor.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_GENERIC_FORMAT; @@ -813,16 +813,16 @@ static inline HGLRC createDummyGLContext(HDC dc) const int pixelFormat = ChoosePixelFormat(dc, &pixelFormDescriptor); if (!pixelFormat) { qErrnoWarning("%s: ChoosePixelFormat failed.", __FUNCTION__); - return 0; + return nullptr; } if (!QOpenGLStaticContext::opengl32.setPixelFormat(dc, pixelFormat, &pixelFormDescriptor)) { qErrnoWarning("%s: SetPixelFormat failed.", __FUNCTION__); - return 0; + return nullptr; } HGLRC rc = QOpenGLStaticContext::opengl32.wglCreateContext(dc); if (!rc) { qErrnoWarning("%s: wglCreateContext failed.", __FUNCTION__); - return 0; + return nullptr; } return rc; } @@ -1002,7 +1002,7 @@ QOpenGLStaticContext *QOpenGLStaticContext::create(bool softwareRendering) { if (!opengl32.init(softwareRendering)) { qWarning("Failed to load and resolve WGL/OpenGL functions"); - return 0; + return nullptr; } // We need a current context for wglGetProcAdress()/getGLString() to work. @@ -1033,12 +1033,12 @@ QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext, QOpenGLContext *context) : m_staticContext(staticContext), m_context(context), - m_renderingContext(0), + m_renderingContext(nullptr), m_pixelFormat(0), m_extensionsUsed(false), m_swapInterval(-1), m_ownsContext(true), - m_getGraphicsResetStatus(0), + m_getGraphicsResetStatus(nullptr), m_lost(false) { if (!m_staticContext) // Something went very wrong. Stop here, isValid() will return false. @@ -1081,7 +1081,7 @@ QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext, if (ok) m_ownsContext = false; else - m_renderingContext = 0; + m_renderingContext = nullptr; return; } @@ -1105,8 +1105,8 @@ QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext, // Create a dummy one as we are not associated with a window yet. // Try to find a suitable pixel format using preferably ARB extensions // (default to GDI) and store that. - HWND dummyWindow = 0; - HDC hdc = 0; + HWND dummyWindow = nullptr; + HDC hdc = nullptr; bool tryExtensions = false; int obtainedSwapInterval = -1; do { @@ -1163,7 +1163,7 @@ QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext, break; } // Create context with sharing, again preferably using ARB. - HGLRC sharingRenderingContext = 0; + HGLRC sharingRenderingContext = nullptr; if (const QPlatformOpenGLContext *sc = context->shareHandle()) sharingRenderingContext = static_cast(sc)->renderingContext(); @@ -1190,7 +1190,7 @@ QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext, // Make the HGLRC retrievable via QOpenGLContext::nativeHandle(). // Do not provide the window since it is the dummy one and it is about to disappear. if (m_renderingContext) - context->setNativeHandle(QVariant::fromValue(QWGLNativeContext(m_renderingContext, 0))); + context->setNativeHandle(QVariant::fromValue(QWGLNativeContext(m_renderingContext, nullptr))); if (hdc) ReleaseDC(dummyWindow, hdc); @@ -1281,7 +1281,7 @@ static inline const QOpenGLContextData * if (e.hwnd == hwnd) return &e; } - return 0; + return nullptr; } void QWindowsGLContext::swapBuffers(QPlatformSurface *surface) @@ -1365,7 +1365,7 @@ void QWindowsGLContext::doneCurrent() if (QWindowsContext::verbose > 1) qCDebug(lcQpaGl) << __FUNCTION__ << this << m_windowContexts.size() << "contexts"; #endif // DEBUG_GL - QOpenGLStaticContext::opengl32.wglMakeCurrent(0, 0); + QOpenGLStaticContext::opengl32.wglMakeCurrent(nullptr, nullptr); releaseDCs(); } diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index d1e99c037b..8adcf56b11 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -311,10 +311,10 @@ void QWindowsInputContext::setWindowsImeEnabled(QWindowsWindow *platformWindow, return; if (enabled) { // Re-enable Windows IME by associating default context. - ImmAssociateContextEx(platformWindow->handle(), 0, IACE_DEFAULT); + ImmAssociateContextEx(platformWindow->handle(), nullptr, IACE_DEFAULT); } else { // Disable Windows IME by associating 0 context. - ImmAssociateContext(platformWindow->handle(), 0); + ImmAssociateContext(platformWindow->handle(), nullptr); } } @@ -539,7 +539,7 @@ bool QWindowsInputContext::composition(HWND hwnd, LPARAM lParamIn) // attribute sequence specifying the formatting of the converted part. int selStart, selLength; m_compositionContext.composition = getCompositionString(himc, GCS_COMPSTR); - m_compositionContext.position = ImmGetCompositionString(himc, GCS_CURSORPOS, 0, 0); + m_compositionContext.position = ImmGetCompositionString(himc, GCS_CURSORPOS, nullptr, 0); getCompositionStringConvertedRange(himc, &selStart, &selLength); if ((lParam & CS_INSERTCHAR) && (lParam & CS_NOMOVECARET)) { // make Korean work correctly. Hope this is correct for all IMEs @@ -620,11 +620,11 @@ void QWindowsInputContext::doneContext() { if (!m_compositionContext.hwnd) return; - m_compositionContext.hwnd = 0; + m_compositionContext.hwnd = nullptr; m_compositionContext.composition.clear(); m_compositionContext.position = 0; m_compositionContext.isComposing = false; - m_compositionContext.focusObject = 0; + m_compositionContext.focusObject = nullptr; } bool QWindowsInputContext::handleIME_Request(WPARAM wParam, diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index cae1452885..2c90b0484e 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -461,7 +461,7 @@ QPlatformOpenGLContext *QWindowsIntegration::createPlatformOpenGLContext(QOpenGL if (result->isValid()) return result.take(); } - return 0; + return nullptr; } QOpenGLContext::OpenGLModuleType QWindowsIntegration::openGLModuleType() @@ -481,7 +481,7 @@ QWindowsStaticOpenGLContext *QWindowsIntegration::staticOpenGLContext() { QWindowsIntegration *integration = QWindowsIntegration::instance(); if (!integration) - return 0; + return nullptr; QWindowsIntegrationPrivate *d = integration->d.data(); QMutexLocker lock(&d->m_staticContextLock); if (d->m_staticOpenGLContext.isNull()) diff --git a/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp b/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp index 8f1d8f73d9..44b7523fa6 100644 --- a/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp +++ b/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp @@ -70,7 +70,7 @@ bool QWindowsInternalMimeData::hasFormat_sys(const QString &mime) const return false; const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter(); - const bool has = mc.converterToMime(mime, pDataObj) != 0; + const bool has = mc.converterToMime(mime, pDataObj) != nullptr; releaseDataObject(pDataObj); qCDebug(lcQpaMime) << __FUNCTION__ << mime << has; return has; diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index 96abfdb9d7..c050369801 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -97,7 +97,7 @@ QT_BEGIN_NAMESPACE static void clearKeyRecorderOnApplicationInActive(Qt::ApplicationState state); QWindowsKeyMapper::QWindowsKeyMapper() - : m_useRTLExtensions(false), m_keyGrabber(0) + : m_useRTLExtensions(false), m_keyGrabber(nullptr) { memset(keyLayout, 0, sizeof(keyLayout)); QGuiApplication *app = static_cast(QGuiApplication::instance()); @@ -162,7 +162,7 @@ static void clearKeyRecorderOnApplicationInActive(Qt::ApplicationState state) KeyRecord *KeyRecorder::findKey(int code, bool remove) { - KeyRecord *result = 0; + KeyRecord *result = nullptr; for (int i = 0; i < nrecs; ++i) { if (records[i].code == code) { if (remove) { @@ -605,7 +605,7 @@ inline quint32 winceKeyBend(quint32 keyCode) } // Translate a VK into a Qt key code, or unicode character -static inline quint32 toKeyOrUnicode(quint32 vk, quint32 scancode, unsigned char *kbdBuffer, bool *isDeadkey = 0) +static inline quint32 toKeyOrUnicode(quint32 vk, quint32 scancode, unsigned char *kbdBuffer, bool *isDeadkey = nullptr) { Q_ASSERT(vk > 0 && vk < 256); quint32 code = 0; @@ -822,7 +822,7 @@ static void showSystemMenu(QWindow* w) TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD, pos.x(), pos.y(), topLevelHwnd, - 0); + nullptr); if (ret) qWindowsWndProc(topLevelHwnd, WM_SYSCOMMAND, WPARAM(ret), 0); } @@ -1023,13 +1023,15 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg, if (dirStatus == VK_LSHIFT && ((msg.wParam == VK_SHIFT && GetKeyState(VK_LCONTROL)) || (msg.wParam == VK_CONTROL && GetKeyState(VK_LSHIFT)))) { - sendExtendedPressRelease(receiver, Qt::Key_Direction_L, 0, scancode, vk_key, nModifiers, QString(), false); + sendExtendedPressRelease(receiver, Qt::Key_Direction_L, nullptr, + scancode, vk_key, nModifiers, QString(), false); result = true; dirStatus = 0; } else if (dirStatus == VK_RSHIFT && ( (msg.wParam == VK_SHIFT && GetKeyState(VK_RCONTROL)) || (msg.wParam == VK_CONTROL && GetKeyState(VK_RSHIFT)))) { - sendExtendedPressRelease(receiver, Qt::Key_Direction_R, 0, scancode, vk_key, nModifiers, QString(), false); + sendExtendedPressRelease(receiver, Qt::Key_Direction_R, nullptr, + scancode, vk_key, nModifiers, QString(), false); result = true; dirStatus = 0; } else { @@ -1140,7 +1142,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg, // This will stop the auto-repeat of the key, should a modifier change, for example if (rec && rec->state != state) { key_recorder.findKey(int(msg.wParam), true); - rec = 0; + rec = nullptr; } // Find unicode character from Windows Message Queue @@ -1150,7 +1152,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg, : msgType == WM_IME_KEYDOWN ? WM_IME_CHAR : WM_SYSCHAR); QChar uch; - if (PeekMessage(&wm_char, 0, charType, charType, PM_REMOVE)) { + if (PeekMessage(&wm_char, nullptr, charType, charType, PM_REMOVE)) { if (QWindowsContext::filterNativeEvent(&wm_char, lResult)) return true; if (receiver && QWindowsContext::filterNativeEvent(receiver, &wm_char, lResult)) diff --git a/src/plugins/platforms/windows/qwindowsmenu.cpp b/src/plugins/platforms/windows/qwindowsmenu.cpp index 71802b9017..5a92a7cf90 100644 --- a/src/plugins/platforms/windows/qwindowsmenu.cpp +++ b/src/plugins/platforms/windows/qwindowsmenu.cpp @@ -797,7 +797,7 @@ QWindowsMenuBar *QWindowsMenuBar::menuBarOf(const QWindow *notYetCreatedWindow) static inline void forceNcCalcSize(HWND hwnd) { // Force WM_NCCALCSIZE to adjust margin: Does not appear to work? - SetWindowPos(hwnd, 0, 0, 0, 0, 0, + SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER); } diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp index ff0dccb0d9..96e34fb44c 100644 --- a/src/plugins/platforms/windows/qwindowsmime.cpp +++ b/src/plugins/platforms/windows/qwindowsmime.cpp @@ -312,7 +312,7 @@ static FORMATETC setCf(int cf) formatetc.cfFormat = CLIPFORMAT(cf); formatetc.dwAspect = DVASPECT_CONTENT; formatetc.lindex = -1; - formatetc.ptd = NULL; + formatetc.ptd = nullptr; formatetc.tymed = TYMED_HGLOBAL; return formatetc; } @@ -328,7 +328,7 @@ static bool setData(const QByteArray &data, STGMEDIUM *pmedium) GlobalUnlock(hData); pmedium->tymed = TYMED_HGLOBAL; pmedium->hGlobal = hData; - pmedium->pUnkForRelease = 0; + pmedium->pUnkForRelease = nullptr; return true; } @@ -352,7 +352,7 @@ static QByteArray getData(int cf, IDataObject *pDataObj, int lindex = -1) ULONG actualRead = 0; LARGE_INTEGER pos = {{0, 0}}; //Move to front (can fail depending on the data model implemented) - HRESULT hr = s.pstm->Seek(pos, STREAM_SEEK_SET, NULL); + HRESULT hr = s.pstm->Seek(pos, STREAM_SEEK_SET, nullptr); while(SUCCEEDED(hr)){ hr = s.pstm->Read(szBuffer, sizeof(szBuffer), &actualRead); if (SUCCEEDED(hr) && actualRead > 0) { @@ -1123,11 +1123,11 @@ bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeD bool QWindowsMimeImage::hasOriginalDIBV5(IDataObject *pDataObj) const { bool isSynthesized = true; - IEnumFORMATETC *pEnum =NULL; + IEnumFORMATETC *pEnum = nullptr; HRESULT res = pDataObj->EnumFormatEtc(1, &pEnum); if (res == S_OK && pEnum) { FORMATETC fc; - while ((res = pEnum->Next(1, &fc, 0)) == S_OK) { + while ((res = pEnum->Next(1, &fc, nullptr)) == S_OK) { if (fc.ptd) CoTaskMemFree(fc.ptd); if (fc.cfFormat == CF_DIB) @@ -1398,7 +1398,7 @@ static bool isCustomMimeType(const QString &mimeType) return mimeType.startsWith(QLatin1String(x_qt_windows_mime), Qt::CaseInsensitive); } -static QString customMimeType(const QString &mimeType, int *lindex = 0) +static QString customMimeType(const QString &mimeType, int *lindex = nullptr) { int len = sizeof(x_qt_windows_mime) - 1; int n = mimeType.lastIndexOf(QLatin1Char('\"')) - len; @@ -1510,7 +1510,7 @@ QWindowsMime * QWindowsMimeConverter::converterToMime(const QString &mimeType, I if (m_mimes.at(i)->canConvertToMime(mimeType, pDataObj)) return m_mimes.at(i); } - return 0; + return nullptr; } QStringList QWindowsMimeConverter::allMimesForFormats(IDataObject *pDataObj) const @@ -1523,7 +1523,7 @@ QStringList QWindowsMimeConverter::allMimesForFormats(IDataObject *pDataObj) con if (hr == NOERROR) { FORMATETC fmtetc; - while (S_OK == fmtenum->Next(1, &fmtetc, 0)) { + while (S_OK == fmtenum->Next(1, &fmtetc, nullptr)) { for (int i= m_mimes.size() - 1; i >= 0; --i) { QString format = m_mimes.at(i)->mimeForFormat(fmtetc); if (!format.isEmpty() && !formats.contains(format)) { @@ -1550,7 +1550,7 @@ QWindowsMime * QWindowsMimeConverter::converterFromMime(const FORMATETC &formate if (m_mimes.at(i)->canConvertFromMime(formatetc, mimeData)) return m_mimes.at(i); } - return 0; + return nullptr; } QVector QWindowsMimeConverter::allFormatsForMime(const QMimeData *mimeData) const diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index fcdd179a31..737fd1d2a9 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -75,11 +75,11 @@ static inline void compressMouseMove(MSG *msg) // key release events (kls 2003-05-13): MSG keyMsg; bool done = false; - while (PeekMessage(&keyMsg, 0, WM_KEYFIRST, WM_KEYLAST, + while (PeekMessage(&keyMsg, nullptr, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE)) { if (keyMsg.time < mouseMsg.time) { if ((keyMsg.lParam & 0xC0000000) == 0x40000000) { - PeekMessage(&keyMsg, 0, keyMsg.message, + PeekMessage(&keyMsg, nullptr, keyMsg.message, keyMsg.message, PM_REMOVE); } else { done = true; @@ -121,7 +121,7 @@ static inline QTouchDevice *createTouchDevice() { const int digitizers = GetSystemMetrics(SM_DIGITIZER); if (!(digitizers & (NID_INTEGRATED_TOUCH | NID_EXTERNAL_TOUCH))) - return 0; + return nullptr; const int tabletPc = GetSystemMetrics(SM_TABLETPC); const int maxTouchPoints = GetSystemMetrics(SM_MAXIMUMTOUCHES); qCDebug(lcQpaEvents) << "Digitizers:" << hex << showbase << (digitizers & ~NID_READY) @@ -159,7 +159,7 @@ QTouchDevice *QWindowsMouseHandler::ensureTouchDevice() Qt::MouseButtons QWindowsMouseHandler::queryMouseButtons() { - Qt::MouseButtons result = 0; + Qt::MouseButtons result = nullptr; const bool mouseSwapped = GetSystemMetrics(SM_SWAPBUTTON); if (GetAsyncKeyState(VK_LBUTTON) < 0) result |= mouseSwapped ? Qt::RightButton: Qt::LeftButton; @@ -327,8 +327,8 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, QWindow *leaveTarget = m_windowUnderMouse ? m_windowUnderMouse : m_trackedWindow; qCDebug(lcQpaEvents) << "Generating leave event for " << leaveTarget; QWindowSystemInterface::handleLeaveEvent(leaveTarget); - m_trackedWindow = 0; - m_windowUnderMouse = 0; + m_trackedWindow = nullptr; + m_windowUnderMouse = nullptr; } return true; } @@ -430,7 +430,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, if (currentNotCapturing) { // Clear tracking if capturing and current window is not the capturing window // to avoid leave when mouse actually leaves the application. - m_trackedWindow = 0; + m_trackedWindow = nullptr; // We are not officially in any window, but we need to set some cursor to clear // whatever cursor the left window had, so apply the cursor of the capture window. platformWindow->applyCursor(); @@ -464,7 +464,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, QWindowsKeyMapper::queryKeyboardModifiers(), source); } - m_previousCaptureWindow = hasCapture ? window : 0; + m_previousCaptureWindow = hasCapture ? window : nullptr; // QTBUG-48117, force synchronous handling for the extra buttons so that WM_APPCOMMAND // is sent for unhandled WM_XBUTTONDOWN. return (msg.message != WM_XBUTTONUP && msg.message != WM_XBUTTONDOWN && msg.message != WM_XBUTTONDBLCLK) @@ -595,7 +595,7 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND, QTouchPointList touchPoints; touchPoints.reserve(winTouchPointCount); - Qt::TouchPointStates allStates = 0; + Qt::TouchPointStates allStates = nullptr; GetTouchInputInfo(reinterpret_cast(msg.lParam), UINT(msg.wParam), winTouchInputs.data(), sizeof(TOUCHINPUT)); diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp index de11356fd4..32eec322e8 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -95,7 +95,7 @@ void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resourc { if (!window || !window->handle()) { qWarning("%s: '%s' requested for null window or window without handle.", __FUNCTION__, resource.constData()); - return 0; + return nullptr; } QWindowsWindow *bw = static_cast(window->handle()); int type = resourceType(resource); @@ -108,7 +108,7 @@ void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resourc return bw->getDC(); if (type == ReleaseDCType) { bw->releaseDC(); - return 0; + return nullptr; } break; case QWindow::VulkanSurface: @@ -121,7 +121,7 @@ void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resourc break; } qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); - return 0; + return nullptr; } #ifndef QT_NO_CURSOR @@ -179,7 +179,7 @@ void *QWindowsNativeInterface::nativeResourceForIntegration(const QByteArray &re } #endif - return 0; + return nullptr; } #ifndef QT_NO_OPENGL @@ -187,7 +187,7 @@ void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resour { if (!context || !context->handle()) { qWarning("%s: '%s' requested for null context or context without handle.", __FUNCTION__, resource.constData()); - return 0; + return nullptr; } QWindowsOpenGLContext *glcontext = static_cast(context->handle()); @@ -204,7 +204,7 @@ void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resour } qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); - return 0; + return nullptr; } #endif // !QT_NO_OPENGL diff --git a/src/plugins/platforms/windows/qwindowsole.cpp b/src/plugins/platforms/windows/qwindowsole.cpp index ad0442c8bd..e9c3f2cbf6 100644 --- a/src/plugins/platforms/windows/qwindowsole.cpp +++ b/src/plugins/platforms/windows/qwindowsole.cpp @@ -84,7 +84,7 @@ QWindowsOleDataObject::~QWindowsOleDataObject() = default; void QWindowsOleDataObject::releaseQt() { - data = 0; + data = nullptr; } QMimeData *QWindowsOleDataObject::mimeData() const @@ -142,7 +142,7 @@ QWindowsOleDataObject::QueryGetData(LPFORMATETC pformatetc) STDMETHODIMP QWindowsOleDataObject::GetCanonicalFormatEtc(LPFORMATETC, LPFORMATETC pformatetcOut) { - pformatetcOut->ptd = NULL; + pformatetcOut->ptd = nullptr; return ResultFromScode(E_NOTIMPL); } @@ -188,7 +188,7 @@ QWindowsOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppe formatetc.cfFormat = CLIPFORMAT(CF_PERFORMEDDROPEFFECT); formatetc.dwAspect = DVASPECT_CONTENT; formatetc.lindex = -1; - formatetc.ptd = NULL; + formatetc.ptd = nullptr; formatetc.tymed = TYMED_HGLOBAL; fmtetcs.append(formatetc); } @@ -197,7 +197,7 @@ QWindowsOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppe *ppenumFormatEtc = enumFmtEtc; if (enumFmtEtc->isNull()) { delete enumFmtEtc; - *ppenumFormatEtc = NULL; + *ppenumFormatEtc = nullptr; sc = E_OUTOFMEMORY; } @@ -295,7 +295,7 @@ QWindowsOleEnumFmtEtc::Next(ULONG celt, LPFORMATETC rgelt, ULONG FAR* pceltFetch ULONG i=0; ULONG nOffset; - if (rgelt == NULL) + if (rgelt == nullptr) return ResultFromScode(E_INVALIDARG); while (i < celt) { @@ -311,7 +311,7 @@ QWindowsOleEnumFmtEtc::Next(ULONG celt, LPFORMATETC rgelt, ULONG FAR* pceltFetch m_nIndex += i; - if (pceltFetched != NULL) + if (pceltFetched != nullptr) *pceltFetched = i; if (i != celt) @@ -354,7 +354,7 @@ QWindowsOleEnumFmtEtc::Reset() STDMETHODIMP QWindowsOleEnumFmtEtc::Clone(LPENUMFORMATETC FAR* newEnum) { - if (newEnum == NULL) + if (newEnum == nullptr) return ResultFromScode(E_INVALIDARG); QWindowsOleEnumFmtEtc *result = new QWindowsOleEnumFmtEtc(m_lpfmtetcs); @@ -371,7 +371,7 @@ QWindowsOleEnumFmtEtc::Clone(LPENUMFORMATETC FAR* newEnum) bool QWindowsOleEnumFmtEtc::copyFormatEtc(LPFORMATETC dest, const FORMATETC *src) const { - if (dest == NULL || src == NULL) + if (dest == nullptr || src == nullptr) return false; *dest = *src; diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp index 3efccf0f32..2046135725 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.cpp +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -330,10 +330,10 @@ bool QWindowsOpenGLTester::testDesktopGL() typedef BOOL (WINAPI *MakeCurrentType)(HDC, HGLRC); typedef PROC (WINAPI *WglGetProcAddressType)(LPCSTR); - HMODULE lib = 0; - HWND wnd = 0; - HDC dc = 0; - HGLRC context = 0; + HMODULE lib = nullptr; + HWND wnd = nullptr; + HDC dc = nullptr; + HGLRC context = nullptr; LPCTSTR className = L"qtopengltest"; CreateContextType CreateContext = nullptr; @@ -367,18 +367,18 @@ bool QWindowsOpenGLTester::testDesktopGL() WNDCLASS wclass; wclass.cbClsExtra = 0; wclass.cbWndExtra = 0; - wclass.hInstance = static_cast(GetModuleHandle(0)); - wclass.hIcon = 0; - wclass.hCursor = 0; + wclass.hInstance = static_cast(GetModuleHandle(nullptr)); + wclass.hIcon = nullptr; + wclass.hCursor = nullptr; wclass.hbrBackground = HBRUSH(COLOR_BACKGROUND); - wclass.lpszMenuName = 0; + wclass.lpszMenuName = nullptr; wclass.lpfnWndProc = DefWindowProc; wclass.lpszClassName = className; wclass.style = CS_OWNDC; if (!RegisterClass(&wclass)) goto cleanup; wnd = CreateWindow(className, L"qtopenglproxytest", WS_OVERLAPPED, - 0, 0, 640, 480, 0, 0, wclass.hInstance, 0); + 0, 0, 640, 480, nullptr, nullptr, wclass.hInstance, nullptr); if (!wnd) goto cleanup; dc = GetDC(wnd); @@ -447,14 +447,14 @@ bool QWindowsOpenGLTester::testDesktopGL() cleanup: if (MakeCurrent) - MakeCurrent(0, 0); + MakeCurrent(nullptr, nullptr); if (context) DeleteContext(context); if (dc && wnd) ReleaseDC(wnd, dc); if (wnd) { DestroyWindow(wnd); - UnregisterClass(className, GetModuleHandle(0)); + UnregisterClass(className, GetModuleHandle(nullptr)); } // No FreeLibrary. Some implementations, Mesa in particular, deadlock when trying to unload. diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 2eaf386d42..a161dc46e9 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -89,7 +89,7 @@ static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data) if (data->name == QLatin1String("WinDisc")) { data->flags |= QWindowsScreenData::LockScreen; } else { - if (const HDC hdc = CreateDC(info.szDevice, NULL, NULL, NULL)) { + if (const HDC hdc = CreateDC(info.szDevice, nullptr, nullptr, nullptr)) { const QDpi dpi = monitorDPI(hMonitor); data->dpi = dpi.first ? dpi : deviceDPI(hdc); data->depth = GetDeviceCaps(hdc, BITSPIXEL); @@ -137,7 +137,7 @@ BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM static inline WindowsScreenDataList monitorData() { WindowsScreenDataList result; - EnumDisplayMonitors(0, 0, monitorEnumCallback, reinterpret_cast(&result)); + EnumDisplayMonitors(nullptr, nullptr, monitorEnumCallback, reinterpret_cast(&result)); return result; } @@ -209,7 +209,7 @@ QPixmap QWindowsScreen::grabWindow(WId window, int xIn, int yIn, int width, int height = windowSize.height() - yIn; // Create and setup bitmap - HDC display_dc = GetDC(0); + HDC display_dc = GetDC(nullptr); HDC bitmap_dc = CreateCompatibleDC(display_dc); HBITMAP bitmap = CreateCompatibleBitmap(display_dc, width, height); HGDIOBJ null_bitmap = SelectObject(bitmap_dc, bitmap); @@ -226,7 +226,7 @@ QPixmap QWindowsScreen::grabWindow(WId window, int xIn, int yIn, int width, int const QPixmap pixmap = qt_pixmapFromWinHBITMAP(bitmap); DeleteObject(bitmap); - ReleaseDC(0, display_dc); + ReleaseDC(nullptr, display_dc); return pixmap; } @@ -237,7 +237,7 @@ QPixmap QWindowsScreen::grabWindow(WId window, int xIn, int yIn, int width, int QWindow *QWindowsScreen::topLevelAt(const QPoint &point) const { - QWindow *result = 0; + QWindow *result = nullptr; if (QWindow *child = QWindowsScreen::windowAt(point, CWP_SKIPINVISIBLE)) result = QWindowsWindow::topLevelOf(child); qCDebug(lcQpaWindows) <<__FUNCTION__ << point << result; @@ -246,7 +246,7 @@ QWindow *QWindowsScreen::topLevelAt(const QPoint &point) const QWindow *QWindowsScreen::windowAt(const QPoint &screenPoint, unsigned flags) { - QWindow* result = 0; + QWindow* result = nullptr; if (QPlatformWindow *bw = QWindowsContext::instance()-> findPlatformWindowAt(GetDesktopWindow(), screenPoint, flags)) result = bw->window(); @@ -576,7 +576,7 @@ const QWindowsScreen *QWindowsScreenManager::screenAtDp(const QPoint &p) const const QWindowsScreen *QWindowsScreenManager::screenForHwnd(HWND hwnd) const { HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL); - if (hMonitor == NULL) + if (hMonitor == nullptr) return nullptr; const auto it = std::find_if(m_screens.cbegin(), m_screens.cend(), diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp index b6ed27464e..9504513a5e 100644 --- a/src/plugins/platforms/windows/qwindowsservices.cpp +++ b/src/plugins/platforms/windows/qwindowsservices.cpp @@ -58,9 +58,9 @@ static inline bool shellExecute(const QUrl &url) ? QDir::toNativeSeparators(url.toLocalFile()) : url.toString(QUrl::FullyEncoded); const quintptr result = - reinterpret_cast(ShellExecute(0, 0, + reinterpret_cast(ShellExecute(nullptr, nullptr, reinterpret_cast(nativeFilePath.utf16()), - 0, 0, SW_SHOWNORMAL)); + nullptr, nullptr, SW_SHOWNORMAL)); // ShellExecute returns a value greater than 32 if successful if (result <= 32) { qWarning("ShellExecute '%s' failed (error %s).", qPrintable(url.toString()), qPrintable(QString::number(result))); @@ -84,7 +84,7 @@ static inline QString mailCommand() QString keyName; if (!RegOpenKeyEx(HKEY_CURRENT_USER, mailUserKey, 0, KEY_READ, &handle)) { DWORD bufferSize = BufferSize; - if (!RegQueryValueEx(handle, L"Progid", 0, 0, reinterpret_cast(command), &bufferSize)) + if (!RegQueryValueEx(handle, L"Progid", nullptr, nullptr, reinterpret_cast(command), &bufferSize)) keyName = QString::fromWCharArray(command); RegCloseKey(handle); } @@ -95,7 +95,7 @@ static inline QString mailCommand() command[0] = 0; if (!RegOpenKeyExW(HKEY_CLASSES_ROOT, reinterpret_cast(keyName.utf16()), 0, KEY_READ, &handle)) { DWORD bufferSize = BufferSize; - RegQueryValueEx(handle, L"", 0, 0, reinterpret_cast(command), &bufferSize); + RegQueryValueEx(handle, L"", nullptr, nullptr, reinterpret_cast(command), &bufferSize); RegCloseKey(handle); } // QTBUG-57816: As of Windows 10, if there is no mail client installed, an entry like @@ -136,8 +136,8 @@ static inline bool launchMail(const QUrl &url) STARTUPINFO si; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); - if (!CreateProcess(NULL, reinterpret_cast(const_cast(command.utf16())), - NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { + if (!CreateProcess(nullptr, reinterpret_cast(const_cast(command.utf16())), + nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) { qErrnoWarning("Unable to launch '%s'", qPrintable(command)); return false; } diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp index b738007f0e..c0f4e4d014 100644 --- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp +++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp @@ -160,7 +160,7 @@ static inline HWND createTrayIconMessageWindow() { QWindowsContext *ctx = QWindowsContext::instance(); if (!ctx) - return 0; + return nullptr; // Register window class in the platform plugin. const QString className = ctx->registerWindowClass(QStringLiteral("QTrayIconMessageWindowClass"), @@ -170,7 +170,8 @@ static inline HWND createTrayIconMessageWindow() windowName, WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - NULL, NULL, (HINSTANCE)GetModuleHandle(0), NULL); + nullptr, nullptr, + static_cast(GetModuleHandle(nullptr)), nullptr); } /*! diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 4b70e915a8..6dd3e6ed56 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -159,7 +159,7 @@ public: void run() override { - m_init = CoInitializeEx(NULL, COINIT_MULTITHREADED); + m_init = CoInitializeEx(nullptr, COINIT_MULTITHREADED); QMutexLocker readyLocker(&m_readyMutex); while (!m_cancelled.load()) { @@ -381,7 +381,7 @@ static inline QPalette menuPalette(const QPalette &systemPalette) static inline QPalette *menuBarPalette(const QPalette &menuPalette) { - QPalette *result = 0; + QPalette *result = nullptr; if (booleanSystemParametersInfo(SPI_GETFLATMENU, false)) { result = new QPalette(menuPalette); const QColor menubar(getSysColor(COLOR_MENUBAR)); @@ -393,13 +393,13 @@ static inline QPalette *menuBarPalette(const QPalette &menuPalette) } const char *QWindowsTheme::name = "windows"; -QWindowsTheme *QWindowsTheme::m_instance = 0; +QWindowsTheme *QWindowsTheme::m_instance = nullptr; QWindowsTheme::QWindowsTheme() { m_instance = this; - std::fill(m_fonts, m_fonts + NFonts, static_cast(0)); - std::fill(m_palettes, m_palettes + NPalettes, static_cast(0)); + std::fill(m_fonts, m_fonts + NFonts, nullptr); + std::fill(m_palettes, m_palettes + NPalettes, nullptr); refresh(); refreshIconPixmapSizes(); } @@ -408,7 +408,7 @@ QWindowsTheme::~QWindowsTheme() { clearPalettes(); clearFonts(); - m_instance = 0; + m_instance = nullptr; } static inline QStringList iconThemeSearchPaths() @@ -481,7 +481,7 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const void QWindowsTheme::clearPalettes() { qDeleteAll(m_palettes, m_palettes + NPalettes); - std::fill(m_palettes, m_palettes + NPalettes, static_cast(0)); + std::fill(m_palettes, m_palettes + NPalettes, nullptr); } void QWindowsTheme::refreshPalettes() @@ -498,7 +498,7 @@ void QWindowsTheme::refreshPalettes() void QWindowsTheme::clearFonts() { qDeleteAll(m_fonts, m_fonts + NFonts); - std::fill(m_fonts, m_fonts + NFonts, static_cast(0)); + std::fill(m_fonts, m_fonts + NFonts, nullptr); } void QWindowsTheme::refreshFonts() @@ -606,7 +606,7 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSiz int resourceId = -1; SHSTOCKICONID stockId = SIID_INVALID; UINT stockFlags = 0; - LPCTSTR iconName = 0; + LPCTSTR iconName = nullptr; switch (sp) { case DriveCDIcon: stockId = SIID_DRIVECD; @@ -716,7 +716,7 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSiz } if (iconName) { - HICON iconHandle = LoadIcon(NULL, iconName); + HICON iconHandle = LoadIcon(nullptr, iconName); QPixmap pixmap = qt_pixmapFromWinHICON(iconHandle); DestroyIcon(iconHandle); if (!pixmap.isNull()) @@ -776,7 +776,7 @@ static QPixmap pixmapFromShellImageList(int iImageList, const SHFILEINFO &info) // For MinGW: static const IID iID_IImageList = {0x46eb5926, 0x582e, 0x4017, {0x9f, 0xdf, 0xe8, 0x99, 0x8d, 0xaa, 0x9, 0x50}}; - IImageList *imageList = 0; + IImageList *imageList = nullptr; HRESULT hr = SHGetImageList(iImageList, iID_IImageList, reinterpret_cast(&imageList)); if (hr != S_OK) return result; @@ -832,7 +832,7 @@ QPixmap QWindowsFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon { /* We don't use the variable, but by storing it statically, we * ensure CoInitialize is only called once. */ - static HRESULT comInit = CoInitialize(NULL); + static HRESULT comInit = CoInitialize(nullptr); Q_UNUSED(comInit); static QCache > dirIconEntryCache(1000); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 54a4f237ff..c5d57be2ad 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -347,7 +347,7 @@ static bool applyBlurBehindWindow(HWND hwnd) if (DwmIsCompositionEnabled(&compositionEnabled) != S_OK) return false; - DWM_BLURBEHIND blurBehind = {0, 0, 0, 0}; + DWM_BLURBEHIND blurBehind = {0, 0, nullptr, 0}; if (compositionEnabled) { blurBehind.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; @@ -403,12 +403,12 @@ static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, bo if (hasAlpha && !accelerated && (flags & Qt::FramelessWindowHint)) { // Non-GL windows with alpha: Use blend function to update. BLENDFUNCTION blend = {AC_SRC_OVER, 0, alpha, AC_SRC_ALPHA}; - UpdateLayeredWindow(hwnd, NULL, NULL, NULL, NULL, NULL, 0, &blend, ULW_ALPHA); + UpdateLayeredWindow(hwnd, nullptr, nullptr, nullptr, nullptr, nullptr, 0, &blend, ULW_ALPHA); } else { SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA); } } else if (IsWindowVisible(hwnd)) { // Repaint when switching from layered. - InvalidateRect(hwnd, NULL, TRUE); + InvalidateRect(hwnd, nullptr, TRUE); } } @@ -764,7 +764,7 @@ QWindowsWindowData style, pos.x(), pos.y(), context->frameWidth, context->frameHeight, - parentHandle, NULL, appinst, NULL); + parentHandle, nullptr, appinst, nullptr); qCDebug(lcQpaWindows).nospace() << "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: " << context->obtainedGeometry << ' ' << context->margins; @@ -898,7 +898,7 @@ bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, co ncp->rgrc[0].top += customMargins.top(); ncp->rgrc[0].right -= customMargins.right(); ncp->rgrc[0].bottom -= customMargins.bottom(); - result = 0; + result = nullptr; qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << oldClientArea << '+' << customMargins << "-->" << ncp->rgrc[0] << ' ' << ncp->rgrc[1] << ' ' << ncp->rgrc[2] << ' ' << ncp->lppos->cx << ',' << ncp->lppos->cy; @@ -973,7 +973,7 @@ QWindowsBaseWindow *QWindowsBaseWindow::baseWindowOf(const QWindow *w) HWND QWindowsBaseWindow::handleOf(const QWindow *w) { const QWindowsBaseWindow *bw = QWindowsBaseWindow::baseWindowOf(w); - return bw ? bw->handle() : HWND(0); + return bw ? bw->handle() : HWND(nullptr); } bool QWindowsBaseWindow::isTopLevel_sys() const @@ -999,7 +999,7 @@ QMargins QWindowsBaseWindow::frameMargins_sys() const void QWindowsBaseWindow::hide_sys() // Normal hide, do not activate other windows. { - SetWindowPos(handle(),0 , 0, 0, 0, 0, + SetWindowPos(handle(), nullptr , 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); } @@ -1068,7 +1068,7 @@ QWindowsForeignWindow::QWindowsForeignWindow(QWindow *window, HWND hwnd) void QWindowsForeignWindow::setParent(const QPlatformWindow *newParentWindow) { const bool wasTopLevel = isTopLevel_sys(); - const HWND newParent = newParentWindow ? reinterpret_cast(newParentWindow->winId()) : HWND(0); + const HWND newParent = newParentWindow ? reinterpret_cast(newParentWindow->winId()) : HWND(nullptr); const bool isTopLevel = !newParent; const DWORD oldStyle = style(); qCDebug(lcQpaWindows) << __FUNCTION__ << window() << "newParent=" @@ -1299,7 +1299,7 @@ void QWindowsWindow::destroyWindow() #endif DestroyWindow(m_data.hwnd); context->removeWindow(m_data.hwnd); - m_data.hwnd = 0; + m_data.hwnd = nullptr; } } @@ -1348,7 +1348,7 @@ void QWindowsWindow::setDropSiteEnabled(bool dropEnabled) CoLockObjectExternal(m_dropTarget, false, true); m_dropTarget->Release(); RevokeDragDrop(m_data.hwnd); - m_dropTarget = 0; + m_dropTarget = nullptr; } #endif // QT_CONFIG(clipboard) && QT_CONFIG(draganddrop) } @@ -1491,7 +1491,7 @@ void QWindowsWindow::updateTransientParent() const return; // QTBUG-34503, // a popup stays on top, no parent, see also WindowCreationData::fromWindow(). // Update transient parent. const HWND oldTransientParent = GetWindow(m_data.hwnd, GW_OWNER); - HWND newTransientParent = 0; + HWND newTransientParent = nullptr; if (const QWindow *tp = window()->transientParent()) if (const QWindowsWindow *tw = QWindowsWindow::windowsWindowOf(tp)) if (!tw->testFlag(WithinDestroy)) // Prevent destruction by parent window (QTBUG-35499, QTBUG-36666) @@ -1584,7 +1584,7 @@ void QWindowsWindow::show_sys() const if (fakedMaximize) { setStyle(style() & ~WS_MAXIMIZEBOX); - SetWindowPos(m_data.hwnd, 0, 0, 0, 0, 0, + SetWindowPos(m_data.hwnd, nullptr, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); } @@ -1604,7 +1604,7 @@ void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) { // Use GetAncestor instead of GetParent, as GetParent can return owner window for toplevels HWND oldParentHWND = parentHwnd(); - HWND newParentHWND = 0; + HWND newParentHWND = nullptr; if (parent) { const QWindowsWindow *parentW = static_cast(parent); newParentHWND = parentW->handle(); @@ -1614,13 +1614,13 @@ void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) // NULL handle means desktop window, which also has its proper handle -> disambiguate HWND desktopHwnd = GetDesktopWindow(); if (oldParentHWND == desktopHwnd) - oldParentHWND = 0; + oldParentHWND = nullptr; if (newParentHWND == desktopHwnd) - newParentHWND = 0; + newParentHWND = nullptr; if (newParentHWND != oldParentHWND) { - const bool wasTopLevel = oldParentHWND == 0; - const bool isTopLevel = newParentHWND == 0; + const bool wasTopLevel = oldParentHWND == nullptr; + const bool isTopLevel = newParentHWND == nullptr; setFlag(WithinSetParent); SetParent(m_data.hwnd, newParentHWND); @@ -1847,7 +1847,7 @@ void QWindowsWindow::releaseDC() { if (m_hdc) { ReleaseDC(handle(), m_hdc); - m_hdc = 0; + m_hdc = nullptr; } } @@ -1881,7 +1881,7 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message, // GL software rendering (QTBUG-58178) and Windows 7/Aero off with some AMD cards // (QTBUG-60527) need InvalidateRect() to suppress artifacts while resizing. if (testFlag(OpenGLSurface) && (isSoftwareGl() || !dwmIsCompositionEnabled())) - InvalidateRect(hwnd, 0, false); + InvalidateRect(hwnd, nullptr, false); BeginPaint(hwnd, &ps); @@ -1889,7 +1889,7 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message, if (Q_UNLIKELY(!dwmIsCompositionEnabled()) && ((testFlag(OpenGLSurface) && testFlag(OpenGLDoubleBuffered)) || testFlag(VulkanSurface))) { - SelectClipRgn(ps.hdc, NULL); + SelectClipRgn(ps.hdc, nullptr); } // If the a window is obscured by another window (such as a child window) @@ -2100,7 +2100,7 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowStates newState) // it before applying the normal geometry. if (windowVisibility_sys(m_data.hwnd) == QWindow::Maximized) ShowWindow(m_data.hwnd, SW_SHOWNOACTIVATE); - SetWindowPos(m_data.hwnd, 0, m_savedFrameGeometry.x(), m_savedFrameGeometry.y(), + SetWindowPos(m_data.hwnd, nullptr, m_savedFrameGeometry.x(), m_savedFrameGeometry.y(), m_savedFrameGeometry.width(), m_savedFrameGeometry.height(), swpf); if (!wasSync) clearFlag(SynchronousGeometryChangeEvent); @@ -2286,7 +2286,7 @@ static HRGN qRegionToWinRegion(const QRegion ®ion) void QWindowsWindow::setMask(const QRegion ®ion) { if (region.isEmpty()) { - SetWindowRgn(m_data.hwnd, 0, true); + SetWindowRgn(m_data.hwnd, nullptr, true); return; } const HRGN winRegion = qRegionToWinRegion(region); @@ -2319,7 +2319,7 @@ void QWindowsWindow::requestActivateWindow() if (QGuiApplication::applicationState() != Qt::ApplicationActive && QWindowsNativeInterface::windowActivationBehavior() == QWindowsWindowFunctions::AlwaysActivateWindow) { if (const HWND foregroundWindow = GetForegroundWindow()) { - foregroundThread = GetWindowThreadProcessId(foregroundWindow, NULL); + foregroundThread = GetWindowThreadProcessId(foregroundWindow, nullptr); if (foregroundThread && foregroundThread != currentThread) attached = AttachThreadInput(foregroundThread, currentThread, TRUE) == TRUE; if (attached) { @@ -2353,7 +2353,7 @@ bool QWindowsWindow::setKeyboardGrabEnabled(bool grab) context->setKeyGrabber(window()); } else { if (context->keyGrabber() == window()) - context->setKeyGrabber(0); + context->setKeyGrabber(nullptr); } return true; } @@ -2653,7 +2653,7 @@ static HICON createHIcon(const QIcon &icon, int xSize, int ySize) if (!pm.isNull()) return qt_pixmapToWinHICON(pm); } - return 0; + return nullptr; } void QWindowsWindow::setWindowIcon(const QIcon &icon) @@ -2711,7 +2711,7 @@ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins) newFrame.moveTo(topLeft); qCDebug(lcQpaWindows) << __FUNCTION__ << oldCustomMargins << "->" << newCustomMargins << currentFrameGeometry << "->" << newFrame; - SetWindowPos(m_data.hwnd, 0, newFrame.x(), newFrame.y(), newFrame.width(), newFrame.height(), SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE); + SetWindowPos(m_data.hwnd, nullptr, newFrame.x(), newFrame.y(), newFrame.width(), newFrame.height(), SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE); } } diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp index fbb5c3b9ec..7980826b49 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp @@ -90,7 +90,7 @@ HWND hwndForAccessible(const QAccessibleInterface *accessible) return QWindowsBaseWindow::handleOf(window); } } - return NULL; + return nullptr; } void clearVariant(VARIANT *variant) -- cgit v1.2.3 From cf53ed97a113751f3130543e3a1e853d45817dd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 28 Jan 2019 15:18:48 +0100 Subject: macOS: Apply alpha channel to surface format even when non-default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Relying on QSurfaceFormat() to check whether or not we should set the alpha channel size makes it impossible to tweak other properties of the surface format without also having to set the alpha. There's no need to do such as broad comparison, we can check the alpha channel size for its default value instead. Change-Id: Iac31d37c9460eb3e7ec5ee15902f7e5addb48178 Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qcocoawindow.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index df1ad82592..b0f0d51ecb 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -227,8 +227,9 @@ QSurfaceFormat QCocoaWindow::format() const // Upgrade the default surface format to include an alpha channel. The default RGB format // causes Cocoa to spend an unreasonable amount of time converting it to RGBA internally. - if (format == QSurfaceFormat()) + if (format.alphaBufferSize() < 0) format.setAlphaBufferSize(8); + return format; } -- cgit v1.2.3 From 64e8e69d25e08ad81cdb5fb8c2897bc3c0283c9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Fri, 11 Jan 2019 06:57:48 +0100 Subject: =?UTF-8?q?Cocoa:=20Don=E2=80=99t=20cache=20accessibility=20role?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The object role may in some cases (e.g. when using Qt Quick Loaders) be changed after construction, and we don’t have RoleChanged events. Change-Id: Idb246c1c1206221cacd93c83cbd07a0e3d98cb0e Fixes: QTBUG-72967 Reviewed-by: Frederik Gladhorn Reviewed-by: Jan Arve Sæther --- src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index a1176da33f..f26263261c 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -100,7 +100,6 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of } @implementation QMacAccessibilityElement { - NSString *role; QAccessible::Id axid; } @@ -110,9 +109,6 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of self = [super init]; if (self) { axid = anId; - QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); - Q_ASSERT(iface); - role = QCocoaAccessible::macRole(iface); } return self; @@ -276,11 +272,12 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of } if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) { - return role; + return QCocoaAccessible::macRole(iface); } else if ([attribute isEqualToString:NSAccessibilitySubroleAttribute]) { return QCocoaAccessible::macSubrole(iface); } else if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) { - return NSAccessibilityRoleDescription(role, [self accessibilityAttributeValue:NSAccessibilitySubroleAttribute]); + return NSAccessibilityRoleDescription(QCocoaAccessible::macRole(iface), + [self accessibilityAttributeValue:NSAccessibilitySubroleAttribute]); } else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { return QCocoaAccessible::unignoredChildren(iface); } else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { -- cgit v1.2.3 From a4767bb9e022b97cdf3a1750dd58f87e7d17ef79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Sun, 21 Oct 2018 22:13:34 +0200 Subject: Wasm: remove debug output. Change-Id: Ieb9c06203626854f9b7c561563c3261510230803 Reviewed-by: Lorn Potter --- src/plugins/platforms/wasm/qwasmwindow.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp index c4167be71e..25a0190053 100644 --- a/src/plugins/platforms/wasm/qwasmwindow.cpp +++ b/src/plugins/platforms/wasm/qwasmwindow.cpp @@ -53,7 +53,6 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingSt m_needsCompositor = w->surfaceType() != QSurface::OpenGLSurface; static int serialNo = 0; m_winid = ++serialNo; - qWarning("QWasmWindow %p: %p 0x%x\n", this, w, uint(m_winid)); m_compositor->addWindow(this); -- cgit v1.2.3 From 744be250bf8dbd3e5065662f55a4655c14aa512c Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 28 Jan 2019 10:25:55 +0100 Subject: Fix building offscreen QPA with Qt XCB Only builds without XCB or with system XCB Change-Id: I1161c5b78c92308ac63c2e2907b9a5d8477ab2f0 Reviewed-by: Gatis Paeglis --- src/plugins/platforms/offscreen/offscreen.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/offscreen/offscreen.pro b/src/plugins/platforms/offscreen/offscreen.pro index 6652cefd86..392ee8bed1 100644 --- a/src/plugins/platforms/offscreen/offscreen.pro +++ b/src/plugins/platforms/offscreen/offscreen.pro @@ -17,7 +17,7 @@ HEADERS = qoffscreenintegration.h \ OTHER_FILES += offscreen.json -qtConfig(xlib):qtConfig(opengl):!qtConfig(opengles2) { +qtConfig(system-xcb):qtConfig(xlib):qtConfig(opengl):!qtConfig(opengles2) { SOURCES += qoffscreenintegration_x11.cpp HEADERS += qoffscreenintegration_x11.h QT += glx_support-private -- cgit v1.2.3 From 8915904e2a56d46bdedf64f9a7a5e331ae9d00e1 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Fri, 25 Jan 2019 12:10:34 +0100 Subject: QMacStyle - fix a weird NSBox geometry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For some reason, displayRectIgnoringOpacity renders NSBox with a smaller height than we asked. So let's ask for more and translate. Change-Id: I6e03ad99d1ccf746c89d58dd37d53d0087f15282 Fixes: QTBUG-71741 Reviewed-by: Tor Arne Vestbø --- src/plugins/styles/mac/qmacstyle_mac.mm | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 50a657e774..13ef98b840 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -2996,7 +2996,20 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai // inContext:, but only in light mode. In dark mode, we use a custom NSBox subclass, // QDarkNSBox, of type NSBoxCustom. Its appearance is close enough to the real thing so // we can use this for now. - d->drawNSViewInRect(box, opt->rect, p, ^(CGContextRef ctx, const CGRect &rect) { + auto adjustedRect = opt->rect; + bool needTranslation = false; + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave + && !qt_mac_applicationIsInDarkMode()) { + // Another surprise from AppKit (SDK 10.14) - -displayRectIgnoringOpacity: + // is different from drawRect: for some Apple-known reason box is smaller + // in height than we need, resulting in tab buttons sitting too high/not + // centered. Attempts to play with insets etc did not work - the same wrong + // height. Simple translation is not working (too much space "at bottom"), + // so we make it bigger and translate (otherwise it's clipped at bottom btw). + adjustedRect.adjust(0, 0, 0, 3); + needTranslation = true; + } + d->drawNSViewInRect(box, adjustedRect, p, ^(CGContextRef ctx, const CGRect &rect) { if (QTabWidget *tabWidget = qobject_cast(opt->styleObject)) clipTabBarFrame(opt, this, ctx); CGContextTranslateCTM(ctx, 0, rect.origin.y + rect.size.height); @@ -3005,6 +3018,8 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai || [box isMemberOfClass:QDarkNSBox.class]) { [box drawRect:rect]; } else { + if (needTranslation) + CGContextTranslateCTM(ctx, 0.0, 4.0); [box displayRectIgnoringOpacity:box.bounds inContext:NSGraphicsContext.currentContext]; } }); -- cgit v1.2.3 From daee9af969a04a2919a948ba1f5d314626925a9a Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Fri, 25 Jan 2019 21:15:43 +0100 Subject: QtGui: mark obsolete QPixmapCache::find() functions as deprecated QPixmapCache::find(QString) and QPixmapCache::find(QString, QPixmap&) are deprecated since Qt4 times. Explicit mark them as deprecated so they can be removed with Qt6. Change-Id: Iaf185f69afe02203559a1c812fbb4a95c9049a1d Reviewed-by: Eirik Aavitsland --- src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp index a3e6cedecd..2688d6e884 100644 --- a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp +++ b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp @@ -458,7 +458,7 @@ static QPixmap qt_patternForAlpha(uchar alpha, int screen) % HexString(alpha) % HexString(screen); - if (!QPixmapCache::find(key, pm)) { + if (!QPixmapCache::find(key, &pm)) { // #### why not use a mono image here???? QImage pattern(DITHER_SIZE, DITHER_SIZE, QImage::Format_ARGB32); pattern.fill(0xffffffff); -- cgit v1.2.3 From 850c922036b7eebc24cdb74a43a4b31319d924c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 30 Jan 2019 18:03:00 +0100 Subject: macOS: Don't deliver update requests for windows that need display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a window needs display due to e.g. being resized, we need to wait until the corresponding expose event has been delivered before we resume update requests, otherwise the update requests may result in partial paints that do not fully cover the area needing display. Change-Id: Ibfb54bfe3c2e85b606ef67d34a6a5fdb85456edd Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qcocoawindow.mm | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index b0f0d51ecb..a1bed3db45 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1487,6 +1487,17 @@ void QCocoaWindow::requestUpdate() void QCocoaWindow::deliverUpdateRequest() { + // Don't send update requests for views that need display, as the update + // request doesn't carry any information about dirty rects, so the app + // may end up painting a smaller region than required. (For some reason + // the layer and view's needsDisplay status isn't always in sync, even if + // the view is layer-backed, not layer-hosted, so we check both). + if (m_view.layer.needsDisplay || m_view.needsDisplay) { + qCDebug(lcQpaDrawing) << "View needs display, deferring update request for" << window(); + requestUpdate(); + return; + } + qCDebug(lcQpaDrawing) << "Delivering update request to" << window(); QPlatformWindow::deliverUpdateRequest(); } -- cgit v1.2.3 From 05bcfb901115eb92820478746cae359d4dc84fbf Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 30 Jan 2019 17:18:04 +0100 Subject: Normalize some SIGNAL/SLOT signatures ...for a minor performance gain. Change-Id: I4bef867055e069926fdc24fa98a6f94b6a0630e2 Reviewed-by: Oliver Wolff --- src/plugins/bearer/connman/qconnmanservice_linux.cpp | 2 +- src/plugins/bearer/linux_common/qofonoservice_linux.cpp | 2 +- src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/bearer/connman/qconnmanservice_linux.cpp b/src/plugins/bearer/connman/qconnmanservice_linux.cpp index 7c9db4640b..3659eb7740 100644 --- a/src/plugins/bearer/connman/qconnmanservice_linux.cpp +++ b/src/plugins/bearer/connman/qconnmanservice_linux.cpp @@ -171,7 +171,7 @@ void QConnmanManagerInterface::connectNotify(const QMetaMethod &signal) QLatin1String(CONNMAN_MANAGER_PATH), QLatin1String(CONNMAN_MANAGER_INTERFACE), QLatin1String("ServicesChanged"), - this,SLOT(onServicesChanged(ConnmanMapList, QList)))) { + this,SLOT(onServicesChanged(ConnmanMapList,QList)))) { qWarning("servicesChanged not connected"); } } diff --git a/src/plugins/bearer/linux_common/qofonoservice_linux.cpp b/src/plugins/bearer/linux_common/qofonoservice_linux.cpp index 897ee953c0..5d72731bc4 100644 --- a/src/plugins/bearer/linux_common/qofonoservice_linux.cpp +++ b/src/plugins/bearer/linux_common/qofonoservice_linux.cpp @@ -84,7 +84,7 @@ QOfonoManagerInterface::QOfonoManagerInterface( QObject *parent) QLatin1String(OFONO_MANAGER_PATH), QLatin1String(OFONO_MANAGER_INTERFACE), QLatin1String("ModemAdded"), - this,SLOT(modemAdded(QDBusObjectPath, QVariantMap))); + this,SLOT(modemAdded(QDBusObjectPath,QVariantMap))); QDBusConnection::systemBus().connect(QLatin1String(OFONO_SERVICE), QLatin1String(OFONO_MANAGER_PATH), QLatin1String(OFONO_MANAGER_INTERFACE), diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp index 3a54f33832..ca315840e2 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp @@ -593,7 +593,7 @@ void QIBusPlatformInputContext::connectToContextSignals() if (d->context) { connect(d->context, SIGNAL(CommitText(QDBusVariant)), SLOT(commitText(QDBusVariant))); connect(d->context, SIGNAL(UpdatePreeditText(QDBusVariant,uint,bool)), this, SLOT(updatePreeditText(QDBusVariant,uint,bool))); - connect(d->context, SIGNAL(ForwardKeyEvent(uint, uint, uint)), this, SLOT(forwardKeyEvent(uint, uint, uint))); + connect(d->context, SIGNAL(ForwardKeyEvent(uint,uint,uint)), this, SLOT(forwardKeyEvent(uint,uint,uint))); connect(d->context, SIGNAL(DeleteSurroundingText(int,uint)), this, SLOT(deleteSurroundingText(int,uint))); connect(d->context, SIGNAL(RequireSurroundingText()), this, SLOT(surroundingTextRequired())); connect(d->context, SIGNAL(HidePreeditText()), this, SLOT(hidePreeditText())); -- cgit v1.2.3 From b319d141105044f612ada1efe62685b2c5dd4514 Mon Sep 17 00:00:00 2001 From: Boubacar DIENE Date: Thu, 31 Jan 2019 00:12:16 +0100 Subject: Fix "error: too many arguments to function media_get_entity_by_name()" Since the official v4l-utils-1.12.0 release, media_get_entity_by_name() function expects only two arguments instead of three as in older versions thus breaking build of eglfs_kms_vsp2 backend. Cf. https://git.linuxtv.org/v4l-utils.git/tree/utils/media-ctl/mediactl.h#n253 Fixes it by creating an overloaded wrapper function that will choose the right version based on the signature of the media_get_entity_by_name function pointer argument. Fixes: QTBUG-73427 Change-Id: Idab52558b6f2f23137456c21e33ece1ef0e9aa4e Reviewed-by: Johan Helsing --- .../eglfs_kms_vsp2/qlinuxmediadevice.cpp | 25 ++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.cpp index 25b0c39050..f77430d7a0 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.cpp @@ -273,9 +273,30 @@ bool QLinuxMediaDevice::disableLink(struct media_link *link) return true; } -media_entity *QLinuxMediaDevice::getEntity(const QString &name) +// Between the v4l-utils 1.10 and 1.12 releases, media_get_entity_by_name changed signature, +// i.e. breaking source compatibility. Unfortunately the v4l-utils version is not exposed +// through anything we can use through a regular ifdef so here we do a hack and create two +// overloads for a function based on the signature of the function pointer argument. This +// means that by calling safeGetEntity with media_get_entity_by_name as an argument, the +// compiler will pick the correct version. +// +// v4l-utils v1.12 and later +static struct media_entity *safeGetEntity(struct media_entity *(get_entity_by_name_fn)(struct media_device *, const char *), + struct media_device *device, const QString &name) { - struct media_entity *entity = media_get_entity_by_name(m_mediaDevice, name.toStdString().c_str(), name.length()); + return get_entity_by_name_fn(device, name.toStdString().c_str()); +} +// v4l-utils v1.10 and earlier +static struct media_entity *safeGetEntity(struct media_entity *(get_entity_by_name_fn)(struct media_device *, const char *, size_t), + struct media_device *device, + const QString &name) +{ + return get_entity_by_name_fn(device, name.toStdString().c_str(), name.length()); +} + +struct media_entity *QLinuxMediaDevice::getEntity(const QString &name) +{ + struct media_entity *entity = safeGetEntity(media_get_entity_by_name, m_mediaDevice, name); if (!entity) qWarning() << "Failed to get media entity:" << name; -- cgit v1.2.3 From 8a7c373f8e745427d5fe7afc08d698837b7b8f2b Mon Sep 17 00:00:00 2001 From: Karim Pinter Date: Tue, 29 Jan 2019 16:05:06 +0200 Subject: QNX QPA: Add support for Qt Virtual Keyboard If the QT_IM_MODULE environment variable is set, then it loads the IM module accordingly, otherwise it is using the PPS one, if it is available. Task-number: QTBUG-54576 Change-Id: Icb8b474805053d8297029096365783c2cabc2cbc Reviewed-by: Samuli Piippo Reviewed-by: James McDonnell --- src/plugins/platforms/qnx/qqnxintegration.cpp | 23 ++++++++++++++++------- src/plugins/platforms/qnx/qqnxintegration.h | 1 + 2 files changed, 17 insertions(+), 7 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp index db79780407..a996e765c4 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.cpp +++ b/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -72,6 +72,9 @@ # endif #endif +#include +#include + #include "private/qgenericunixfontdatabase_p.h" #include "private/qgenericunixeventdispatcher_p.h" @@ -152,6 +155,7 @@ QQnxIntegration::QQnxIntegration(const QStringList ¶mList) , m_inputContext(0) , m_buttonsNotifier(new QQnxButtonEventNotifier()) #endif + , m_qpaInputContext(0) , m_services(0) , m_fontDatabase(new QGenericUnixFontDatabase()) , m_eventDispatcher(createUnixEventDispatcher()) @@ -194,13 +198,17 @@ QQnxIntegration::QQnxIntegration(const QStringList ¶mList) m_screenEventHandler->setScreenEventThread(m_screenEventThread); m_screenEventThread->start(); + m_qpaInputContext = QPlatformInputContextFactory::create(); + #if QT_CONFIG(qqnx_pps) - // Create/start the keyboard class. - m_virtualKeyboard = new QQnxVirtualKeyboardPps(); + if (!m_qpaInputContext) { + // Create/start the keyboard class. + m_virtualKeyboard = new QQnxVirtualKeyboardPps(); - // delay invocation of start() to the time the event loop is up and running - // needed to have the QThread internals of the main thread properly initialized - QMetaObject::invokeMethod(m_virtualKeyboard, "start", Qt::QueuedConnection); + // delay invocation of start() to the time the event loop is up and running + // needed to have the QThread internals of the main thread properly initialized + QMetaObject::invokeMethod(m_virtualKeyboard, "start", Qt::QueuedConnection); + } #endif #if QT_CONFIG(qqnx_pps) @@ -281,6 +289,7 @@ QQnxIntegration::~QQnxIntegration() // Destroy input context delete m_inputContext; #endif + delete m_qpaInputContext; // Destroy the keyboard class. delete m_virtualKeyboard; @@ -397,13 +406,13 @@ QPlatformOpenGLContext *QQnxIntegration::createPlatformOpenGLContext(QOpenGLCont } #endif -#if QT_CONFIG(qqnx_pps) QPlatformInputContext *QQnxIntegration::inputContext() const { qIntegrationDebug(); + if (m_qpaInputContext) + return m_qpaInputContext; return m_inputContext; } -#endif void QQnxIntegration::moveToScreen(QWindow *window, int screen) { diff --git a/src/plugins/platforms/qnx/qqnxintegration.h b/src/plugins/platforms/qnx/qqnxintegration.h index 4a6f15fc08..366556dc4b 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.h +++ b/src/plugins/platforms/qnx/qqnxintegration.h @@ -153,6 +153,7 @@ private: QQnxInputContext *m_inputContext; QQnxButtonEventNotifier *m_buttonsNotifier; #endif + QPlatformInputContext *m_qpaInputContext; QQnxServices *m_services; QPlatformFontDatabase *m_fontDatabase; mutable QAbstractEventDispatcher *m_eventDispatcher; -- cgit v1.2.3 From c0ebec51e3dd1b52767878fe7fd56ce6e8f95461 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Wed, 16 Jan 2019 15:12:16 +0800 Subject: xcb: respect big-request encoding in max request size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From big-request specification: "This extension defines a mechanism for extending the length field beyond 16 bits. If the normal 16-bit length field of the protocol request is zero, then an additional 32-bit field containing the actual length (in 4-byte units) is inserted into the request, immediately following the 16-bit length field." Meaning that the request requires 4 additional bytes. This patch provides a convenience API for calculating maximum request data size. Besides fixing QTBUG-73044, it was also discovered that calculations for xcb_image_put (in QXcbBackingStoreImage::flushPixmap) were wrong. The code assumed that xcb_get_maximum_request_length() returns bytes, but what it actually returns is length which is measured in four-byte units. This means that we were sending 4x less bytes than allowed by the protocol. Furthermore, use the actual 'stride' (bytes per line) value when calculating rows_per_put. The new stride value was introduced by 760b2929a3b268e2edf14a561329bdb78fbdc26e, but was not updated in rows_per_put calculations. Fixes: QTBUG-73044 Done-with: JiDe Zhang Done-with: Mikhail Svetkin Change-Id: I06beb6082da3e8bc78225a87603914e796fe5878 Reviewed-by: Błażej Szczygieł Reviewed-by: JiDe Zhang Reviewed-by: Mikhail Svetkin Reviewed-by: Uli Schlachter Reviewed-by: Allan Sandfeld Jensen --- src/plugins/platforms/xcb/qxcbbackingstore.cpp | 17 ++++++++-------- src/plugins/platforms/xcb/qxcbclipboard.cpp | 23 ++++++++-------------- src/plugins/platforms/xcb/qxcbclipboard.h | 4 ++-- src/plugins/platforms/xcb/qxcbconnection.h | 2 +- src/plugins/platforms/xcb/qxcbconnection_basic.cpp | 14 +++++++++++++ src/plugins/platforms/xcb/qxcbconnection_basic.h | 5 +++++ 6 files changed, 39 insertions(+), 26 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index f9240a45cc..741317d766 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -641,17 +641,17 @@ void QXcbBackingStoreImage::flushPixmap(const QRegion ®ion, bool fullRegion) xcb_subimage.bit_order = m_xcb_image->bit_order; const bool needsByteSwap = xcb_subimage.byte_order != m_xcb_image->byte_order; + // Ensure that we don't send more than maxPutImageRequestDataBytes per request. + const auto maxPutImageRequestDataBytes = connection()->maxRequestDataBytes(sizeof(xcb_put_image_request_t)); for (const QRect &rect : region) { - // We must make sure that each request is not larger than max_req_size. - // Each request takes req_size + m_xcb_image->stride * height bytes. - static const uint32_t req_size = sizeof(xcb_put_image_request_t); - const uint32_t max_req_size = xcb_get_maximum_request_length(xcb_connection()); - const int rows_per_put = (max_req_size - req_size) / m_xcb_image->stride; + const quint32 stride = round_up_scanline(rect.width() * m_qimage.depth(), xcb_subimage.scanline_pad) >> 3; + const int rows_per_put = maxPutImageRequestDataBytes / stride; // This assert could trigger if a single row has more pixels than fit in - // a single PutImage request. However, max_req_size is guaranteed to be - // at least 16384 bytes. That should be enough for quite large images. + // a single PutImage request. In the absence of the BIG-REQUESTS extension + // the theoretical maximum lengths of maxPutImageRequestDataBytes can be + // roughly 256kB. Q_ASSERT(rows_per_put > 0); // If we upload the whole image in a single chunk, the result might be @@ -666,9 +666,10 @@ void QXcbBackingStoreImage::flushPixmap(const QRegion ®ion, bool fullRegion) while (height > 0) { const int rows = std::min(height, rows_per_put); const QRect subRect(x, y, width, rows); - const quint32 stride = round_up_scanline(width * m_qimage.depth(), xcb_subimage.scanline_pad) >> 3; const QImage subImage = native_sub_image(&m_flushBuffer, stride, m_qimage, subRect, needsByteSwap); + Q_ASSERT(static_cast(subImage.sizeInBytes()) <= maxPutImageRequestDataBytes); + xcb_subimage.width = width; xcb_subimage.height = rows; xcb_subimage.data = const_cast(subImage.constBits()); diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index ac8b029916..2cb6720d40 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -240,8 +240,8 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c) xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, atom(QXcbAtom::CLIPBOARD), mask); } - // change property protocol request is 24 bytes - m_increment = (xcb_get_maximum_request_length(xcb_connection()) * 4) - 24; + // xcb_change_property_request_t and xcb_get_property_request_t are the same size + m_maxPropertyRequestDataBytes = connection()->maxRequestDataBytes(sizeof(xcb_change_property_request_t)); } QXcbClipboard::~QXcbClipboard() @@ -486,7 +486,7 @@ xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_win if (m_clipboard_closing) allow_incr = false; - if (data.size() > m_increment && allow_incr) { + if (data.size() > m_maxPropertyRequestDataBytes && allow_incr) { long bytes = data.size(); xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property, atom(QXcbAtom::INCR), 32, 1, (const void *)&bytes); @@ -496,7 +496,7 @@ xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_win } // make sure we can perform the XChangeProperty in a single request - if (data.size() > m_increment) + if (data.size() > m_maxPropertyRequestDataBytes) return XCB_NONE; // ### perhaps use several XChangeProperty calls w/ PropModeAppend? int dataSize = data.size() / (dataFormat / 8); // use a single request to transfer data @@ -678,17 +678,8 @@ void QXcbClipboard::handleXFixesSelectionRequest(xcb_xfixes_selection_notify_eve emitChanged(mode); } - -static inline int maxSelectionIncr(xcb_connection_t *c) -{ - int l = xcb_get_maximum_request_length(c); - return (l > 65536 ? 65536*4 : l*4) - 100; -} - bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format) { - int maxsize = maxSelectionIncr(xcb_connection()); - ulong bytes_left; // bytes_after xcb_atom_t dummy_type; int dummy_format; @@ -705,7 +696,8 @@ bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property, } *type = reply->type; *format = reply->format; - bytes_left = reply->bytes_after; + + auto bytes_left = reply->bytes_after; int offset = 0, buffer_offset = 0; @@ -720,7 +712,8 @@ bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property, while (bytes_left) { // more to read... - reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(), false, win, property, XCB_GET_PROPERTY_TYPE_ANY, offset, maxsize/4); + reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(), false, win, property, + XCB_GET_PROPERTY_TYPE_ANY, offset, m_maxPropertyRequestDataBytes / 4); if (!reply || reply->type == XCB_NONE) break; diff --git a/src/plugins/platforms/xcb/qxcbclipboard.h b/src/plugins/platforms/xcb/qxcbclipboard.h index 26d3b3b395..51ae0dc1ee 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.h +++ b/src/plugins/platforms/xcb/qxcbclipboard.h @@ -113,7 +113,7 @@ public: xcb_window_t getSelectionOwner(xcb_atom_t atom) const; QByteArray getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t t = 0); - int increment() const { return m_increment; } + int increment() const { return m_maxPropertyRequestDataBytes; } int clipboardTimeout() const { return clipboard_timeout; } void removeTransaction(xcb_window_t window) { m_transactions.remove(window); } @@ -137,7 +137,7 @@ private: static const int clipboard_timeout; - int m_increment = 0; + int m_maxPropertyRequestDataBytes = 0; bool m_clipboard_closing = false; xcb_timestamp_t m_incr_receive_time = 0; diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index d63888b48f..0e3ecd135b 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -245,7 +245,7 @@ public: void flush() { xcb_flush(xcb_connection()); } void processXcbEvents(QEventLoop::ProcessEventsFlags flags); - QTimer &focusInTimer() { return m_focusInTimer; }; + QTimer &focusInTimer() { return m_focusInTimer; } protected: bool event(QEvent *e) override; diff --git a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp index af72285135..9a028e5a7e 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp @@ -134,6 +134,7 @@ QXcbBasicConnection::QXcbBasicConnection(const char *displayName) m_setup = xcb_get_setup(m_xcbConnection); m_xcbAtom.initialize(m_xcbConnection); + m_maximumRequestLength = xcb_get_maximum_request_length(m_xcbConnection); xcb_extension_t *extensions[] = { &xcb_shm_id, &xcb_xfixes_id, &xcb_randr_id, &xcb_shape_id, &xcb_sync_id, @@ -178,6 +179,14 @@ QXcbBasicConnection::~QXcbBasicConnection() } } +size_t QXcbBasicConnection::maxRequestDataBytes(size_t requestSize) const +{ + if (hasBigRequest()) + requestSize += 4; // big-request encoding adds 4 bytes + + return m_maximumRequestLength * 4 - requestSize; +} + xcb_atom_t QXcbBasicConnection::internAtom(const char *name) { if (!name || *name == 0) @@ -199,6 +208,11 @@ QByteArray QXcbBasicConnection::atomName(xcb_atom_t atom) return QByteArray(); } +bool QXcbBasicConnection::hasBigRequest() const +{ + return m_maximumRequestLength > m_setup->maximum_request_length; +} + #if QT_CONFIG(xcb_xinput) // Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed: // - "pad0" became "extension" diff --git a/src/plugins/platforms/xcb/qxcbconnection_basic.h b/src/plugins/platforms/xcb/qxcbconnection_basic.h index ca91f7fa45..3691763398 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_basic.h +++ b/src/plugins/platforms/xcb/qxcbconnection_basic.h @@ -73,6 +73,8 @@ public: } const xcb_setup_t *setup() const { return m_setup; } + size_t maxRequestDataBytes(size_t requestSize) const; + inline xcb_atom_t atom(QXcbAtom::Atom qatom) const { return m_xcbAtom.atom(qatom); } QXcbAtom::Atom qatom(xcb_atom_t atom) const { return m_xcbAtom.qatom(atom); } xcb_atom_t internAtom(const char *name); @@ -94,6 +96,7 @@ public: bool hasShmFd() const { return m_hasShmFd; } bool hasXSync() const { return m_hasXSync; } bool hasXinerama() const { return m_hasXinerama; } + bool hasBigRequest() const; #if QT_CONFIG(xcb_xinput) bool isAtLeastXI21() const { return m_xi2Enabled && m_xi2Minor >= 1; } @@ -152,6 +155,8 @@ private: uint32_t m_xfixesFirstEvent = 0; uint32_t m_xrandrFirstEvent = 0; uint32_t m_xkbFirstEvent = 0; + + uint32_t m_maximumRequestLength = 0; }; #define Q_XCB_REPLY_CONNECTION_ARG(connection, ...) connection -- cgit v1.2.3 From 27065bdc50fb3163f41d65ff70653aac8ca19094 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Wed, 23 Jan 2019 14:02:38 +0100 Subject: ibus: allow filterEvent() from QWindowSystemEventHandler::sendEvent() The async mode, which is also default mode will recurs if QIBusPlatformInputContext::filterEvent() is called from QWindowSystemEventHandler::sendEvent() callback. The sync mode works fine without this patch. Modes can be toggled via IBUS_ENABLE_SYNC_MODE envvar. Removed redundant #ifndef and renamed one variable to something more meaningful. Change-Id: I8773445cef10212464cff09e3a70487fb38ac3fd Reviewed-by: Takao Fujiwara Reviewed-by: Lars Knoll --- .../ibus/qibusplatforminputcontext.cpp | 31 +++++++++++----------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp index c0979e7864..98362f2116 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp @@ -47,7 +47,9 @@ #include #include -#include +#include + +#include #include "qibusproxy.h" #include "qibusproxyportal.h" @@ -419,9 +421,9 @@ bool QIBusPlatformInputContext::filterEvent(const QEvent *event) QDBusPendingReply reply = d->context->ProcessKeyEvent(sym, code - 8, ibusState); if (m_eventFilterUseSynchronousMode || reply.isFinished()) { - bool retval = reply.value(); - qCDebug(qtQpaInputMethods) << "filterEvent return" << code << sym << state << retval; - return retval; + bool filtered = reply.value(); + qCDebug(qtQpaInputMethods) << "filterEvent return" << code << sym << state << filtered; + return filtered; } Qt::KeyboardModifiers modifiers = keyEvent->modifiers(); @@ -491,23 +493,22 @@ void QIBusPlatformInputContext::filterEventFinished(QDBusPendingCallWatcher *cal const bool isAutoRepeat = args.at(7).toBool(); // copied from QXcbKeyboard::handleKeyEvent() - bool retval = reply.value(); - qCDebug(qtQpaInputMethods) << "filterEventFinished return" << code << sym << state << retval; - if (!retval) { + bool filtered = reply.value(); + qCDebug(qtQpaInputMethods) << "filterEventFinished return" << code << sym << state << filtered; + if (!filtered) { #ifndef QT_NO_CONTEXTMENU if (type == QEvent::KeyPress && qtcode == Qt::Key_Menu && window != NULL) { const QPoint globalPos = window->screen()->handle()->cursor()->pos(); const QPoint pos = window->mapFromGlobal(globalPos); -#ifndef QT_NO_CONTEXTMENU - QWindowSystemInterface::handleContextMenuEvent(window, false, pos, - globalPos, modifiers); -#endif + QWindowSystemInterfacePrivate::ContextMenuEvent contextMenuEvent(window, false, pos, + globalPos, modifiers); + QGuiApplicationPrivate::processWindowSystemEvent(&contextMenuEvent); } -#endif // QT_NO_CONTEXTMENU - QWindowSystemInterface::handleExtendedKeyEvent(window, time, type, qtcode, modifiers, - code, sym, state, string, isAutoRepeat); - +#endif + QWindowSystemInterfacePrivate::KeyEvent keyEvent(window, time, type, qtcode, modifiers, + code, sym, state, string, isAutoRepeat); + QGuiApplicationPrivate::processWindowSystemEvent(&keyEvent); } call->deleteLater(); } -- cgit v1.2.3 From a6f25dedd8fc7fa6053a6a1b98dc0548f3559db6 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 5 Feb 2019 16:29:01 +0100 Subject: Windows style, themes: Fix deprecation warnings Fix: qwindowstheme.cpp:287:77: warning: 'const QBrush& QPalette::background() const' is deprecated: Use QPalette::window() instead [-Wdeprecated-declarations] qwindowstheme.cpp:336:37: warning: 'const QBrush& QPalette::foreground() const' is deprecated: Use QPalette::windowText() instead [-Wdeprecated-declarations] qwindowstheme.cpp:861:102: warning: 'static bool QPixmapCache::find(const QString&, QPixmap&)' is deprecated: Use bool find(const QString &, QPixmap *) instead [-Wdeprecated-declarations] qwindowsvistastyle.cpp:635:56: warning: 'const QBrush& QPalette::background() const' is deprecated: Use QPalette::window() instead [-Wdeprecated-declarations] qwindowsvistastyle.cpp:707:60: warning: 'static bool QPixmapCache::find(const QString&, QPixmap&)' is deprecated: Use bool find(const QString &, QPixmap *) instead [-Wdeprecated-declarations] qwindowsxpstyle.cpp:743:58: warning: 'const QMatrix& QPainter::deviceMatrix() const' is deprecated: Use deviceTransform() instead [-Wdeprecated-declarations] qwindowsinputcontext.cpp:448:49: warning: 'const QBrush& QPalette::background() const' is deprecated: Use QPalette::window() instead [-Wdeprecated-declarations] Change-Id: I00a52a27b066caeb135ad4124f71ef3e09beafbf Reviewed-by: Christian Ehrlicher --- .../platforms/windows/qwindowsinputcontext.cpp | 2 +- src/plugins/platforms/windows/qwindowstheme.cpp | 19 ++++++++++--------- .../styles/windowsvista/qwindowsvistastyle.cpp | 12 ++++++------ src/plugins/styles/windowsvista/qwindowsxpstyle.cpp | 5 +++-- 4 files changed, 20 insertions(+), 18 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index d1e99c037b..2353afdd6a 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -445,7 +445,7 @@ static inline QTextFormat standardFormat(StandardFormat format) const QPalette palette = QGuiApplication::palette(); const QColor background = palette.text().color(); result.setBackground(QBrush(background)); - result.setForeground(palette.background()); + result.setForeground(palette.window()); break; } } diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 4b70e915a8..137ac98899 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -284,24 +284,24 @@ static inline QPalette systemPalette() result.setColor(QPalette::Link, Qt::blue); result.setColor(QPalette::LinkVisited, Qt::magenta); result.setColor(QPalette::Inactive, QPalette::Button, result.button().color()); - result.setColor(QPalette::Inactive, QPalette::Window, result.background().color()); + result.setColor(QPalette::Inactive, QPalette::Window, result.window().color()); result.setColor(QPalette::Inactive, QPalette::Light, result.light().color()); result.setColor(QPalette::Inactive, QPalette::Dark, result.dark().color()); if (result.midlight() == result.button()) result.setColor(QPalette::Midlight, result.button().color().lighter(110)); - if (result.background() != result.base()) { + if (result.window() != result.base()) { result.setColor(QPalette::Inactive, QPalette::Highlight, result.color(QPalette::Inactive, QPalette::Window)); result.setColor(QPalette::Inactive, QPalette::HighlightedText, result.color(QPalette::Inactive, QPalette::Text)); } const QColor disabled = - mixColors(result.foreground().color(), result.button().color()); + mixColors(result.windowText().color(), result.button().color()); - result.setColorGroup(QPalette::Disabled, result.foreground(), result.button(), + result.setColorGroup(QPalette::Disabled, result.windowText(), result.button(), result.light(), result.dark(), result.mid(), result.text(), result.brightText(), result.base(), - result.background()); + result.window()); result.setColor(QPalette::Disabled, QPalette::WindowText, disabled); result.setColor(QPalette::Disabled, QPalette::Text, disabled); result.setColor(QPalette::Disabled, QPalette::ButtonText, disabled); @@ -310,7 +310,7 @@ static inline QPalette systemPalette() result.setColor(QPalette::Disabled, QPalette::HighlightedText, getSysColor(COLOR_HIGHLIGHTTEXT)); result.setColor(QPalette::Disabled, QPalette::Base, - result.background().color()); + result.window().color()); return result; } @@ -333,7 +333,7 @@ static inline QPalette toolTipPalette(const QPalette &systemPalette) result.setColor(QPalette::All, QPalette::ToolTipBase, tipBgColor); result.setColor(QPalette::All, QPalette::ToolTipText, tipTextColor); const QColor disabled = - mixColors(result.foreground().color(), result.button().color()); + mixColors(result.windowText().color(), result.button().color()); result.setColor(QPalette::Disabled, QPalette::WindowText, disabled); result.setColor(QPalette::Disabled, QPalette::Text, disabled); result.setColor(QPalette::Disabled, QPalette::ToolTipText, disabled); @@ -858,7 +858,8 @@ QPixmap QWindowsFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon int iIcon = (useDefaultFolderIcon && defaultFolderIIcon >= 0) ? defaultFolderIIcon : **dirIconEntryCache.object(filePath); if (iIcon) { - QPixmapCache::find(dirIconPixmapCacheKey(iIcon, iconSize, requestedImageListSize), pixmap); + QPixmapCache::find(dirIconPixmapCacheKey(iIcon, iconSize, requestedImageListSize), + &pixmap); if (pixmap.isNull()) // Let's keep both caches in sync dirIconEntryCache.remove(filePath); else @@ -889,7 +890,7 @@ QPixmap QWindowsFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon //using the unique icon index provided by windows save us from duplicate keys key = dirIconPixmapCacheKey(info.iIcon, iconSize, requestedImageListSize); - QPixmapCache::find(key, pixmap); + QPixmapCache::find(key, &pixmap); if (!pixmap.isNull()) { QMutexLocker locker(&mx); dirIconEntryCache.insert(filePath, FakePointer::create(info.iIcon)); diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp index 771552a121..8a3ae17b1d 100644 --- a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp @@ -632,7 +632,7 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt { QPen pen = painter->pen(); int margin = 3; - painter->setPen(option->palette.background().color().darker(114)); + painter->setPen(option->palette.window().color().darker(114)); if (option->state & State_Horizontal) { int x1 = option->rect.center().x(); painter->drawLine(QPoint(x1, option->rect.top() + margin), QPoint(x1, option->rect.bottom() - margin)); @@ -704,7 +704,7 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt if (sectionSize.width() > 0 && sectionSize.height() > 0) { QString key = QString::fromLatin1("qvdelegate-%1-%2-%3-%4-%5").arg(sectionSize.width()) .arg(sectionSize.height()).arg(selected).arg(active).arg(hover); - if (!QPixmapCache::find(key, pixmap)) { + if (!QPixmapCache::find(key, &pixmap)) { pixmap = QPixmap(sectionSize); pixmap.fill(Qt::transparent); @@ -1053,7 +1053,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption } QString name = QString::fromLatin1("qiprogress-%1-%2").arg(pixmapSize.width()).arg(pixmapSize.height()); QPixmap pixmap; - if (!QPixmapCache::find(name, pixmap)) { + if (!QPixmapCache::find(name, &pixmap)) { QImage image(pixmapSize, QImage::Format_ARGB32); image.fill(Qt::transparent); QPainter imagePainter(&image); @@ -1363,7 +1363,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption case CE_ToolBar: if (const QStyleOptionToolBar *toolbar = qstyleoption_cast(option)) { QPalette pal = option->palette; - pal.setColor(QPalette::Dark, option->palette.background().color().darker(130)); + pal.setColor(QPalette::Dark, option->palette.window().color().darker(130)); QStyleOptionToolBar copyOpt = *toolbar; copyOpt.palette = pal; QWindowsStyle::drawControl(element, ©Opt, painter, widget); @@ -1388,8 +1388,8 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption painter->translate(-rect.left() + 1, -rect.top()); } - painter->setBrush(option->palette.background().color().darker(110)); - painter->setPen(option->palette.background().color().darker(130)); + painter->setBrush(option->palette.window().color().darker(110)); + painter->setPen(option->palette.window().color().darker(130)); painter->drawRect(rect.adjusted(0, 1, -1, -3)); int buttonMargin = 4; diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp index 43e8b37f71..90026e5bf0 100644 --- a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp @@ -740,7 +740,8 @@ bool QWindowsXPStylePrivate::drawBackgroundDirectly(HDC dc, XPThemeData &themeDa { QPainter *painter = themeData.painter; - const QPointF redirectionDelta(painter->deviceMatrix().dx(), painter->deviceMatrix().dy()); + const auto deviceTransform = painter->deviceTransform(); + const QPointF redirectionDelta(deviceTransform.dx(), deviceTransform.dy()); const QRect area = scaleRect(QRectF(themeData.rect), additionalDevicePixelRatio).translated(redirectionDelta).toRect(); QRegion sysRgn = painter->paintEngine()->systemClip(); @@ -835,7 +836,7 @@ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa alphaType = data.alphaType; potentialInvalidAlpha = data.hadInvalidAlpha; - haveCachedPixmap = QPixmapCache::find(pixmapCacheKey, cachedPixmap); + haveCachedPixmap = QPixmapCache::find(pixmapCacheKey, &cachedPixmap); #ifdef DEBUG_XP_STYLE char buf[25]; -- cgit v1.2.3 From de4f256d48145778ed56389f5e883c5994b34dd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Tue, 20 Mar 2018 13:30:53 +0100 Subject: Wasm: enable thread support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit configure.json: Make the “thread” feature be allowed for wasm but disabled by default. Change qmake.conf and wasm.prf to enable Emscripten pthreads mode: - Add USE_PTHREADS=1 linker flag - Add PTHREAD_POOL_SIZE linker flag with a default pool size (4). - Add TOTAL_MEMORY linker flag to set available memory (1GB) It is possible to override options such as PTHREAD_POOL_SIZE from the application .pro file using QMAKE_WASM_PTHREAD_POOL_SIZE To change TOTAL_MEMORY, use QMAKE_WASM_TOTAL_MEMORY Make qtloader.js work in pthreads mode: - The Module.instantiateWasm callback must provide the module in addition to the instance to Emscripten. - Set Module.mainScriptUrlOrBlob so that the pthreads web workers can access the main script Task-number: QTBUG-64625 Change-Id: I1ab5a559ec97c27c5fc24500ba5f863bcd275141 Reviewed-by: Morten Johan Sørvig Reviewed-by: Lorn Potter --- src/plugins/platforms/wasm/qtloader.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/wasm/qtloader.js b/src/plugins/platforms/wasm/qtloader.js index 37a5308034..84694c7b9f 100644 --- a/src/plugins/platforms/wasm/qtloader.js +++ b/src/plugins/platforms/wasm/qtloader.js @@ -312,13 +312,13 @@ function QtLoader(config) // and is ready to be instantiated. Define the instantiateWasm callback which // emscripten will call to create the instance. Module.instantiateWasm = function(imports, successCallback) { - return WebAssembly.instantiate(wasmModule, imports).then(function(instance) { - successCallback(instance); - return instance; + WebAssembly.instantiate(wasmModule, imports).then(function(instance) { + successCallback(instance, wasmModule); }, function(error) { self.error = error; setStatus("Error"); }); + return {}; }; Module.locateFile = Module.locateFile || function(filename) { @@ -382,6 +382,8 @@ function QtLoader(config) } }); + Module.mainScriptUrlOrBlob = new Blob([emscriptenModuleSource], {type: 'text/javascript'}); + config.restart = function() { // Restart by reloading the page. This will wipe all state which means -- cgit v1.2.3 From 86cf366a30c178006ee23f0fbf5bee1748a26b57 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Thu, 31 Jan 2019 13:10:50 +0100 Subject: winrt: Use ES3 ANGLE code path when blitting widgets We run into validation issues when using the ES2 code path when blitting widgets on winrt. By using ES3 we not only avoid this issue, but there might also be performance gains. We now call window()->format() instead of window()->requestedFormat as the latter will not respect the values that were set on initialization of the native window (which is done in QWinRTWindow's constructor). Change-Id: I5ed7a9326691375f9c9cb5d8d22ee8d1b643fbd0 Reviewed-by: Andre de la Rocha Reviewed-by: Miguel Costa --- src/plugins/platforms/winrt/qwinrtbackingstore.cpp | 7 +++---- src/plugins/platforms/winrt/qwinrtwindow.cpp | 2 ++ 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp index c23d48b2dd..fbf611d7f7 100644 --- a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp +++ b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp @@ -45,8 +45,7 @@ #include #include -#include -#include +#include QT_BEGIN_NAMESPACE @@ -83,7 +82,7 @@ bool QWinRTBackingStore::initialize() return true; d->context.reset(new QOpenGLContext); - QSurfaceFormat format = window()->requestedFormat(); + QSurfaceFormat format = window()->format(); d->context->setFormat(format); d->context->setScreen(window()->screen()); if (!d->context->create()) @@ -138,7 +137,7 @@ void QWinRTBackingStore::flush(QWindow *window, const QRegion ®ion, const QPo const int y2 = y1 + bounds.height(); const int x1 = bounds.x(); const int x2 = x1 + bounds.width(); - glBlitFramebufferANGLE(x1, y1, x2, y2, + glBlitFramebuffer(x1, y1, x2, y2, x1, d->size.height() - y1, x2, d->size.height() - y2, GL_COLOR_BUFFER_BIT, GL_NEAREST); diff --git a/src/plugins/platforms/winrt/qwinrtwindow.cpp b/src/plugins/platforms/winrt/qwinrtwindow.cpp index 29d234d276..83c3715bfd 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.cpp +++ b/src/plugins/platforms/winrt/qwinrtwindow.cpp @@ -112,6 +112,8 @@ QWinRTWindow::QWinRTWindow(QWindow *window) d->screen = static_cast(screen()); handleContentOrientationChange(window->contentOrientation()); + d->surfaceFormat.setMajorVersion(3); + d->surfaceFormat.setMinorVersion(0); d->surfaceFormat.setAlphaBufferSize(0); d->surfaceFormat.setRedBufferSize(8); d->surfaceFormat.setGreenBufferSize(8); -- cgit v1.2.3 From 1036c450860fcc6eb1b5fd702f8ca83972170bb7 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Wed, 30 Jan 2019 10:05:31 +0100 Subject: Revert "winrt: Skip context validation in ANGLE" Our current ANGLE version (chromium/3280) relies on validation to be done when doing the rendering, as the validation at the same time completes the caching. Skipping the validation caused asserts and rendering issues. The part of the validation that failed before is now deactivated in Qt's copy of ANGLE as it is not relevant for our use case, so that validation can be re-enabled now. This reverts commit a1dec825f9aa9d7f86d740fd420f1c084463f507. Fixes: QTBUG-73317 Change-Id: I5fd176eaa0bc28d93ca93019b7092211fe5bcce5 Reviewed-by: Miguel Costa Reviewed-by: Andre de la Rocha --- src/plugins/platforms/winrt/qwinrteglcontext.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.cpp b/src/plugins/platforms/winrt/qwinrteglcontext.cpp index eeb79be2e6..5ce2671bf1 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrteglcontext.cpp @@ -138,7 +138,6 @@ void QWinRTEGLContext::initialize() EGL_CONTEXT_CLIENT_VERSION, d->format.majorVersion(), EGL_CONTEXT_MINOR_VERSION_KHR, d->format.minorVersion(), EGL_CONTEXT_FLAGS_KHR, flags, - EGL_CONTEXT_OPENGL_NO_ERROR_KHR, true, EGL_NONE }; d->eglContext = eglCreateContext(g->eglDisplay, d->eglConfig, d->eglShareContext, attributes); -- cgit v1.2.3 From 932b13d3ec76eedfc0e76e81c05b2d54552c0715 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Mon, 4 Feb 2019 11:23:16 +0100 Subject: windows: Support OpenGL ES versions > 3.0 with ANGLE Even though our ANGLE versions only partially supports OpenGL ES > 3.0, there are users who want to use functionality that is available. By setting major and minor version we can support this use case. Fixes: QTBUG-72762 Change-Id: I9a1d3009355693baa971deb3c4bbf14c595edf0b Reviewed-by: Andre de la Rocha Reviewed-by: Miguel Costa --- src/plugins/platforms/windows/qwindowseglcontext.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index 70ba2784e9..063e81150e 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -393,8 +393,14 @@ QWindowsEGLContext::QWindowsEGLContext(QWindowsEGLStaticContext *staticContext, m_shareContext = share ? static_cast(share)->m_eglContext : nullptr; QVector contextAttrs; - contextAttrs.append(EGL_CONTEXT_CLIENT_VERSION); - contextAttrs.append(m_format.majorVersion()); + const int major = m_format.majorVersion(); + const int minor = m_format.minorVersion(); + if (major > 3 || (major == 3 && minor > 0)) + qWarning("QWindowsEGLContext: ANGLE only partially supports OpenGL ES > 3.0"); + contextAttrs.append(EGL_CONTEXT_MAJOR_VERSION); + contextAttrs.append(major); + contextAttrs.append(EGL_CONTEXT_MINOR_VERSION); + contextAttrs.append(minor); contextAttrs.append(EGL_NONE); QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); -- cgit v1.2.3 From 5f384bd39c54b6bd60e71af1e3ac1b8168a33ed9 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Mon, 4 Feb 2019 12:15:54 +0100 Subject: winrt: Warn if OpenGL ES version is set to a value > 3.0 Our bundled ANGLE library only partially supports OpenGL ES > 3.0 so warn users that there might be dragons. Change-Id: I16711fe9f449e85dd8b2369e1fcec6c9f81d5ae0 Reviewed-by: Andre de la Rocha Reviewed-by: Miguel Costa --- src/plugins/platforms/winrt/qwinrteglcontext.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.cpp b/src/plugins/platforms/winrt/qwinrteglcontext.cpp index 5ce2671bf1..aa64ac1f99 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrteglcontext.cpp @@ -134,6 +134,10 @@ void QWinRTEGLContext::initialize() const EGLint flags = d->format.testOption(QSurfaceFormat::DebugContext) ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0; + const int major = d->format.majorVersion(); + const int minor = d->format.minorVersion(); + if (major > 3 || (major == 3 && minor > 0)) + qWarning("QWinRTEGLContext: ANGLE only partially supports OpenGL ES > 3.0"); const EGLint attributes[] = { EGL_CONTEXT_CLIENT_VERSION, d->format.majorVersion(), EGL_CONTEXT_MINOR_VERSION_KHR, d->format.minorVersion(), -- cgit v1.2.3 From bf7458c76fcf821637368d05938823e42fbb28d5 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Wed, 6 Feb 2019 11:16:32 +0100 Subject: winrt qpa: Remove last windows phone leftovers WINAPI_PARTITION_PHONE_APP is defined for all our winrt mkspecs nowadays so the code can be used unconditionally. Change-Id: I4f2b60a0b9bba5b407ebbc213c44a0e5b4057855 Reviewed-by: Maurice Kalinowski --- src/plugins/platforms/winrt/qwinrtinputcontext.cpp | 4 --- src/plugins/platforms/winrt/qwinrtinputcontext.h | 2 -- src/plugins/platforms/winrt/qwinrtscreen.cpp | 29 ---------------------- src/plugins/platforms/winrt/qwinrtscreen.h | 5 ---- 4 files changed, 40 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp index f7e91bb047..5ae94ba613 100644 --- a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp @@ -158,8 +158,6 @@ HRESULT QWinRTInputContext::handleVisibilityChange(IInputPane *pane) return S_OK; } -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) - static HRESULT getInputPane(ComPtr *inputPane2) { ComPtr factory; @@ -221,6 +219,4 @@ void QWinRTInputContext::hideInputPanel() }); } -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) - QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.h b/src/plugins/platforms/winrt/qwinrtinputcontext.h index 13a0088ddc..59db90231f 100644 --- a/src/plugins/platforms/winrt/qwinrtinputcontext.h +++ b/src/plugins/platforms/winrt/qwinrtinputcontext.h @@ -74,10 +74,8 @@ public: bool isInputPanelVisible() const override; -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) void showInputPanel() override; void hideInputPanel() override; -#endif private slots: void updateScreenCursorRect(); diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index bd2bbcb81c..7f1854c601 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -91,13 +91,10 @@ typedef ITypedEventHandler CharacterRe typedef ITypedEventHandler InputEnabledHandler; typedef ITypedEventHandler KeyHandler; typedef ITypedEventHandler PointerHandler; -typedef ITypedEventHandler SizeChangedHandler; typedef ITypedEventHandler VisibilityChangedHandler; typedef ITypedEventHandler DisplayInformationHandler; typedef ITypedEventHandler RedirectHandler; -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) typedef ITypedEventHandler VisibleBoundsChangedHandler; -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) QT_BEGIN_NAMESPACE @@ -479,10 +476,8 @@ typedef HRESULT (__stdcall IDisplayInformation::*DisplayCallbackRemover)(EventRe uint qHash(DisplayCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } typedef HRESULT (__stdcall ICorePointerRedirector::*RedirectorCallbackRemover)(EventRegistrationToken); uint qHash(RedirectorCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) typedef HRESULT (__stdcall IApplicationView2::*ApplicationView2CallbackRemover)(EventRegistrationToken); uint qHash(ApplicationView2CallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) class QWinRTScreenPrivate { @@ -509,10 +504,8 @@ public: QHash windowTokens; QHash displayTokens; QHash redirectTokens; -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) QHash view2Tokens; ComPtr view2; -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) QAtomicPointer mouseGrabWindow; QAtomicPointer keyboardGrabWindow; QWindow *currentPressWindow = nullptr; @@ -603,10 +596,8 @@ QWinRTScreen::QWinRTScreen() d->cursor.reset(new QWinRTCursor); -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) hr = d->view.As(&d->view2); Q_ASSERT_SUCCEEDED(hr); -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) } QWinRTScreen::~QWinRTScreen() @@ -630,12 +621,10 @@ QWinRTScreen::~QWinRTScreen() hr = (d->redirect.Get()->*i.key())(i.value()); Q_ASSERT_SUCCEEDED(hr); } -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) for (QHash::const_iterator i = d->view2Tokens.begin(); i != d->view2Tokens.end(); ++i) { hr = (d->view2.Get()->*i.key())(i.value()); Q_ASSERT_SUCCEEDED(hr); } -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) return hr; }); RETURN_VOID_IF_FAILED("Failed to unregister screen event callbacks"); @@ -777,14 +766,8 @@ void QWinRTScreen::initialize() Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->add_PointerWheelChanged(Callback(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerWheelChanged]); Q_ASSERT_SUCCEEDED(hr); -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) hr = d->view2->add_VisibleBoundsChanged(Callback(this, &QWinRTScreen::onWindowSizeChanged).Get(), &d->view2Tokens[&IApplicationView2::remove_VisibleBoundsChanged]); Q_ASSERT_SUCCEEDED(hr); -#else - hr = d->coreWindow->add_SizeChanged(Callback(this, &QWinRTScreen::onWindowSizeChanged).Get(), &d->windowTokens[&ICoreWindow::remove_SizeChanged]); - Q_ASSERT_SUCCEEDED(hr) -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) - hr = d->coreWindow->add_Activated(Callback(this, &QWinRTScreen::onActivated).Get(), &d->windowTokens[&ICoreWindow::remove_Activated]); Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->add_Closed(Callback(this, &QWinRTScreen::onClosed).Get(), &d->windowTokens[&ICoreWindow::remove_Closed]); @@ -820,7 +803,6 @@ void QWinRTScreen::setKeyboardRect(const QRectF &keyboardRect) return; } d->logicalRect = QRectF(windowSize.X, windowSize.Y, windowSize.Width, windowSize.Height); -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) Rect visibleRect; hr = d->view2->get_VisibleBounds(&visibleRect); if (FAILED(hr)) { @@ -828,9 +810,6 @@ void QWinRTScreen::setKeyboardRect(const QRectF &keyboardRect) return; } visibleRectF = QRectF(visibleRect.X, visibleRect.Y, visibleRect.Width, visibleRect.Height); -#else - visibleRectF = d->logicalRect; -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) // if keyboard is snapped to the bottom of the screen and would cover the cursor the content is // moved up to make it visible if (keyboardRect.intersects(mCursorRect) @@ -1528,11 +1507,7 @@ HRESULT QWinRTScreen::onRedirectReleased(ICorePointerRedirector *, IPointerEvent return onPointerUpdated(nullptr, args); } -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) HRESULT QWinRTScreen::onWindowSizeChanged(IApplicationView *, IInspectable *) -#else -HRESULT QWinRTScreen::onWindowSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs *) -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) { Q_D(QWinRTScreen); @@ -1543,14 +1518,10 @@ HRESULT QWinRTScreen::onWindowSizeChanged(ICoreWindow *, IWindowSizeChangedEvent RETURN_OK_IF_FAILED("Failed to get window bounds"); d->logicalRect = QRectF(windowSize.X, windowSize.Y, windowSize.Width, windowSize.Height); -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) Rect visibleRect; hr = d->view2->get_VisibleBounds(&visibleRect); RETURN_OK_IF_FAILED("Failed to get window visible bounds"); d->visibleRect = QRectF(visibleRect.X, visibleRect.Y, visibleRect.Width, visibleRect.Height); -#else - d->visibleRect = QRectF(windowSize.X, windowSize.Y, windowSize.Width, windowSize.Height); -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) qCDebug(lcQpaWindows) << __FUNCTION__ << d->logicalRect; QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry()); diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h index cde148a638..e28cfd8cc8 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -59,7 +59,6 @@ namespace ABI { struct IPointerEventArgs; struct IVisibilityChangedEventArgs; struct IWindowActivatedEventArgs; - struct IWindowSizeChangedEventArgs; } namespace Xaml { struct IDependencyObject; @@ -154,11 +153,7 @@ private: HRESULT onOrientationChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); HRESULT onDpiChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) HRESULT onWindowSizeChanged(ABI::Windows::UI::ViewManagement::IApplicationView *, IInspectable *); -#else - HRESULT onWindowSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *); -#endif HRESULT onRedirectReleased(ABI::Windows::UI::Core::ICorePointerRedirector *, ABI::Windows::UI::Core::IPointerEventArgs *); QScopedPointer d_ptr; -- cgit v1.2.3 From 90a8de656fe689b6aa856e70e2d22de6630ea855 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 26 Jun 2018 17:12:02 +0200 Subject: Long live QColorSpace and friends Adds QColorSpace and QColorTransform classes, and parsing of a common subset of ICC profiles found in images, and also parses the ICC profiles in PNG and JPEGs. For backwards compatibility no automatic color handling is done by this patch. [ChangeLog][QtGui] A QColorSpace class has been added, and color spaces are now parsed from PNG and JPEG images. No automatic color space conversion is done however, and applications must request it. Change-Id: Ic09935f84640a716467fa3a9ed1e73c02daf3675 Reviewed-by: Eirik Aavitsland --- src/plugins/imageformats/jpeg/qjpeghandler.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp index 54fe857908..9d5ccc8a3d 100644 --- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp +++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp @@ -40,10 +40,14 @@ #include "qjpeghandler_p.h" #include +#include +#include +#include #include #include #include #include +#include #include #include // for qt_getImageText @@ -725,6 +729,7 @@ public: QRect clipRect; QString description; QStringList readTexts; + QByteArray iccProfile; struct jpeg_decompress_struct info; struct my_jpeg_source_mgr * iod_src; @@ -887,6 +892,7 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) if (!setjmp(err.setjmp_buffer)) { jpeg_save_markers(&info, JPEG_COM, 0xFFFF); jpeg_save_markers(&info, JPEG_APP0 + 1, 0xFFFF); // Exif uses APP1 marker + jpeg_save_markers(&info, JPEG_APP0 + 2, 0xFFFF); // ICC uses APP2 marker (void) jpeg_read_header(&info, TRUE); @@ -919,6 +925,10 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) readTexts.append(value); } else if (marker->marker == JPEG_APP0 + 1) { exifData.append((const char*)marker->data, marker->data_length); + } else if (marker->marker == JPEG_APP0 + 2) { + if (marker->data_length > 128 + 4 + 14 && strcmp((const char *)marker->data, "ICC_PROFILE") == 0) { + iccProfile.append((const char*)marker->data + 14, marker->data_length - 14); + } } } @@ -954,6 +964,9 @@ bool QJpegHandlerPrivate::read(QImage *image) for (int i = 0; i < readTexts.size()-1; i+=2) image->setText(readTexts.at(i), readTexts.at(i+1)); + if (!iccProfile.isEmpty()) + image->setColorSpace(QColorSpace::fromIccProfile(iccProfile)); + state = ReadingEnd; return true; } @@ -962,7 +975,6 @@ bool QJpegHandlerPrivate::read(QImage *image) } return false; - } Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_neon(quint32 *dst, const uchar *src, int len); -- cgit v1.2.3 From 4697467e9888d7631841af6be436ed58e41f4759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 8 Feb 2019 15:01:28 +0100 Subject: macOS: Explain QNSViewMouseMoveHelper for future generations Change-Id: I61f38ee38d5afb657cd8b76b2b9dba1dac7167b4 Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qnsview_mouse.mm | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm index 3d6471005d..563a66515a 100644 --- a/src/plugins/platforms/cocoa/qnsview_mouse.mm +++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm @@ -39,6 +39,22 @@ // This file is included from qnsview.mm, and only used to organize the code +/* + The reason for using this helper is to ensure that QNSView doesn't implement + the NSResponder callbacks for mouseEntered, mouseExited, and mouseMoved. + + If it did, we would get mouse events though the responder chain as well, + for example if a subview has a tracking area of its own and calls super + in the handler, which results in forwarding the event though the responder + chain. The same applies if NSWindow.acceptsMouseMovedEvents is YES. + + By having a helper as the target for our tracking areas, we know for sure + that the events we are getting stem from our own tracking areas. + + FIXME: Ideally we wouldn't need this workaround, and would correctly + interact with the responder chain by e.g. calling super if Qt does not + accept the mouse event +*/ @implementation QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) { QNSView *view; } -- cgit v1.2.3 From 21e25ff38babc6dad57a56c758d05997c16eb111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 4 Feb 2019 23:39:42 +0100 Subject: macOS: Simplify mouse tracking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't need to react to updateTrackingAreas, as we only have a single tracking area that we can add once and forget. By asking AppKit to track all events in the visible rect, we can also pass a zero-rect for the tracking area. Change-Id: I2545712adc49b51904d5adc11f1faca36901b49d Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qnsview.mm | 8 ++--- src/plugins/platforms/cocoa/qnsview_mouse.mm | 50 +++++++++++++--------------- 2 files changed, 25 insertions(+), 33 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 7f826942f3..17063f6e92 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -85,6 +85,7 @@ @end @interface QT_MANGLE_NAMESPACE(QNSView) (Mouse) +- (void)initMouse; - (NSPoint)screenMousePoint:(NSEvent *)theEvent; - (void)mouseMovedImpl:(NSEvent *)theEvent; - (void)mouseEnteredImpl:(NSEvent *)theEvent; @@ -114,7 +115,6 @@ @implementation QT_MANGLE_NAMESPACE(QNSView) { QPointer m_platformWindow; - NSTrackingArea *m_trackingArea; Qt::MouseButtons m_buttons; Qt::MouseButtons m_acceptedMouseDowns; Qt::MouseButtons m_frameStrutButtons; @@ -150,7 +150,6 @@ m_currentlyInterpretedKeyEvent = nil; m_dontOverrideCtrlLMB = qt_mac_resolveOption(false, platformWindow->window(), "_q_platform_MacDontOverrideCtrlLMB", "QT_MAC_DONT_OVERRIDE_CTRL_LMB"); - m_trackingArea = nil; self.focusRingType = NSFocusRingTypeNone; self.cursor = nil; @@ -159,6 +158,7 @@ self.previousWindow = nil; [self initDrawing]; + [self initMouse]; [self registerDragTypes]; [[NSNotificationCenter defaultCenter] addObserver:self @@ -173,10 +173,6 @@ { qCDebug(lcQpaWindow) << "Deallocating" << self; - if (m_trackingArea) { - [self removeTrackingArea:m_trackingArea]; - [m_trackingArea release]; - } [m_inputSource release]; [[NSNotificationCenter defaultCenter] removeObserver:self]; [m_mouseMoveHelper release]; diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm index 563a66515a..49c94f18db 100644 --- a/src/plugins/platforms/cocoa/qnsview_mouse.mm +++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm @@ -151,6 +151,28 @@ @implementation QT_MANGLE_NAMESPACE(QNSView) (Mouse) +- (void)initMouse +{ + NSUInteger trackingOptions = NSTrackingActiveInActiveApp + | NSTrackingMouseEnteredAndExited | NSTrackingCursorUpdate; + + // Ideally, NSTrackingMouseMoved should be turned on only if QWidget::mouseTracking + // is enabled, hover is on, or a tool tip is set. Unfortunately, Qt will send "tooltip" + // events on mouse moves, so we need to turn it on in ALL case. That means EVERY QWindow + // gets to pay the cost of mouse moves delivered to it (Apple recommends keeping it OFF + // because there is a performance hit). + trackingOptions |= NSTrackingMouseMoved; + + // Using NSTrackingInVisibleRect means AppKit will automatically synchronize the + // tracking rect with changes in the view's visible area, so leave it undefined. + trackingOptions |= NSTrackingInVisibleRect; + static const NSRect trackingRect = NSZeroRect; + + QMacAutoReleasePool pool; + [self addTrackingArea:[[[NSTrackingArea alloc] initWithRect:trackingRect + options:trackingOptions owner:m_mouseMoveHelper userInfo:nil] autorelease]]; +} + - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent { Q_UNUSED(theEvent) @@ -422,35 +444,9 @@ [super otherMouseUp:theEvent]; } -- (void)updateTrackingAreas -{ - [super updateTrackingAreas]; - - QMacAutoReleasePool pool; - - // NSTrackingInVisibleRect keeps care of updating once the tracking is set up, so bail out early - if (m_trackingArea && [[self trackingAreas] containsObject:m_trackingArea]) - return; - - // Ideally, we shouldn't have NSTrackingMouseMoved events included below, it should - // only be turned on if mouseTracking, hover is on or a tool tip is set. - // Unfortunately, Qt will send "tooltip" events on mouse moves, so we need to - // turn it on in ALL case. That means EVERY QWindow gets to pay the cost of - // mouse moves delivered to it (Apple recommends keeping it OFF because there - // is a performance hit). So it goes. - NSUInteger trackingOptions = NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp - | NSTrackingInVisibleRect | NSTrackingMouseMoved | NSTrackingCursorUpdate; - [m_trackingArea release]; - m_trackingArea = [[NSTrackingArea alloc] initWithRect:[self frame] - options:trackingOptions - owner:m_mouseMoveHelper - userInfo:nil]; - [self addTrackingArea:m_trackingArea]; -} - - (void)cursorUpdate:(NSEvent *)theEvent { - qCDebug(lcQpaMouse) << "[QNSView cursorUpdate:]" << self.cursor; + qCDebug(lcQpaMouse) << "Updating cursor for" << self << "to" << self.cursor; // Note: We do not get this callback when moving from a subview that // uses the legacy cursorRect API, so the cursor is reset to the arrow -- cgit v1.2.3 From 17e51585702b51c4b854ec32a0cb9339ab34528f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 4 Feb 2019 15:53:01 +0100 Subject: macOS: Treat default swapInterval (-1) as vsync-enabled display-link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I6d3d241d3813bfac36155ad219d4a338cb1ef6f7 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoascreen.mm | 4 ++-- src/plugins/platforms/cocoa/qcocoawindow.h | 1 + src/plugins/platforms/cocoa/qcocoawindow.mm | 13 +++++++++---- 3 files changed, 12 insertions(+), 6 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm index afe14e623c..36c11ba8af 100644 --- a/src/plugins/platforms/cocoa/qcocoascreen.mm +++ b/src/plugins/platforms/cocoa/qcocoascreen.mm @@ -330,7 +330,7 @@ void QCocoaScreen::deliverUpdateRequests() auto windows = QGuiApplication::allWindows(); for (int i = 0; i < windows.size(); ++i) { QWindow *window = windows.at(i); - QPlatformWindow *platformWindow = window->handle(); + auto *platformWindow = static_cast(window->handle()); if (!platformWindow) continue; @@ -341,7 +341,7 @@ void QCocoaScreen::deliverUpdateRequests() continue; // Skip windows that are not doing update requests via display link - if (!(window->format().swapInterval() > 0)) + if (!platformWindow->updatesWithDisplayLink()) continue; platformWindow->deliverUpdateRequest(); diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 8f1bdb8af0..0a913ef66e 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -129,6 +129,7 @@ public: bool isForeignWindow() const override; void requestUpdate() override; + bool updatesWithDisplayLink() const; void deliverUpdateRequest() override; void requestActivateWindow() override; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index a1bed3db45..792993afbf 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1473,11 +1473,10 @@ void QCocoaWindow::recreateWindowIfNeeded() void QCocoaWindow::requestUpdate() { - const int swapInterval = format().swapInterval(); - qCDebug(lcQpaDrawing) << "QCocoaWindow::requestUpdate" << window() << "swapInterval" << swapInterval; + qCDebug(lcQpaDrawing) << "QCocoaWindow::requestUpdate" << window() + << "using" << (updatesWithDisplayLink() ? "display-link" : "timer"); - if (swapInterval > 0) { - // Vsync is enabled, deliver via CVDisplayLink + if (updatesWithDisplayLink()) { static_cast(screen())->requestUpdate(); } else { // Fall back to the un-throttled timer-based callback @@ -1485,6 +1484,12 @@ void QCocoaWindow::requestUpdate() } } +bool QCocoaWindow::updatesWithDisplayLink() const +{ + // Update via CVDisplayLink if Vsync is enabled + return format().swapInterval() != 0; +} + void QCocoaWindow::deliverUpdateRequest() { // Don't send update requests for views that need display, as the update -- cgit v1.2.3 From 9f22ac0aa0254f20f9b26aec7b124d74141fdfcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 30 Jan 2019 16:29:59 +0100 Subject: macOS: Don't send redundant geometry change events for top level windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Top level windows already get their geometry changes via windowDidMove and windowDidResize. Change-Id: Ie6370aa290ef48c8b3ac770e77adb57ce43cbb47 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoawindow.mm | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 792993afbf..724c9485bd 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1101,6 +1101,9 @@ void QCocoaWindow::setEmbeddedInForeignView() void QCocoaWindow::viewDidChangeFrame() { + if (isContentView()) + return; // Handled below + handleGeometryChange(); } -- cgit v1.2.3 From 8c73ddd8e3fb43cc22fa111b855ab1f9f5b83405 Mon Sep 17 00:00:00 2001 From: Gerry Boland Date: Wed, 18 Jul 2018 15:28:02 +0100 Subject: qpa: remove mirclient MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Mir display server is now Wayland compatible, so a dedicated Mir client library is no longer necessary. [ChangeLog][Platform Specific Changes][Mir] The Mir platform plugin has been removed: use the Wayland plugin when connecting to a Mir display server. Change-Id: Ibc77698dd45a1afaf29f0d57b5e5cf7bd91735f5 Reviewed-by: Gatis Paeglis Reviewed-by: Tor Arne Vestbø Reviewed-by: Paul Olav Tvete Reviewed-by: Johan Helsing --- src/plugins/platforms/mirclient/mirclient.json | 3 - src/plugins/platforms/mirclient/mirclient.pro | 61 -- .../mirclient/qmirclientappstatecontroller.cpp | 102 --- .../mirclient/qmirclientappstatecontroller.h | 62 -- .../platforms/mirclient/qmirclientbackingstore.cpp | 157 ---- .../platforms/mirclient/qmirclientbackingstore.h | 74 -- .../platforms/mirclient/qmirclientclipboard.cpp | 181 ---- .../platforms/mirclient/qmirclientclipboard.h | 92 -- .../platforms/mirclient/qmirclientcursor.cpp | 209 ----- src/plugins/platforms/mirclient/qmirclientcursor.h | 64 -- .../mirclient/qmirclientdebugextension.cpp | 79 -- .../platforms/mirclient/qmirclientdebugextension.h | 63 -- .../mirclient/qmirclientdesktopwindow.cpp | 50 -- .../platforms/mirclient/qmirclientdesktopwindow.h | 53 -- .../platforms/mirclient/qmirclientglcontext.cpp | 132 --- .../platforms/mirclient/qmirclientglcontext.h | 63 -- .../platforms/mirclient/qmirclientinput.cpp | 708 --------------- src/plugins/platforms/mirclient/qmirclientinput.h | 86 -- .../platforms/mirclient/qmirclientintegration.cpp | 411 --------- .../platforms/mirclient/qmirclientintegration.h | 131 --- .../platforms/mirclient/qmirclientlogging.h | 55 -- .../mirclient/qmirclientnativeinterface.cpp | 217 ----- .../mirclient/qmirclientnativeinterface.h | 83 -- .../mirclient/qmirclientorientationchangeevent_p.h | 61 -- .../mirclient/qmirclientplatformservices.cpp | 75 -- .../mirclient/qmirclientplatformservices.h | 57 -- .../platforms/mirclient/qmirclientplugin.cpp | 56 -- src/plugins/platforms/mirclient/qmirclientplugin.h | 56 -- .../platforms/mirclient/qmirclientscreen.cpp | 262 ------ src/plugins/platforms/mirclient/qmirclientscreen.h | 106 --- .../mirclient/qmirclientscreenobserver.cpp | 161 ---- .../platforms/mirclient/qmirclientscreenobserver.h | 78 -- .../platforms/mirclient/qmirclienttheme.cpp | 67 -- src/plugins/platforms/mirclient/qmirclienttheme.h | 57 -- .../platforms/mirclient/qmirclientwindow.cpp | 968 --------------------- src/plugins/platforms/mirclient/qmirclientwindow.h | 118 --- src/plugins/platforms/platforms.pro | 2 - 37 files changed, 5260 deletions(-) delete mode 100644 src/plugins/platforms/mirclient/mirclient.json delete mode 100644 src/plugins/platforms/mirclient/mirclient.pro delete mode 100644 src/plugins/platforms/mirclient/qmirclientappstatecontroller.cpp delete mode 100644 src/plugins/platforms/mirclient/qmirclientappstatecontroller.h delete mode 100644 src/plugins/platforms/mirclient/qmirclientbackingstore.cpp delete mode 100644 src/plugins/platforms/mirclient/qmirclientbackingstore.h delete mode 100644 src/plugins/platforms/mirclient/qmirclientclipboard.cpp delete mode 100644 src/plugins/platforms/mirclient/qmirclientclipboard.h delete mode 100644 src/plugins/platforms/mirclient/qmirclientcursor.cpp delete mode 100644 src/plugins/platforms/mirclient/qmirclientcursor.h delete mode 100644 src/plugins/platforms/mirclient/qmirclientdebugextension.cpp delete mode 100644 src/plugins/platforms/mirclient/qmirclientdebugextension.h delete mode 100644 src/plugins/platforms/mirclient/qmirclientdesktopwindow.cpp delete mode 100644 src/plugins/platforms/mirclient/qmirclientdesktopwindow.h delete mode 100644 src/plugins/platforms/mirclient/qmirclientglcontext.cpp delete mode 100644 src/plugins/platforms/mirclient/qmirclientglcontext.h delete mode 100644 src/plugins/platforms/mirclient/qmirclientinput.cpp delete mode 100644 src/plugins/platforms/mirclient/qmirclientinput.h delete mode 100644 src/plugins/platforms/mirclient/qmirclientintegration.cpp delete mode 100644 src/plugins/platforms/mirclient/qmirclientintegration.h delete mode 100644 src/plugins/platforms/mirclient/qmirclientlogging.h delete mode 100644 src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp delete mode 100644 src/plugins/platforms/mirclient/qmirclientnativeinterface.h delete mode 100644 src/plugins/platforms/mirclient/qmirclientorientationchangeevent_p.h delete mode 100644 src/plugins/platforms/mirclient/qmirclientplatformservices.cpp delete mode 100644 src/plugins/platforms/mirclient/qmirclientplatformservices.h delete mode 100644 src/plugins/platforms/mirclient/qmirclientplugin.cpp delete mode 100644 src/plugins/platforms/mirclient/qmirclientplugin.h delete mode 100644 src/plugins/platforms/mirclient/qmirclientscreen.cpp delete mode 100644 src/plugins/platforms/mirclient/qmirclientscreen.h delete mode 100644 src/plugins/platforms/mirclient/qmirclientscreenobserver.cpp delete mode 100644 src/plugins/platforms/mirclient/qmirclientscreenobserver.h delete mode 100644 src/plugins/platforms/mirclient/qmirclienttheme.cpp delete mode 100644 src/plugins/platforms/mirclient/qmirclienttheme.h delete mode 100644 src/plugins/platforms/mirclient/qmirclientwindow.cpp delete mode 100644 src/plugins/platforms/mirclient/qmirclientwindow.h (limited to 'src/plugins') diff --git a/src/plugins/platforms/mirclient/mirclient.json b/src/plugins/platforms/mirclient/mirclient.json deleted file mode 100644 index c31558a2f1..0000000000 --- a/src/plugins/platforms/mirclient/mirclient.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Keys": [ "mirclient" ] -} diff --git a/src/plugins/platforms/mirclient/mirclient.pro b/src/plugins/platforms/mirclient/mirclient.pro deleted file mode 100644 index d9eb069200..0000000000 --- a/src/plugins/platforms/mirclient/mirclient.pro +++ /dev/null @@ -1,61 +0,0 @@ -TARGET = qmirclient - -QT += \ - core-private gui-private dbus \ - theme_support-private eventdispatcher_support-private \ - fontdatabase_support-private egl_support-private - -qtHaveModule(linuxaccessibility_support-private): \ - QT += linuxaccessibility_support-private - -DEFINES += MESA_EGL_NO_X11_HEADERS -# CONFIG += c++11 # only enables C++0x -QMAKE_CXXFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden -std=c++11 -Werror -Wall -QMAKE_LFLAGS += -std=c++11 -Wl,-no-undefined - -QMAKE_USE_PRIVATE += mirclient - -SOURCES = \ - qmirclientappstatecontroller.cpp \ - qmirclientbackingstore.cpp \ - qmirclientclipboard.cpp \ - qmirclientcursor.cpp \ - qmirclientdebugextension.cpp \ - qmirclientdesktopwindow.cpp \ - qmirclientglcontext.cpp \ - qmirclientinput.cpp \ - qmirclientintegration.cpp \ - qmirclientnativeinterface.cpp \ - qmirclientplatformservices.cpp \ - qmirclientplugin.cpp \ - qmirclientscreen.cpp \ - qmirclientscreenobserver.cpp \ - qmirclienttheme.cpp \ - qmirclientwindow.cpp - -HEADERS = \ - qmirclientappstatecontroller.h \ - qmirclientbackingstore.h \ - qmirclientclipboard.h \ - qmirclientcursor.h \ - qmirclientdebugextension.h \ - qmirclientdesktopwindow.h \ - qmirclientglcontext.h \ - qmirclientinput.h \ - qmirclientintegration.h \ - qmirclientlogging.h \ - qmirclientnativeinterface.h \ - qmirclientorientationchangeevent_p.h \ - qmirclientplatformservices.h \ - qmirclientplugin.h \ - qmirclientscreen.h \ - qmirclientscreenobserver.h \ - qmirclienttheme.h \ - qmirclientwindow.h - -QMAKE_USE_PRIVATE += xkbcommon - -PLUGIN_TYPE = platforms -PLUGIN_CLASS_NAME = MirServerIntegrationPlugin -!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - -load(qt_plugin) diff --git a/src/plugins/platforms/mirclient/qmirclientappstatecontroller.cpp b/src/plugins/platforms/mirclient/qmirclientappstatecontroller.cpp deleted file mode 100644 index 69fc9b7aa7..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientappstatecontroller.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include "qmirclientappstatecontroller.h" - -#include - -/* - * QMirClientAppStateController - updates Qt's QApplication::applicationState property. - * - * Tries to avoid active-inactive-active invocations using a timer. The rapid state - * change can confuse some applications. - */ - -QMirClientAppStateController::QMirClientAppStateController() - : m_suspended(false) - , m_lastActive(true) -{ - m_inactiveTimer.setSingleShot(true); - m_inactiveTimer.setInterval(10); - QObject::connect(&m_inactiveTimer, &QTimer::timeout, []() - { - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); - }); -} - -void QMirClientAppStateController::setSuspended() -{ - m_inactiveTimer.stop(); - if (!m_suspended) { - m_suspended = true; - - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended); - } -} - -void QMirClientAppStateController::setResumed() -{ - m_inactiveTimer.stop(); - if (m_suspended) { - m_suspended = false; - - if (m_lastActive) { - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive); - } else { - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); - } - } -} - -void QMirClientAppStateController::setWindowFocused(bool focused) -{ - if (m_suspended) { - return; - } - - if (focused) { - m_inactiveTimer.stop(); - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive); - } else { - m_inactiveTimer.start(); - } - - m_lastActive = focused; -} diff --git a/src/plugins/platforms/mirclient/qmirclientappstatecontroller.h b/src/plugins/platforms/mirclient/qmirclientappstatecontroller.h deleted file mode 100644 index b3aa0022d9..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientappstatecontroller.h +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTAPPSTATECONTROLLER_H -#define QMIRCLIENTAPPSTATECONTROLLER_H - -#include - -class QMirClientAppStateController -{ -public: - QMirClientAppStateController(); - - void setSuspended(); - void setResumed(); - - void setWindowFocused(bool focused); - -private: - bool m_suspended; - bool m_lastActive; - QTimer m_inactiveTimer; -}; - -#endif // QMIRCLIENTAPPSTATECONTROLLER_H diff --git a/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp b/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp deleted file mode 100644 index 51363619d9..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include "qmirclientbackingstore.h" -#include "qmirclientlogging.h" -#include -#include -#include -#include -#include - -QMirClientBackingStore::QMirClientBackingStore(QWindow* window) - : QPlatformBackingStore(window) - , mContext(new QOpenGLContext) - , mTexture(new QOpenGLTexture(QOpenGLTexture::Target2D)) - , mBlitter(new QOpenGLTextureBlitter) -{ - mContext->setFormat(window->requestedFormat()); - mContext->setScreen(window->screen()); - mContext->create(); - - window->setSurfaceType(QSurface::OpenGLSurface); -} - -QMirClientBackingStore::~QMirClientBackingStore() -{ - mContext->makeCurrent(window()); // needed as QOpenGLTexture destructor assumes current context -} - -void QMirClientBackingStore::flush(QWindow* window, const QRegion& region, const QPoint& offset) -{ - Q_UNUSED(region); - Q_UNUSED(offset); - mContext->makeCurrent(window); - glViewport(0, 0, window->width(), window->height()); - - updateTexture(); - - if (!mBlitter->isCreated()) - mBlitter->create(); - - mBlitter->bind(); - mBlitter->blit(mTexture->textureId(), QMatrix4x4(), QOpenGLTextureBlitter::OriginTopLeft); - mBlitter->release(); - - mContext->swapBuffers(window); -} - -void QMirClientBackingStore::updateTexture() -{ - if (mDirty.isNull()) - return; - - if (!mTexture->isCreated()) { - mTexture->setMinificationFilter(QOpenGLTexture::Nearest); - mTexture->setMagnificationFilter(QOpenGLTexture::Nearest); - mTexture->setWrapMode(QOpenGLTexture::ClampToEdge); - mTexture->setData(mImage, QOpenGLTexture::DontGenerateMipMaps); - mTexture->create(); - } - mTexture->bind(); - - QRegion fixed; - QRect imageRect = mImage.rect(); - - for (const QRect &rect : mDirty) { - // intersect with image rect to be sure - QRect r = imageRect & rect; - - // if the rect is wide enough it is cheaper to just extend it instead of doing an image copy - if (r.width() >= imageRect.width() / 2) { - r.setX(0); - r.setWidth(imageRect.width()); - } - - fixed |= r; - } - - for (const QRect &rect : fixed) { - // if the sub-rect is full-width we can pass the image data directly to - // OpenGL instead of copying, since there is no gap between scanlines - if (rect.width() == imageRect.width()) { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, - mImage.constScanLine(rect.y())); - } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, - mImage.copy(rect).constBits()); - } - } - /* End of code taken from QEGLPlatformBackingStore */ - - mDirty = QRegion(); -} - - -void QMirClientBackingStore::beginPaint(const QRegion& region) -{ - mDirty |= region; -} - -void QMirClientBackingStore::resize(const QSize& size, const QRegion& /*staticContents*/) -{ - mImage = QImage(size, QImage::Format_RGBA8888); - - mContext->makeCurrent(window()); - - if (mTexture->isCreated()) - mTexture->destroy(); -} - -QPaintDevice* QMirClientBackingStore::paintDevice() -{ - return &mImage; -} - -QImage QMirClientBackingStore::toImage() const -{ - // used by QPlatformBackingStore::composeAndFlush - return mImage; -} diff --git a/src/plugins/platforms/mirclient/qmirclientbackingstore.h b/src/plugins/platforms/mirclient/qmirclientbackingstore.h deleted file mode 100644 index 7644c77df2..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientbackingstore.h +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTBACKINGSTORE_H -#define QMIRCLIENTBACKINGSTORE_H - -#include - -class QOpenGLContext; -class QOpenGLTexture; -class QOpenGLTextureBlitter; - -class QMirClientBackingStore : public QPlatformBackingStore -{ -public: - QMirClientBackingStore(QWindow* window); - virtual ~QMirClientBackingStore(); - - // QPlatformBackingStore methods. - void beginPaint(const QRegion&) override; - void flush(QWindow* window, const QRegion& region, const QPoint& offset) override; - void resize(const QSize& size, const QRegion& staticContents) override; - QPaintDevice* paintDevice() override; - QImage toImage() const override; - -protected: - void updateTexture(); - -private: - QScopedPointer mContext; - QScopedPointer mTexture; - QScopedPointer mBlitter; - QImage mImage; - QRegion mDirty; -}; - -#endif // QMIRCLIENTBACKINGSTORE_H diff --git a/src/plugins/platforms/mirclient/qmirclientclipboard.cpp b/src/plugins/platforms/mirclient/qmirclientclipboard.cpp deleted file mode 100644 index b9fc9b3b42..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientclipboard.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include "qmirclientclipboard.h" -#include "qmirclientlogging.h" -#include "qmirclientwindow.h" - -#include -#include -#include -#include -#include - -// content-hub -#include - -// get this cumbersome nested namespace out of the way -using namespace com::ubuntu::content; - -QMirClientClipboard::QMirClientClipboard() - : mMimeData(new QMimeData) - , mContentHub(Hub::Client::instance()) -{ - connect(mContentHub, &Hub::pasteboardChanged, this, [this]() { - if (mClipboardState == QMirClientClipboard::SyncedClipboard) { - mClipboardState = QMirClientClipboard::OutdatedClipboard; - emitChanged(QClipboard::Clipboard); - } - }); - - connect(qGuiApp, &QGuiApplication::applicationStateChanged, - this, &QMirClientClipboard::onApplicationStateChanged); - - requestMimeData(); -} - -QMirClientClipboard::~QMirClientClipboard() -{ - delete mMimeData; -} - -QMimeData* QMirClientClipboard::mimeData(QClipboard::Mode mode) -{ - if (mode != QClipboard::Clipboard) - return nullptr; - - // Blocks dataChanged() signal from being emitted. Makes no sense to emit it from - // inside the data getter. - const QSignalBlocker blocker(this); - - if (mClipboardState == OutdatedClipboard) { - updateMimeData(); - } else if (mClipboardState == SyncingClipboard) { - mPasteReply->waitForFinished(); - } - - return mMimeData; -} - -void QMirClientClipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode) -{ - QWindow *focusWindow = QGuiApplication::focusWindow(); - if (focusWindow && mode == QClipboard::Clipboard && mimeData != nullptr) { - QString surfaceId = static_cast(focusWindow->handle())->persistentSurfaceId(); - - QDBusPendingCall reply = mContentHub->createPaste(surfaceId, *mimeData); - - // Don't care whether it succeeded - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); - connect(watcher, &QDBusPendingCallWatcher::finished, - watcher, &QObject::deleteLater); - - mMimeData = mimeData; - mClipboardState = SyncedClipboard; - emitChanged(QClipboard::Clipboard); - } -} - -bool QMirClientClipboard::supportsMode(QClipboard::Mode mode) const -{ - return mode == QClipboard::Clipboard; -} - -bool QMirClientClipboard::ownsMode(QClipboard::Mode mode) const -{ - Q_UNUSED(mode); - return false; -} - -void QMirClientClipboard::onApplicationStateChanged(Qt::ApplicationState state) -{ - if (state == Qt::ApplicationActive) { - // Only focused or active applications might be allowed to paste, so we probably - // missed changes in the clipboard while we were hidden, inactive or, more importantly, - // suspended. - requestMimeData(); - } -} - -void QMirClientClipboard::updateMimeData() -{ - if (qGuiApp->applicationState() != Qt::ApplicationActive) { - // Don't even bother asking as content-hub would probably ignore our request (and should). - return; - } - - delete mMimeData; - - QWindow *focusWindow = QGuiApplication::focusWindow(); - if (focusWindow) { - QString surfaceId = static_cast(focusWindow->handle())->persistentSurfaceId(); - mMimeData = mContentHub->latestPaste(surfaceId); - mClipboardState = SyncedClipboard; - emitChanged(QClipboard::Clipboard); - } -} - -void QMirClientClipboard::requestMimeData() -{ - if (qGuiApp->applicationState() != Qt::ApplicationActive) { - // Don't even bother asking as content-hub would probably ignore our request (and should). - return; - } - - QWindow *focusWindow = QGuiApplication::focusWindow(); - if (!focusWindow) { - return; - } - - QString surfaceId = static_cast(focusWindow->handle())->persistentSurfaceId(); - QDBusPendingCall reply = mContentHub->requestLatestPaste(surfaceId); - mClipboardState = SyncingClipboard; - - mPasteReply = new QDBusPendingCallWatcher(reply, this); - connect(mPasteReply, &QDBusPendingCallWatcher::finished, - this, [this]() { - delete mMimeData; - mMimeData = mContentHub->paste(*mPasteReply); - mClipboardState = SyncedClipboard; - mPasteReply->deleteLater(); - mPasteReply = nullptr; - emitChanged(QClipboard::Clipboard); - }); -} diff --git a/src/plugins/platforms/mirclient/qmirclientclipboard.h b/src/plugins/platforms/mirclient/qmirclientclipboard.h deleted file mode 100644 index 09e9bcdf38..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientclipboard.h +++ /dev/null @@ -1,92 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTCLIPBOARD_H -#define QMIRCLIENTCLIPBOARD_H - -#include - -#include -#include - -namespace com { - namespace ubuntu { - namespace content { - class Hub; - } - } -} - -class QDBusPendingCallWatcher; - -class QMirClientClipboard : public QObject, public QPlatformClipboard -{ - Q_OBJECT -public: - QMirClientClipboard(); - virtual ~QMirClientClipboard(); - - // QPlatformClipboard methods. - QMimeData* mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override; - void setMimeData(QMimeData* data, QClipboard::Mode mode = QClipboard::Clipboard) override; - bool supportsMode(QClipboard::Mode mode) const override; - bool ownsMode(QClipboard::Mode mode) const override; - -private Q_SLOTS: - void onApplicationStateChanged(Qt::ApplicationState state); - -private: - void updateMimeData(); - void requestMimeData(); - - QMimeData *mMimeData; - - enum { - OutdatedClipboard, // Our mimeData is outdated, need to fetch latest from ContentHub - SyncingClipboard, // Our mimeData is outdated and we are waiting for ContentHub to reply with the latest paste - SyncedClipboard // Our mimeData is in sync with what ContentHub has - } mClipboardState{OutdatedClipboard}; - - com::ubuntu::content::Hub *mContentHub; - - QDBusPendingCallWatcher *mPasteReply{nullptr}; -}; - -#endif // QMIRCLIENTCLIPBOARD_H diff --git a/src/plugins/platforms/mirclient/qmirclientcursor.cpp b/src/plugins/platforms/mirclient/qmirclientcursor.cpp deleted file mode 100644 index 812cde95c6..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientcursor.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015-2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include "qmirclientcursor.h" - -#include "qmirclientlogging.h" -#include "qmirclientwindow.h" - -#include - -Q_LOGGING_CATEGORY(mirclientCursor, "qt.qpa.mirclient.cursor", QtWarningMsg) - -QMirClientCursor::QMirClientCursor(MirConnection *connection) - : mConnection(connection) -{ - /* - * TODO: Add the missing cursors to Mir (LP: #1388987) - * Those are the ones without a mir_ prefix, which are X11 cursors - * and won't be understood by any shell other than Unity8. - */ - mShapeToCursorName[Qt::ArrowCursor] = mir_arrow_cursor_name; - mShapeToCursorName[Qt::UpArrowCursor] = "up_arrow"; - mShapeToCursorName[Qt::CrossCursor] = mir_crosshair_cursor_name; - mShapeToCursorName[Qt::WaitCursor] = mir_busy_cursor_name; - mShapeToCursorName[Qt::IBeamCursor] = mir_caret_cursor_name; - mShapeToCursorName[Qt::SizeVerCursor] = mir_vertical_resize_cursor_name; - mShapeToCursorName[Qt::SizeHorCursor] = mir_horizontal_resize_cursor_name; - mShapeToCursorName[Qt::SizeBDiagCursor] = mir_diagonal_resize_bottom_to_top_cursor_name; - mShapeToCursorName[Qt::SizeFDiagCursor] = mir_diagonal_resize_top_to_bottom_cursor_name; - mShapeToCursorName[Qt::SizeAllCursor] = mir_omnidirectional_resize_cursor_name; - mShapeToCursorName[Qt::BlankCursor] = mir_disabled_cursor_name; - mShapeToCursorName[Qt::SplitVCursor] = mir_vsplit_resize_cursor_name; - mShapeToCursorName[Qt::SplitHCursor] = mir_hsplit_resize_cursor_name; - mShapeToCursorName[Qt::PointingHandCursor] = mir_pointing_hand_cursor_name; - mShapeToCursorName[Qt::ForbiddenCursor] = "forbidden"; - mShapeToCursorName[Qt::WhatsThisCursor] = "whats_this"; - mShapeToCursorName[Qt::BusyCursor] = "left_ptr_watch"; - mShapeToCursorName[Qt::OpenHandCursor] = mir_open_hand_cursor_name; - mShapeToCursorName[Qt::ClosedHandCursor] = mir_closed_hand_cursor_name; - mShapeToCursorName[Qt::DragCopyCursor] = "dnd-copy"; - mShapeToCursorName[Qt::DragMoveCursor] = "dnd-move"; - mShapeToCursorName[Qt::DragLinkCursor] = "dnd-link"; -} - -namespace { -const char *qtCursorShapeToStr(Qt::CursorShape shape) -{ - switch (shape) { - case Qt::ArrowCursor: - return "Arrow"; - case Qt::UpArrowCursor: - return "UpArrow"; - case Qt::CrossCursor: - return "Cross"; - case Qt::WaitCursor: - return "Wait"; - case Qt::IBeamCursor: - return "IBeam"; - case Qt::SizeVerCursor: - return "SizeVer"; - case Qt::SizeHorCursor: - return "SizeHor"; - case Qt::SizeBDiagCursor: - return "SizeBDiag"; - case Qt::SizeFDiagCursor: - return "SizeFDiag"; - case Qt::SizeAllCursor: - return "SizeAll"; - case Qt::BlankCursor: - return "Blank"; - case Qt::SplitVCursor: - return "SplitV"; - case Qt::SplitHCursor: - return "SplitH"; - case Qt::PointingHandCursor: - return "PointingHand"; - case Qt::ForbiddenCursor: - return "Forbidden"; - case Qt::WhatsThisCursor: - return "WhatsThis"; - case Qt::BusyCursor: - return "Busy"; - case Qt::OpenHandCursor: - return "OpenHand"; - case Qt::ClosedHandCursor: - return "ClosedHand"; - case Qt::DragCopyCursor: - return "DragCopy"; - case Qt::DragMoveCursor: - return "DragMove"; - case Qt::DragLinkCursor: - return "DragLink"; - case Qt::BitmapCursor: - return "Bitmap"; - default: - return "???"; - } -} -} // anonymous namespace - -void QMirClientCursor::changeCursor(QCursor *windowCursor, QWindow *window) -{ - if (!window) { - return; - } - - MirSurface *surface = static_cast(window->handle())->mirSurface(); - - if (!surface) { - return; - } - - - if (windowCursor) { - qCDebug(mirclientCursor, "changeCursor shape=%s, window=%p", qtCursorShapeToStr(windowCursor->shape()), window); - if (!windowCursor->pixmap().isNull()) { - configureMirCursorWithPixmapQCursor(surface, *windowCursor); - } else if (windowCursor->shape() == Qt::BitmapCursor) { - // TODO: Implement bitmap cursor support - applyDefaultCursorConfiguration(surface); - } else { - const auto &cursorName = mShapeToCursorName.value(windowCursor->shape(), QByteArray("left_ptr")); - auto cursorConfiguration = mir_cursor_configuration_from_name(cursorName.data()); - mir_surface_configure_cursor(surface, cursorConfiguration); - mir_cursor_configuration_destroy(cursorConfiguration); - } - } else { - applyDefaultCursorConfiguration(surface); - } - -} - -void QMirClientCursor::configureMirCursorWithPixmapQCursor(MirSurface *surface, QCursor &cursor) -{ - QImage image = cursor.pixmap().toImage(); - - if (image.format() != QImage::Format_ARGB32) { - image = image.convertToFormat(QImage::Format_ARGB32); - } - - MirBufferStream *bufferStream = mir_connection_create_buffer_stream_sync(mConnection, - image.width(), image.height(), mir_pixel_format_argb_8888, mir_buffer_usage_software); - - { - MirGraphicsRegion region; - mir_buffer_stream_get_graphics_region(bufferStream, ®ion); - - char *regionLine = region.vaddr; - Q_ASSERT(image.bytesPerLine() <= region.stride); - for (int i = 0; i < image.height(); ++i) { - memcpy(regionLine, image.scanLine(i), image.bytesPerLine()); - regionLine += region.stride; - } - } - - mir_buffer_stream_swap_buffers_sync(bufferStream); - - { - auto configuration = mir_cursor_configuration_from_buffer_stream(bufferStream, cursor.hotSpot().x(), cursor.hotSpot().y()); - mir_surface_configure_cursor(surface, configuration); - mir_cursor_configuration_destroy(configuration); - } - - mir_buffer_stream_release_sync(bufferStream); -} - -void QMirClientCursor::applyDefaultCursorConfiguration(MirSurface *surface) -{ - auto cursorConfiguration = mir_cursor_configuration_from_name("left_ptr"); - mir_surface_configure_cursor(surface, cursorConfiguration); - mir_cursor_configuration_destroy(cursorConfiguration); -} diff --git a/src/plugins/platforms/mirclient/qmirclientcursor.h b/src/plugins/platforms/mirclient/qmirclientcursor.h deleted file mode 100644 index c5de23b272..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientcursor.h +++ /dev/null @@ -1,64 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015-2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTCURSOR_H -#define QMIRCLIENTCURSOR_H - -#include - -#include -#include - -struct MirConnection; -struct MirSurface; - -class QMirClientCursor : public QPlatformCursor -{ -public: - QMirClientCursor(MirConnection *connection); - void changeCursor(QCursor *windowCursor, QWindow *window) override; -private: - void configureMirCursorWithPixmapQCursor(MirSurface *surface, QCursor &cursor); - void applyDefaultCursorConfiguration(MirSurface *surface); - QMap mShapeToCursorName; - MirConnection *mConnection; -}; - -#endif // QMIRCLIENTCURSOR_H diff --git a/src/plugins/platforms/mirclient/qmirclientdebugextension.cpp b/src/plugins/platforms/mirclient/qmirclientdebugextension.cpp deleted file mode 100644 index 9aa934083d..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientdebugextension.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include "qmirclientdebugextension.h" - -#include "qmirclientlogging.h" - -// mir client debug -#include - -Q_LOGGING_CATEGORY(mirclientDebug, "qt.qpa.mirclient.debug") - -QMirClientDebugExtension::QMirClientDebugExtension() - : m_mirclientDebug(QStringLiteral("mirclient-debug-extension"), 1) - , m_mapper(nullptr) -{ - qCDebug(mirclientDebug) << "NOTICE: Loading mirclient-debug-extension"; - m_mapper = (MapperPrototype) m_mirclientDebug.resolve("mir_debug_surface_coords_to_screen"); - - if (!m_mirclientDebug.isLoaded()) { - qCWarning(mirclientDebug) << "ERROR: mirclient-debug-extension failed to load:" - << m_mirclientDebug.errorString(); - } else if (!m_mapper) { - qCWarning(mirclientDebug) << "ERROR: unable to find required symbols in mirclient-debug-extension:" - << m_mirclientDebug.errorString(); - } -} - -QPoint QMirClientDebugExtension::mapSurfacePointToScreen(MirSurface *surface, const QPoint &point) -{ - if (!m_mapper) { - return point; - } - - QPoint mappedPoint; - bool status = m_mapper(surface, point.x(), point.y(), &mappedPoint.rx(), &mappedPoint.ry()); - if (status) { - return mappedPoint; - } else { - return point; - } -} diff --git a/src/plugins/platforms/mirclient/qmirclientdebugextension.h b/src/plugins/platforms/mirclient/qmirclientdebugextension.h deleted file mode 100644 index 0596561d77..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientdebugextension.h +++ /dev/null @@ -1,63 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTDEBUGEXTENSION_H -#define QMIRCLIENTDEBUGEXTENSION_H - -#include -#include -struct MirSurface; - -typedef bool (*MapperPrototype)(MirSurface* surface, int x, int y, int* screenX, int* screenY); - - -class QMirClientDebugExtension -{ -public: - QMirClientDebugExtension(); - - QPoint mapSurfacePointToScreen(MirSurface *, const QPoint &point); - -private: - QLibrary m_mirclientDebug; - MapperPrototype m_mapper; -}; - -#endif // QMIRCLIENTDEBUGEXTENSION_H diff --git a/src/plugins/platforms/mirclient/qmirclientdesktopwindow.cpp b/src/plugins/platforms/mirclient/qmirclientdesktopwindow.cpp deleted file mode 100644 index 123f805c25..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientdesktopwindow.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include "qmirclientdesktopwindow.h" - -// local -#include "qmirclientlogging.h" - -QMirClientDesktopWindow::QMirClientDesktopWindow(QWindow *window) - : QPlatformWindow(window) -{ - qCDebug(mirclient, "QMirClientDesktopWindow(window=%p)", window); -} diff --git a/src/plugins/platforms/mirclient/qmirclientdesktopwindow.h b/src/plugins/platforms/mirclient/qmirclientdesktopwindow.h deleted file mode 100644 index 3ba54db826..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientdesktopwindow.h +++ /dev/null @@ -1,53 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTDESKTOPWINDOW_H -#define QMIRCLIENTDESKTOPWINDOW_H - -#include - -// TODO Implement it. For now it's just an empty, dummy class. -class QMirClientDesktopWindow : public QPlatformWindow -{ -public: - QMirClientDesktopWindow(QWindow*); -}; - -#endif // QMIRCLIENTDESKTOPWINDOW_H diff --git a/src/plugins/platforms/mirclient/qmirclientglcontext.cpp b/src/plugins/platforms/mirclient/qmirclientglcontext.cpp deleted file mode 100644 index fc7d90d5ec..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientglcontext.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include "qmirclientglcontext.h" -#include "qmirclientlogging.h" -#include "qmirclientwindow.h" - -#include -#include -#include -#include - -Q_LOGGING_CATEGORY(mirclientGraphics, "qt.qpa.mirclient.graphics", QtWarningMsg) - -namespace { - -void printEglConfig(EGLDisplay display, EGLConfig config) -{ - Q_ASSERT(display != EGL_NO_DISPLAY); - Q_ASSERT(config != nullptr); - - const char *string = eglQueryString(display, EGL_VENDOR); - qCDebug(mirclientGraphics, "EGL vendor: %s", string); - - string = eglQueryString(display, EGL_VERSION); - qCDebug(mirclientGraphics, "EGL version: %s", string); - - string = eglQueryString(display, EGL_EXTENSIONS); - qCDebug(mirclientGraphics, "EGL extensions: %s", string); - - qCDebug(mirclientGraphics, "EGL configuration attributes:"); - q_printEglConfig(display, config); -} - -} // anonymous namespace - -QMirClientOpenGLContext::QMirClientOpenGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, - EGLDisplay display) - : QEGLPlatformContext(format, share, display, 0) -{ - if (mirclientGraphics().isDebugEnabled()) { - printEglConfig(display, eglConfig()); - } -} - -static bool needsFBOReadBackWorkaround() -{ - static bool set = false; - static bool needsWorkaround = false; - - if (Q_UNLIKELY(!set)) { - const char *rendererString = reinterpret_cast(glGetString(GL_RENDERER)); - needsWorkaround = qstrncmp(rendererString, "Mali-400", 8) == 0 - || qstrncmp(rendererString, "Mali-T7", 7) == 0 - || qstrncmp(rendererString, "PowerVR Rogue G6200", 19) == 0; - set = true; - } - - return needsWorkaround; -} - -bool QMirClientOpenGLContext::makeCurrent(QPlatformSurface* surface) -{ - const bool ret = QEGLPlatformContext::makeCurrent(surface); - - if (Q_LIKELY(ret)) { - QOpenGLContextPrivate *ctx_d = QOpenGLContextPrivate::get(context()); - if (!ctx_d->workaround_brokenFBOReadBack && needsFBOReadBackWorkaround()) { - ctx_d->workaround_brokenFBOReadBack = true; - } - } - return ret; -} - -// Following method used internally in the base class QEGLPlatformContext to access -// the egl surface of a QPlatformSurface/QMirClientWindow -EGLSurface QMirClientOpenGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) -{ - if (surface->surface()->surfaceClass() == QSurface::Window) { - return static_cast(surface)->eglSurface(); - } else { - return static_cast(surface)->pbuffer(); - } -} - -void QMirClientOpenGLContext::swapBuffers(QPlatformSurface* surface) -{ - QEGLPlatformContext::swapBuffers(surface); - - if (surface->surface()->surfaceClass() == QSurface::Window) { - // notify window on swap completion - auto platformWindow = static_cast(surface); - platformWindow->onSwapBuffersDone(); - } -} diff --git a/src/plugins/platforms/mirclient/qmirclientglcontext.h b/src/plugins/platforms/mirclient/qmirclientglcontext.h deleted file mode 100644 index 92331a6fb1..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientglcontext.h +++ /dev/null @@ -1,63 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTGLCONTEXT_H -#define QMIRCLIENTGLCONTEXT_H - -#include -#include - -#include - -class QMirClientOpenGLContext : public QEGLPlatformContext -{ -public: - QMirClientOpenGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, - EGLDisplay display); - - // QEGLPlatformContext methods. - void swapBuffers(QPlatformSurface *surface) final; - bool makeCurrent(QPlatformSurface *surface) final; - -protected: - EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) final; -}; - -#endif // QMIRCLIENTGLCONTEXT_H diff --git a/src/plugins/platforms/mirclient/qmirclientinput.cpp b/src/plugins/platforms/mirclient/qmirclientinput.cpp deleted file mode 100644 index e5319b0435..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientinput.cpp +++ /dev/null @@ -1,708 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014-2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -// Local -#include "qmirclientinput.h" -#include "qmirclientintegration.h" -#include "qmirclientnativeinterface.h" -#include "qmirclientscreen.h" -#include "qmirclientwindow.h" -#include "qmirclientlogging.h" -#include "qmirclientorientationchangeevent_p.h" - -// Qt -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -Q_LOGGING_CATEGORY(mirclientInput, "qt.qpa.mirclient.input", QtWarningMsg) - -namespace -{ - -// XKB Keysyms which do not map directly to Qt types (i.e. Unicode points) -static const uint32_t KeyTable[] = { - XKB_KEY_Escape, Qt::Key_Escape, - XKB_KEY_Tab, Qt::Key_Tab, - XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab, - XKB_KEY_BackSpace, Qt::Key_Backspace, - XKB_KEY_Return, Qt::Key_Return, - XKB_KEY_Insert, Qt::Key_Insert, - XKB_KEY_Delete, Qt::Key_Delete, - XKB_KEY_Clear, Qt::Key_Delete, - XKB_KEY_Pause, Qt::Key_Pause, - XKB_KEY_Print, Qt::Key_Print, - - XKB_KEY_Home, Qt::Key_Home, - XKB_KEY_End, Qt::Key_End, - XKB_KEY_Left, Qt::Key_Left, - XKB_KEY_Up, Qt::Key_Up, - XKB_KEY_Right, Qt::Key_Right, - XKB_KEY_Down, Qt::Key_Down, - XKB_KEY_Prior, Qt::Key_PageUp, - XKB_KEY_Next, Qt::Key_PageDown, - - XKB_KEY_Shift_L, Qt::Key_Shift, - XKB_KEY_Shift_R, Qt::Key_Shift, - XKB_KEY_Shift_Lock, Qt::Key_Shift, - XKB_KEY_Control_L, Qt::Key_Control, - XKB_KEY_Control_R, Qt::Key_Control, - XKB_KEY_Meta_L, Qt::Key_Meta, - XKB_KEY_Meta_R, Qt::Key_Meta, - XKB_KEY_Alt_L, Qt::Key_Alt, - XKB_KEY_Alt_R, Qt::Key_Alt, - XKB_KEY_Caps_Lock, Qt::Key_CapsLock, - XKB_KEY_Num_Lock, Qt::Key_NumLock, - XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock, - XKB_KEY_Super_L, Qt::Key_Super_L, - XKB_KEY_Super_R, Qt::Key_Super_R, - XKB_KEY_Menu, Qt::Key_Menu, - XKB_KEY_Hyper_L, Qt::Key_Hyper_L, - XKB_KEY_Hyper_R, Qt::Key_Hyper_R, - XKB_KEY_Help, Qt::Key_Help, - - XKB_KEY_KP_Space, Qt::Key_Space, - XKB_KEY_KP_Tab, Qt::Key_Tab, - XKB_KEY_KP_Enter, Qt::Key_Enter, - XKB_KEY_KP_Home, Qt::Key_Home, - XKB_KEY_KP_Left, Qt::Key_Left, - XKB_KEY_KP_Up, Qt::Key_Up, - XKB_KEY_KP_Right, Qt::Key_Right, - XKB_KEY_KP_Down, Qt::Key_Down, - XKB_KEY_KP_Prior, Qt::Key_PageUp, - XKB_KEY_KP_Next, Qt::Key_PageDown, - XKB_KEY_KP_End, Qt::Key_End, - XKB_KEY_KP_Begin, Qt::Key_Clear, - XKB_KEY_KP_Insert, Qt::Key_Insert, - XKB_KEY_KP_Delete, Qt::Key_Delete, - XKB_KEY_KP_Equal, Qt::Key_Equal, - XKB_KEY_KP_Multiply, Qt::Key_Asterisk, - XKB_KEY_KP_Add, Qt::Key_Plus, - XKB_KEY_KP_Separator, Qt::Key_Comma, - XKB_KEY_KP_Subtract, Qt::Key_Minus, - XKB_KEY_KP_Decimal, Qt::Key_Period, - XKB_KEY_KP_Divide, Qt::Key_Slash, - - XKB_KEY_ISO_Level3_Shift, Qt::Key_AltGr, - XKB_KEY_Multi_key, Qt::Key_Multi_key, - XKB_KEY_Codeinput, Qt::Key_Codeinput, - XKB_KEY_SingleCandidate, Qt::Key_SingleCandidate, - XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate, - XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate, - - // dead keys - XKB_KEY_dead_grave, Qt::Key_Dead_Grave, - XKB_KEY_dead_acute, Qt::Key_Dead_Acute, - XKB_KEY_dead_circumflex, Qt::Key_Dead_Circumflex, - XKB_KEY_dead_tilde, Qt::Key_Dead_Tilde, - XKB_KEY_dead_macron, Qt::Key_Dead_Macron, - XKB_KEY_dead_breve, Qt::Key_Dead_Breve, - XKB_KEY_dead_abovedot, Qt::Key_Dead_Abovedot, - XKB_KEY_dead_diaeresis, Qt::Key_Dead_Diaeresis, - XKB_KEY_dead_abovering, Qt::Key_Dead_Abovering, - XKB_KEY_dead_doubleacute, Qt::Key_Dead_Doubleacute, - XKB_KEY_dead_caron, Qt::Key_Dead_Caron, - XKB_KEY_dead_cedilla, Qt::Key_Dead_Cedilla, - XKB_KEY_dead_ogonek, Qt::Key_Dead_Ogonek, - XKB_KEY_dead_iota, Qt::Key_Dead_Iota, - XKB_KEY_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound, - XKB_KEY_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound, - XKB_KEY_dead_belowdot, Qt::Key_Dead_Belowdot, - XKB_KEY_dead_hook, Qt::Key_Dead_Hook, - XKB_KEY_dead_horn, Qt::Key_Dead_Horn, - XKB_KEY_dead_stroke, Qt::Key_Dead_Stroke, - XKB_KEY_dead_abovecomma, Qt::Key_Dead_Abovecomma, - XKB_KEY_dead_abovereversedcomma, Qt::Key_Dead_Abovereversedcomma, - XKB_KEY_dead_doublegrave, Qt::Key_Dead_Doublegrave, - XKB_KEY_dead_belowring, Qt::Key_Dead_Belowring, - XKB_KEY_dead_belowmacron, Qt::Key_Dead_Belowmacron, - XKB_KEY_dead_belowcircumflex, Qt::Key_Dead_Belowcircumflex, - XKB_KEY_dead_belowtilde, Qt::Key_Dead_Belowtilde, - XKB_KEY_dead_belowbreve, Qt::Key_Dead_Belowbreve, - XKB_KEY_dead_belowdiaeresis, Qt::Key_Dead_Belowdiaeresis, - XKB_KEY_dead_invertedbreve, Qt::Key_Dead_Invertedbreve, - XKB_KEY_dead_belowcomma, Qt::Key_Dead_Belowcomma, - XKB_KEY_dead_currency, Qt::Key_Dead_Currency, - XKB_KEY_dead_a, Qt::Key_Dead_a, - XKB_KEY_dead_A, Qt::Key_Dead_A, - XKB_KEY_dead_e, Qt::Key_Dead_e, - XKB_KEY_dead_E, Qt::Key_Dead_E, - XKB_KEY_dead_i, Qt::Key_Dead_i, - XKB_KEY_dead_I, Qt::Key_Dead_I, - XKB_KEY_dead_o, Qt::Key_Dead_o, - XKB_KEY_dead_O, Qt::Key_Dead_O, - XKB_KEY_dead_u, Qt::Key_Dead_u, - XKB_KEY_dead_U, Qt::Key_Dead_U, - XKB_KEY_dead_small_schwa, Qt::Key_Dead_Small_Schwa, - XKB_KEY_dead_capital_schwa, Qt::Key_Dead_Capital_Schwa, - XKB_KEY_dead_greek, Qt::Key_Dead_Greek, - XKB_KEY_dead_lowline, Qt::Key_Dead_Lowline, - XKB_KEY_dead_aboveverticalline, Qt::Key_Dead_Aboveverticalline, - XKB_KEY_dead_belowverticalline, Qt::Key_Dead_Belowverticalline, - XKB_KEY_dead_longsolidusoverlay, Qt::Key_Dead_Longsolidusoverlay, - - XKB_KEY_Mode_switch, Qt::Key_Mode_switch, - XKB_KEY_script_switch, Qt::Key_Mode_switch, - XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp, - XKB_KEY_XF86AudioLowerVolume, Qt::Key_VolumeDown, - XKB_KEY_XF86PowerOff, Qt::Key_PowerOff, - XKB_KEY_XF86PowerDown, Qt::Key_PowerDown, - - 0, 0 -}; - -Qt::WindowState mirSurfaceStateToWindowState(MirSurfaceState state) -{ - switch (state) { - case mir_surface_state_fullscreen: - return Qt::WindowFullScreen; - case mir_surface_state_maximized: - case mir_surface_state_vertmaximized: - case mir_surface_state_horizmaximized: - return Qt::WindowMaximized; - case mir_surface_state_minimized: - return Qt::WindowMinimized; - case mir_surface_state_hidden: - // We should be handling this state separately. - Q_ASSERT(false); - case mir_surface_state_restored: - case mir_surface_state_unknown: - default: - return Qt::WindowNoState; - } -} - -} // namespace - -class UbuntuEvent : public QEvent -{ -public: - UbuntuEvent(QMirClientWindow* window, const MirEvent *event, QEvent::Type type) - : QEvent(type), window(window) { - nativeEvent = mir_event_ref(event); - } - ~UbuntuEvent() - { - mir_event_unref(nativeEvent); - } - - QPointer window; - const MirEvent *nativeEvent; -}; - -QMirClientInput::QMirClientInput(QMirClientClientIntegration* integration) - : QObject(nullptr) - , mIntegration(integration) - , mEventFilterType(static_cast( - integration->nativeInterface())->genericEventFilterType()) - , mEventType(static_cast(QEvent::registerEventType())) - , mLastInputWindow(nullptr) -{ - // Initialize touch device. - mTouchDevice = new QTouchDevice; - mTouchDevice->setType(QTouchDevice::TouchScreen); - mTouchDevice->setCapabilities( - QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | - QTouchDevice::NormalizedPosition); - QWindowSystemInterface::registerTouchDevice(mTouchDevice); -} - -QMirClientInput::~QMirClientInput() -{ - // Qt will take care of deleting mTouchDevice. -} - -static const char* nativeEventTypeToStr(MirEventType t) -{ - switch (t) - { - case mir_event_type_key: - return "key"; - case mir_event_type_motion: - return "motion"; - case mir_event_type_surface: - return "surface"; - case mir_event_type_resize: - return "resize"; - case mir_event_type_prompt_session_state_change: - return "prompt_session_state_change"; - case mir_event_type_orientation: - return "orientation"; - case mir_event_type_close_surface: - return "close_surface"; - case mir_event_type_input: - return "input"; - case mir_event_type_keymap: - return "keymap"; - case mir_event_type_input_configuration: - return "input_configuration"; - case mir_event_type_surface_output: - return "surface_output"; - case mir_event_type_input_device_state: - return "input_device_state"; - default: - return "unknown"; - } -} - -void QMirClientInput::customEvent(QEvent* event) -{ - Q_ASSERT(QThread::currentThread() == thread()); - UbuntuEvent* ubuntuEvent = static_cast(event); - const MirEvent *nativeEvent = ubuntuEvent->nativeEvent; - - if ((ubuntuEvent->window == nullptr) || (ubuntuEvent->window->window() == nullptr)) { - qCWarning(mirclient) << "Attempted to deliver an event to a non-existent window, ignoring."; - return; - } - - // Event filtering. - long result; - if (QWindowSystemInterface::handleNativeEvent( - ubuntuEvent->window->window(), mEventFilterType, - const_cast(static_cast(nativeEvent)), &result) == true) { - qCDebug(mirclient, "event filtered out by native interface"); - return; - } - - qCDebug(mirclientInput, "customEvent(type=%s)", nativeEventTypeToStr(mir_event_get_type(nativeEvent))); - - // Event dispatching. - switch (mir_event_get_type(nativeEvent)) - { - case mir_event_type_input: - dispatchInputEvent(ubuntuEvent->window, mir_event_get_input_event(nativeEvent)); - break; - case mir_event_type_resize: - { - auto resizeEvent = mir_event_get_resize_event(nativeEvent); - - // Enable workaround for Screen rotation - auto const targetWindow = ubuntuEvent->window; - if (targetWindow) { - auto const screen = static_cast(targetWindow->screen()); - if (screen) { - screen->handleWindowSurfaceResize( - mir_resize_event_get_width(resizeEvent), - mir_resize_event_get_height(resizeEvent)); - } - - targetWindow->handleSurfaceResized( - mir_resize_event_get_width(resizeEvent), - mir_resize_event_get_height(resizeEvent)); - } - break; - } - case mir_event_type_surface: - handleSurfaceEvent(ubuntuEvent->window, mir_event_get_surface_event(nativeEvent)); - break; - case mir_event_type_surface_output: - handleSurfaceOutputEvent(ubuntuEvent->window, mir_event_get_surface_output_event(nativeEvent)); - break; - case mir_event_type_orientation: - dispatchOrientationEvent(ubuntuEvent->window->window(), mir_event_get_orientation_event(nativeEvent)); - break; - case mir_event_type_close_surface: - QWindowSystemInterface::handleCloseEvent(ubuntuEvent->window->window()); - break; - default: - qCDebug(mirclient, "unhandled event type: %d", static_cast(mir_event_get_type(nativeEvent))); - } -} - -void QMirClientInput::postEvent(QMirClientWindow *platformWindow, const MirEvent *event) -{ - QWindow *window = platformWindow->window(); - - QCoreApplication::postEvent(this, new UbuntuEvent( - platformWindow, event, mEventType)); - - if ((window->flags().testFlag(Qt::WindowTransparentForInput)) && window->parent()) { - QCoreApplication::postEvent(this, new UbuntuEvent( - static_cast(platformWindow->QPlatformWindow::parent()), - event, mEventType)); - } -} - -void QMirClientInput::dispatchInputEvent(QMirClientWindow *window, const MirInputEvent *ev) -{ - switch (mir_input_event_get_type(ev)) - { - case mir_input_event_type_key: - dispatchKeyEvent(window, ev); - break; - case mir_input_event_type_touch: - dispatchTouchEvent(window, ev); - break; - case mir_input_event_type_pointer: - dispatchPointerEvent(window, ev); - break; - default: - break; - } -} - -void QMirClientInput::dispatchTouchEvent(QMirClientWindow *window, const MirInputEvent *ev) -{ - const MirTouchEvent *tev = mir_input_event_get_touch_event(ev); - - // FIXME(loicm) Max pressure is device specific. That one is for the Samsung Galaxy Nexus. That - // needs to be fixed as soon as the compat input lib adds query support. - const float kMaxPressure = 1.28; - const QRect kWindowGeometry = window->geometry(); - QList touchPoints; - - - // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left - // as Qt::TouchPointMoved - const unsigned int kPointerCount = mir_touch_event_point_count(tev); - touchPoints.reserve(int(kPointerCount)); - for (unsigned int i = 0; i < kPointerCount; ++i) { - QWindowSystemInterface::TouchPoint touchPoint; - - const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x) + kWindowGeometry.x(); - const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y) + kWindowGeometry.y(); // see bug lp:1346633 workaround comments elsewhere - const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major); - const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor); - const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure); - touchPoint.id = mir_touch_event_id(tev, i); - touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height()); - touchPoint.area = QRectF(kX - (kW / 2.0), kY - (kH / 2.0), kW, kH); - touchPoint.pressure = kP / kMaxPressure; - - MirTouchAction touch_action = mir_touch_event_action(tev, i); - switch (touch_action) - { - case mir_touch_action_down: - mLastInputWindow = window; - touchPoint.state = Qt::TouchPointPressed; - break; - case mir_touch_action_up: - touchPoint.state = Qt::TouchPointReleased; - break; - case mir_touch_action_change: - touchPoint.state = Qt::TouchPointMoved; - break; - default: - Q_UNREACHABLE(); - } - - touchPoints.append(touchPoint); - } - - ulong timestamp = mir_input_event_get_event_time(ev) / 1000000; - QWindowSystemInterface::handleTouchEvent(window->window(), timestamp, - mTouchDevice, touchPoints); -} - -static uint32_t translateKeysym(uint32_t sym, const QString &text) { - int code = 0; - - QTextCodec *systemCodec = QTextCodec::codecForLocale(); - if (sym < 128 || (sym < 256 && systemCodec->mibEnum() == 4)) { - // upper-case key, if known - code = isprint((int)sym) ? toupper((int)sym) : 0; - } else if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F35) { - return Qt::Key_F1 + (int(sym) - XKB_KEY_F1); - } else if (text.length() == 1 && text.unicode()->unicode() > 0x1f - && text.unicode()->unicode() != 0x7f - && !(sym >= XKB_KEY_dead_grave && sym <= XKB_KEY_dead_currency)) { - code = text.unicode()->toUpper().unicode(); - } else { - for (int i = 0; KeyTable[i]; i += 2) - if (sym == KeyTable[i]) - code = KeyTable[i + 1]; - } - - return code; -} - -namespace -{ -Qt::KeyboardModifiers qt_modifiers_from_mir(MirInputEventModifiers modifiers) -{ - Qt::KeyboardModifiers q_modifiers = Qt::NoModifier; - if (modifiers & mir_input_event_modifier_shift) { - q_modifiers |= Qt::ShiftModifier; - } - if (modifiers & mir_input_event_modifier_ctrl) { - q_modifiers |= Qt::ControlModifier; - } - if (modifiers & mir_input_event_modifier_alt_left) { - q_modifiers |= Qt::AltModifier; - } - if (modifiers & mir_input_event_modifier_meta) { - q_modifiers |= Qt::MetaModifier; - } - if (modifiers & mir_input_event_modifier_alt_right) { - q_modifiers |= Qt::GroupSwitchModifier; - } - return q_modifiers; -} -} - -void QMirClientInput::dispatchKeyEvent(QMirClientWindow *window, const MirInputEvent *event) -{ - const MirKeyboardEvent *key_event = mir_input_event_get_keyboard_event(event); - - ulong timestamp = mir_input_event_get_event_time(event) / 1000000; - xkb_keysym_t xk_sym = mir_keyboard_event_key_code(key_event); - quint32 scan_code = mir_keyboard_event_scan_code(key_event); - quint32 native_modifiers = mir_keyboard_event_modifiers(key_event); - - // Key modifier and unicode index mapping. - auto modifiers = qt_modifiers_from_mir(native_modifiers); - - MirKeyboardAction action = mir_keyboard_event_action(key_event); - QEvent::Type keyType = action == mir_keyboard_action_up - ? QEvent::KeyRelease : QEvent::KeyPress; - - if (action == mir_keyboard_action_down) - mLastInputWindow = window; - - QString text; - QVarLengthArray chars(32); - { - int result = xkb_keysym_to_utf8(xk_sym, chars.data(), chars.size()); - - if (result > 0) { - text = QString::fromUtf8(chars.constData()); - } - } - int sym = translateKeysym(xk_sym, text); - - bool is_auto_rep = action == mir_keyboard_action_repeat; - - QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext(); - if (context) { - QKeyEvent qKeyEvent(keyType, sym, modifiers, scan_code, xk_sym, native_modifiers, text, is_auto_rep); - qKeyEvent.setTimestamp(timestamp); - if (context->filterEvent(&qKeyEvent)) { - qCDebug(mirclient, "key event filtered out by input context"); - return; - } - } - - QWindowSystemInterface::handleExtendedKeyEvent(window->window(), timestamp, keyType, sym, modifiers, scan_code, xk_sym, native_modifiers, text, is_auto_rep); -} - -namespace -{ -Qt::MouseButtons extract_buttons(const MirPointerEvent *pev) -{ - Qt::MouseButtons buttons = Qt::NoButton; - if (mir_pointer_event_button_state(pev, mir_pointer_button_primary)) - buttons |= Qt::LeftButton; - if (mir_pointer_event_button_state(pev, mir_pointer_button_secondary)) - buttons |= Qt::RightButton; - if (mir_pointer_event_button_state(pev, mir_pointer_button_tertiary)) - buttons |= Qt::MiddleButton; - if (mir_pointer_event_button_state(pev, mir_pointer_button_back)) - buttons |= Qt::BackButton; - if (mir_pointer_event_button_state(pev, mir_pointer_button_forward)) - buttons |= Qt::ForwardButton; - - return buttons; -} -} - -void QMirClientInput::dispatchPointerEvent(QMirClientWindow *platformWindow, const MirInputEvent *ev) -{ - const auto window = platformWindow->window(); - const auto timestamp = mir_input_event_get_event_time(ev) / 1000000; - - const auto pev = mir_input_event_get_pointer_event(ev); - const auto action = mir_pointer_event_action(pev); - - const auto modifiers = qt_modifiers_from_mir(mir_pointer_event_modifiers(pev)); - const auto localPoint = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x), - mir_pointer_event_axis_value(pev, mir_pointer_axis_y)); - - mLastInputWindow = platformWindow; - - switch (action) { - case mir_pointer_action_button_up: - case mir_pointer_action_button_down: - case mir_pointer_action_motion: - { - const float hDelta = mir_pointer_event_axis_value(pev, mir_pointer_axis_hscroll); - const float vDelta = mir_pointer_event_axis_value(pev, mir_pointer_axis_vscroll); - - if (hDelta != 0 || vDelta != 0) { - // QWheelEvent::DefaultDeltasPerStep = 120 but doesn't exist on vivid - const QPoint angleDelta(120 * hDelta, 120 * vDelta); - QWindowSystemInterface::handleWheelEvent(window, timestamp, localPoint, window->position() + localPoint, - QPoint(), angleDelta, modifiers, Qt::ScrollUpdate); - } - auto buttons = extract_buttons(pev); - QWindowSystemInterface::handleMouseEvent(window, timestamp, localPoint, window->position() + localPoint /* Should we omit global point instead? */, - buttons, modifiers); - break; - } - case mir_pointer_action_enter: - QWindowSystemInterface::handleEnterEvent(window, localPoint, window->position() + localPoint); - break; - case mir_pointer_action_leave: - QWindowSystemInterface::handleLeaveEvent(window); - break; - default: - Q_UNREACHABLE(); - } -} - -static const char* nativeOrientationDirectionToStr(MirOrientation orientation) -{ - switch (orientation) { - case mir_orientation_normal: - return "Normal"; - case mir_orientation_left: - return "Left"; - case mir_orientation_inverted: - return "Inverted"; - case mir_orientation_right: - return "Right"; - } - Q_UNREACHABLE(); -} - -void QMirClientInput::dispatchOrientationEvent(QWindow *window, const MirOrientationEvent *event) -{ - MirOrientation mir_orientation = mir_orientation_event_get_direction(event); - qCDebug(mirclientInput, "orientation direction: %s", nativeOrientationDirectionToStr(mir_orientation)); - - if (!window->screen()) { - qCDebug(mirclient, "Window has no associated screen, dropping orientation event"); - return; - } - - OrientationChangeEvent::Orientation orientation; - switch (mir_orientation) { - case mir_orientation_normal: - orientation = OrientationChangeEvent::TopUp; - break; - case mir_orientation_left: - orientation = OrientationChangeEvent::LeftUp; - break; - case mir_orientation_inverted: - orientation = OrientationChangeEvent::TopDown; - break; - case mir_orientation_right: - orientation = OrientationChangeEvent::RightUp; - break; - default: - qCDebug(mirclient, "No such orientation %d", mir_orientation); - return; - } - - // Dispatch orientation event to [Platform]Screen, as that is where Qt reads it. Screen will handle - // notifying Qt of the actual orientation change - done to prevent multiple Windows each creating - // an identical orientation change event and passing it directly to Qt. - // [Platform]Screen can also factor in the native orientation. - QCoreApplication::postEvent(static_cast(window->screen()->handle()), - new OrientationChangeEvent(OrientationChangeEvent::mType, orientation)); -} - -void QMirClientInput::handleSurfaceEvent(const QPointer &window, const MirSurfaceEvent *event) -{ - auto surfaceEventAttribute = mir_surface_event_get_attribute(event); - - switch (surfaceEventAttribute) { - case mir_surface_attrib_focus: { - window->handleSurfaceFocusChanged( - mir_surface_event_get_attribute_value(event) == mir_surface_focused); - break; - } - case mir_surface_attrib_visibility: { - window->handleSurfaceExposeChange( - mir_surface_event_get_attribute_value(event) == mir_surface_visibility_exposed); - break; - } - // Remaining attributes are ones client sets for server, and server should not override them - case mir_surface_attrib_state: { - MirSurfaceState state = static_cast(mir_surface_event_get_attribute_value(event)); - - if (state == mir_surface_state_hidden) { - window->handleSurfaceVisibilityChanged(false); - } else { - // it's visible! - window->handleSurfaceVisibilityChanged(true); - window->handleSurfaceStateChanged(mirSurfaceStateToWindowState(state)); - } - break; - } - case mir_surface_attrib_type: - case mir_surface_attrib_swapinterval: - case mir_surface_attrib_dpi: - case mir_surface_attrib_preferred_orientation: - case mir_surface_attribs: - break; - } -} - -void QMirClientInput::handleSurfaceOutputEvent(const QPointer &window, const MirSurfaceOutputEvent *event) -{ - const uint32_t outputId = mir_surface_output_event_get_output_id(event); - const int dpi = mir_surface_output_event_get_dpi(event); - const MirFormFactor formFactor = mir_surface_output_event_get_form_factor(event); - const float scale = mir_surface_output_event_get_scale(event); - - const auto screenObserver = mIntegration->screenObserver(); - QMirClientScreen *screen = screenObserver->findScreenWithId(outputId); - if (!screen) { - qCWarning(mirclient) << "Mir notified window" << window->window() << "on an unknown screen with id" << outputId; - return; - } - - screenObserver->handleScreenPropertiesChange(screen, dpi, formFactor, scale); - window->handleScreenPropertiesChange(formFactor, scale); - - if (window->screen() != screen) { - QWindowSystemInterface::handleWindowScreenChanged(window->window(), screen->screen()); - } -} diff --git a/src/plugins/platforms/mirclient/qmirclientinput.h b/src/plugins/platforms/mirclient/qmirclientinput.h deleted file mode 100644 index 263cb5e54e..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientinput.h +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014-2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTINPUT_H -#define QMIRCLIENTINPUT_H - -// Qt -#include - -#include - -class QMirClientClientIntegration; -class QMirClientWindow; - -class QMirClientInput : public QObject -{ - Q_OBJECT - -public: - QMirClientInput(QMirClientClientIntegration* integration); - virtual ~QMirClientInput(); - - // QObject methods. - void customEvent(QEvent* event) override; - - void postEvent(QMirClientWindow* window, const MirEvent *event); - QMirClientClientIntegration* integration() const { return mIntegration; } - QMirClientWindow *lastInputWindow() const {return mLastInputWindow; } - -protected: - void dispatchKeyEvent(QMirClientWindow *window, const MirInputEvent *event); - void dispatchPointerEvent(QMirClientWindow *window, const MirInputEvent *event); - void dispatchTouchEvent(QMirClientWindow *window, const MirInputEvent *event); - void dispatchInputEvent(QMirClientWindow *window, const MirInputEvent *event); - - void dispatchOrientationEvent(QWindow* window, const MirOrientationEvent *event); - void handleSurfaceEvent(const QPointer &window, const MirSurfaceEvent *event); - void handleSurfaceOutputEvent(const QPointer &window, const MirSurfaceOutputEvent *event); - -private: - QMirClientClientIntegration* mIntegration; - QTouchDevice* mTouchDevice; - const QByteArray mEventFilterType; - const QEvent::Type mEventType; - - QMirClientWindow *mLastInputWindow; -}; - -#endif // QMIRCLIENTINPUT_H diff --git a/src/plugins/platforms/mirclient/qmirclientintegration.cpp b/src/plugins/platforms/mirclient/qmirclientintegration.cpp deleted file mode 100644 index eef96ee3de..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientintegration.cpp +++ /dev/null @@ -1,411 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014-2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -// Local -#include "qmirclientintegration.h" -#include "qmirclientbackingstore.h" -#include "qmirclientclipboard.h" -#include "qmirclientdebugextension.h" -#include "qmirclientdesktopwindow.h" -#include "qmirclientglcontext.h" -#include "qmirclientinput.h" -#include "qmirclientlogging.h" -#include "qmirclientnativeinterface.h" -#include "qmirclientscreen.h" -#include "qmirclienttheme.h" -#include "qmirclientwindow.h" - -// Qt -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef QT_NO_ACCESSIBILITY -#include -#ifndef QT_NO_ACCESSIBILITY_ATSPI_BRIDGE -#include -#endif -#endif - -#include -#include - -// platform-api -#include -#include -#include - -static void resumedCallback(const UApplicationOptions */*options*/, void* context) -{ - auto integration = static_cast(context); - integration->appStateController()->setResumed(); -} - -static void aboutToStopCallback(UApplicationArchive */*archive*/, void* context) -{ - auto integration = static_cast(context); - auto inputContext = integration->inputContext(); - if (inputContext) { - inputContext->hideInputPanel(); - } else { - qCWarning(mirclient) << "aboutToStopCallback(): no input context"; - } - integration->appStateController()->setSuspended(); -} - -QMirClientClientIntegration::QMirClientClientIntegration(int argc, char **argv) - : QPlatformIntegration() - , mNativeInterface(new QMirClientNativeInterface(this)) - , mFontDb(new QGenericUnixFontDatabase) - , mServices(new QMirClientPlatformServices) - , mAppStateController(new QMirClientAppStateController) - , mScaleFactor(1.0) -{ - { - QStringList args = QCoreApplication::arguments(); - setupOptions(args); - QByteArray sessionName = generateSessionName(args); - setupDescription(sessionName); - } - - // Create new application instance - mInstance = u_application_instance_new_from_description_with_options(mDesc, mOptions); - - if (Q_UNLIKELY(!mInstance)) - qFatal("QMirClientClientIntegration: connection to Mir server failed. Check that a Mir server is\n" - "running, and the correct socket is being used and is accessible. The shell may have\n" - "rejected the incoming connection, so check its log file"); - - mMirConnection = u_application_instance_get_mir_connection(mInstance); - - // Choose the default surface format suited to the Mir platform - QSurfaceFormat defaultFormat; - defaultFormat.setRedBufferSize(8); - defaultFormat.setGreenBufferSize(8); - defaultFormat.setBlueBufferSize(8); - QSurfaceFormat::setDefaultFormat(defaultFormat); - - // Initialize EGL. - mEglNativeDisplay = mir_connection_get_egl_native_display(mMirConnection); - ASSERT((mEglDisplay = eglGetDisplay(mEglNativeDisplay)) != EGL_NO_DISPLAY); - ASSERT(eglInitialize(mEglDisplay, nullptr, nullptr) == EGL_TRUE); - - // Has debug mode been requsted, either with "-testability" switch or QT_LOAD_TESTABILITY env var - bool testability = qEnvironmentVariableIsSet("QT_LOAD_TESTABILITY"); - for (int i=1; !testability && iscreenAdded(screen); }); - connect(mScreenObserver.data(), &QMirClientScreenObserver::screenRemoved, - this, &QMirClientClientIntegration::destroyScreen); - - Q_FOREACH (auto screen, mScreenObserver->screens()) { - screenAdded(screen); - } - - // Initialize input. - mInput = new QMirClientInput(this); - mInputContext = QPlatformInputContextFactory::create(); - - // compute the scale factor - const int defaultGridUnit = 8; - int gridUnit = defaultGridUnit; - QByteArray gridUnitString = qgetenv("GRID_UNIT_PX"); - if (!gridUnitString.isEmpty()) { - bool ok; - gridUnit = gridUnitString.toInt(&ok); - if (!ok) { - gridUnit = defaultGridUnit; - } - } - mScaleFactor = static_cast(gridUnit) / defaultGridUnit; -} - -QMirClientClientIntegration::~QMirClientClientIntegration() -{ - eglTerminate(mEglDisplay); - delete mInput; - delete mInputContext; - delete mServices; -} - -QPlatformServices *QMirClientClientIntegration::services() const -{ - return mServices; -} - -void QMirClientClientIntegration::setupOptions(QStringList &args) -{ - int argc = args.size() + 1; - char **argv = new char*[argc]; - for (int i = 0; i < argc - 1; i++) - argv[i] = qstrdup(args.at(i).toLocal8Bit()); - argv[argc - 1] = nullptr; - - mOptions = u_application_options_new_from_cmd_line(argc - 1, argv); - - for (int i = 0; i < argc; i++) - delete [] argv[i]; - delete [] argv; -} - -void QMirClientClientIntegration::setupDescription(QByteArray &sessionName) -{ - mDesc = u_application_description_new(); - - UApplicationId* id = u_application_id_new_from_stringn(sessionName.data(), sessionName.count()); - u_application_description_set_application_id(mDesc, id); - - UApplicationLifecycleDelegate* delegate = u_application_lifecycle_delegate_new(); - u_application_lifecycle_delegate_set_application_resumed_cb(delegate, &resumedCallback); - u_application_lifecycle_delegate_set_application_about_to_stop_cb(delegate, &aboutToStopCallback); - u_application_lifecycle_delegate_set_context(delegate, this); - u_application_description_set_application_lifecycle_delegate(mDesc, delegate); -} - -QByteArray QMirClientClientIntegration::generateSessionName(QStringList &args) -{ - // Try to come up with some meaningful session name to uniquely identify this session, - // helping with shell debugging - - if (args.count() == 0) { - return QByteArray("QtUbuntu"); - } if (args[0].contains("qmlscene")) { - return generateSessionNameFromQmlFile(args); - } else { - // use the executable name - QFileInfo fileInfo(args[0]); - return fileInfo.fileName().toLocal8Bit(); - } -} - -QByteArray QMirClientClientIntegration::generateSessionNameFromQmlFile(QStringList &args) -{ - Q_FOREACH (QString arg, args) { - if (arg.endsWith(".qml")) { - QFileInfo fileInfo(arg); - return fileInfo.fileName().toLocal8Bit(); - } - } - - // give up - return "qmlscene"; -} - -QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* window) const -{ - if (window->type() == Qt::Desktop) { - // Desktop windows should not be backed up by a mir surface as they don't draw anything (nor should). - return new QMirClientDesktopWindow(window); - } else { - return new QMirClientWindow(window, mInput, mNativeInterface, mAppStateController.data(), - mEglDisplay, mMirConnection, mDebugExtension.data()); - } -} - -bool QMirClientClientIntegration::hasCapability(QPlatformIntegration::Capability cap) const -{ - switch (cap) { - case ThreadedOpenGL: - if (qEnvironmentVariableIsEmpty("QTUBUNTU_NO_THREADED_OPENGL")) { - return true; - } else { - qCDebug(mirclient, "disabled threaded OpenGL"); - return false; - } - - case ThreadedPixmaps: - case OpenGL: - case ApplicationState: - case MultipleWindows: - case NonFullScreenWindows: -#if QT_VERSION > QT_VERSION_CHECK(5, 5, 0) - case SwitchableWidgetComposition: -#endif - case RasterGLSurface: // needed for QQuickWidget - return true; - default: - return QPlatformIntegration::hasCapability(cap); - } -} - -QAbstractEventDispatcher *QMirClientClientIntegration::createEventDispatcher() const -{ - return createUnixEventDispatcher(); -} - -QPlatformBackingStore* QMirClientClientIntegration::createPlatformBackingStore(QWindow* window) const -{ - return new QMirClientBackingStore(window); -} - -QPlatformOpenGLContext* QMirClientClientIntegration::createPlatformOpenGLContext( - QOpenGLContext* context) const -{ - QSurfaceFormat format(context->format()); - - auto platformContext = new QMirClientOpenGLContext(format, context->shareHandle(), mEglDisplay); - if (!platformContext->isValid()) { - // Older Intel Atom-based devices only support OpenGL 1.4 compatibility profile but by default - // QML asks for at least OpenGL 2.0. The XCB GLX backend ignores this request and returns a - // 1.4 context, but the XCB EGL backend tries to honor it, and fails. The 1.4 context appears to - // have sufficient capabilities on MESA (i915) to render correctly however. So reduce the default - // requested OpenGL version to 1.0 to ensure EGL will give us a working context (lp:1549455). - static const bool isMesa = QString(eglQueryString(mEglDisplay, EGL_VENDOR)).contains(QStringLiteral("Mesa")); - if (isMesa) { - qCDebug(mirclientGraphics, "Attempting to choose OpenGL 1.4 context which may suit Mesa"); - format.setMajorVersion(1); - format.setMinorVersion(4); - delete platformContext; - platformContext = new QMirClientOpenGLContext(format, context->shareHandle(), mEglDisplay); - } - } - return platformContext; -} - -QStringList QMirClientClientIntegration::themeNames() const -{ - return QStringList(QMirClientTheme::name); -} - -QPlatformTheme* QMirClientClientIntegration::createPlatformTheme(const QString& name) const -{ - Q_UNUSED(name); - return new QMirClientTheme; -} - -QVariant QMirClientClientIntegration::styleHint(StyleHint hint) const -{ - switch (hint) { - case QPlatformIntegration::StartDragDistance: { - // default is 10 pixels (see QPlatformTheme::defaultThemeHint) - return 10.0 * mScaleFactor; - } - case QPlatformIntegration::PasswordMaskDelay: { - // return time in milliseconds - 1 second - return QVariant(1000); - } - default: - break; - } - return QPlatformIntegration::styleHint(hint); -} - -QPlatformClipboard* QMirClientClientIntegration::clipboard() const -{ - static QPlatformClipboard *clipboard = nullptr; - if (!clipboard) { - clipboard = new QMirClientClipboard; - } - return clipboard; -} - -QPlatformNativeInterface* QMirClientClientIntegration::nativeInterface() const -{ - return mNativeInterface; -} - -QPlatformOffscreenSurface *QMirClientClientIntegration::createPlatformOffscreenSurface( - QOffscreenSurface *surface) const -{ - return new QEGLPbuffer(mEglDisplay, surface->requestedFormat(), surface); -} - -void QMirClientClientIntegration::destroyScreen(QMirClientScreen *screen) -{ - // FIXME: on deleting a screen while a Window is on it, Qt will automatically - // move the window to the primaryScreen(). This will trigger a screenChanged - // signal, causing things like QQuickScreenAttached to re-fetch screen properties - // like DPI and physical size. However this is crashing, as Qt is calling virtual - // functions on QPlatformScreen, for reasons unclear. As workaround, move window - // to primaryScreen() before deleting the screen. Might be QTBUG-38650 - - QScreen *primaryScreen = QGuiApplication::primaryScreen(); - if (screen != primaryScreen->handle()) { - uint32_t movedWindowCount = 0; - Q_FOREACH (QWindow *w, QGuiApplication::topLevelWindows()) { - if (w->screen()->handle() == screen) { - QWindowSystemInterface::handleWindowScreenChanged(w, primaryScreen); - ++movedWindowCount; - } - } - if (movedWindowCount > 0) { - QWindowSystemInterface::flushWindowSystemEvents(); - } - } - - qCDebug(mirclient) << "Removing Screen with id" << screen->mirOutputId() << "and geometry" << screen->geometry(); -#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) - delete screen; -#else - QPlatformIntegration::destroyScreen(screen); -#endif -} - -#ifndef QT_NO_ACCESSIBILITY -QPlatformAccessibility *QMirClientClientIntegration::accessibility() const -{ -#if !defined(QT_NO_ACCESSIBILITY_ATSPI_BRIDGE) - if (!mAccessibility) { - Q_ASSERT_X(QCoreApplication::eventDispatcher(), "QMirClientIntegration", - "Initializing accessibility without event-dispatcher!"); - mAccessibility.reset(new QSpiAccessibleBridge()); - } -#endif - return mAccessibility.data(); -} -#endif diff --git a/src/plugins/platforms/mirclient/qmirclientintegration.h b/src/plugins/platforms/mirclient/qmirclientintegration.h deleted file mode 100644 index 035117f4da..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientintegration.h +++ /dev/null @@ -1,131 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTINTEGRATION_H -#define QMIRCLIENTINTEGRATION_H - -#include -#include - -#include "qmirclientappstatecontroller.h" -#include "qmirclientplatformservices.h" -#include "qmirclientscreenobserver.h" - -// platform-api -#include -#include - -#include - -class QMirClientDebugExtension; -class QMirClientInput; -class QMirClientNativeInterface; -class QMirClientScreen; -class MirConnection; - -class QMirClientClientIntegration : public QObject, public QPlatformIntegration -{ - Q_OBJECT - -public: - QMirClientClientIntegration(int argc, char **argv); - virtual ~QMirClientClientIntegration(); - - // QPlatformIntegration methods. - bool hasCapability(QPlatformIntegration::Capability cap) const override; - QAbstractEventDispatcher *createEventDispatcher() const override; - QPlatformNativeInterface* nativeInterface() const override; - QPlatformBackingStore* createPlatformBackingStore(QWindow* window) const override; - QPlatformOpenGLContext* createPlatformOpenGLContext(QOpenGLContext* context) const override; - QPlatformFontDatabase* fontDatabase() const override { return mFontDb; } - QStringList themeNames() const override; - QPlatformTheme* createPlatformTheme(const QString& name) const override; - QVariant styleHint(StyleHint hint) const override; - QPlatformServices *services() const override; - QPlatformWindow* createPlatformWindow(QWindow* window) const override; - QPlatformInputContext* inputContext() const override { return mInputContext; } - QPlatformClipboard* clipboard() const override; - void initialize() override; - QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override; - QPlatformAccessibility *accessibility() const override; - - // New methods. - MirConnection *mirConnection() const { return mMirConnection; } - EGLDisplay eglDisplay() const { return mEglDisplay; } - EGLNativeDisplayType eglNativeDisplay() const { return mEglNativeDisplay; } - QMirClientAppStateController *appStateController() const { return mAppStateController.data(); } - QMirClientScreenObserver *screenObserver() const { return mScreenObserver.data(); } - QMirClientDebugExtension *debugExtension() const { return mDebugExtension.data(); } - -private Q_SLOTS: - void destroyScreen(QMirClientScreen *screen); - -private: - void setupOptions(QStringList &args); - void setupDescription(QByteArray &sessionName); - static QByteArray generateSessionName(QStringList &args); - static QByteArray generateSessionNameFromQmlFile(QStringList &args); - - QMirClientNativeInterface* mNativeInterface; - QPlatformFontDatabase* mFontDb; - - QMirClientPlatformServices* mServices; - - QMirClientInput* mInput; - QPlatformInputContext* mInputContext; - mutable QScopedPointer mAccessibility; - QScopedPointer mDebugExtension; - QScopedPointer mScreenObserver; - QScopedPointer mAppStateController; - qreal mScaleFactor; - - MirConnection *mMirConnection; - - // Platform API stuff - UApplicationOptions* mOptions; - UApplicationDescription* mDesc; - UApplicationInstance* mInstance; - - // EGL related - EGLDisplay mEglDisplay{EGL_NO_DISPLAY}; - EGLNativeDisplayType mEglNativeDisplay; -}; - -#endif // QMIRCLIENTINTEGRATION_H diff --git a/src/plugins/platforms/mirclient/qmirclientlogging.h b/src/plugins/platforms/mirclient/qmirclientlogging.h deleted file mode 100644 index 4921864ced..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientlogging.h +++ /dev/null @@ -1,55 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTLOGGING_H -#define QMIRCLIENTLOGGING_H - -#include - -#define ASSERT(cond) ((!(cond)) ? qt_assert(#cond,__FILE__,__LINE__) : qt_noop()) - -Q_DECLARE_LOGGING_CATEGORY(mirclient) -Q_DECLARE_LOGGING_CATEGORY(mirclientBufferSwap) -Q_DECLARE_LOGGING_CATEGORY(mirclientInput) -Q_DECLARE_LOGGING_CATEGORY(mirclientGraphics) -Q_DECLARE_LOGGING_CATEGORY(mirclientCursor) -Q_DECLARE_LOGGING_CATEGORY(mirclientDebug) - -#endif // QMIRCLIENTLOGGING_H diff --git a/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp b/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp deleted file mode 100644 index b85e6fedfa..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -// Local -#include "qmirclientnativeinterface.h" -#include "qmirclientscreen.h" -#include "qmirclientglcontext.h" -#include "qmirclientwindow.h" - -// Qt -#include -#include -#include -#include - -class UbuntuResourceMap : public QMap -{ -public: - UbuntuResourceMap() - : QMap() { - insert("egldisplay", QMirClientNativeInterface::EglDisplay); - insert("eglcontext", QMirClientNativeInterface::EglContext); - insert("nativeorientation", QMirClientNativeInterface::NativeOrientation); - insert("display", QMirClientNativeInterface::Display); - insert("mirconnection", QMirClientNativeInterface::MirConnection); - insert("mirsurface", QMirClientNativeInterface::MirSurface); - insert("scale", QMirClientNativeInterface::Scale); - insert("formfactor", QMirClientNativeInterface::FormFactor); - } -}; - -Q_GLOBAL_STATIC(UbuntuResourceMap, ubuntuResourceMap) - -QMirClientNativeInterface::QMirClientNativeInterface(const QMirClientClientIntegration *integration) - : mIntegration(integration) - , mGenericEventFilterType(QByteArrayLiteral("Event")) - , mNativeOrientation(nullptr) -{ -} - -QMirClientNativeInterface::~QMirClientNativeInterface() -{ - delete mNativeOrientation; - mNativeOrientation = nullptr; -} - -void* QMirClientNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString) -{ - const QByteArray lowerCaseResource = resourceString.toLower(); - - if (!ubuntuResourceMap()->contains(lowerCaseResource)) { - return nullptr; - } - - const ResourceType resourceType = ubuntuResourceMap()->value(lowerCaseResource); - - if (resourceType == QMirClientNativeInterface::MirConnection) { - return mIntegration->mirConnection(); - } else { - return nullptr; - } -} - -void* QMirClientNativeInterface::nativeResourceForContext( - const QByteArray& resourceString, QOpenGLContext* context) -{ - if (!context) - return nullptr; - - const QByteArray kLowerCaseResource = resourceString.toLower(); - - if (!ubuntuResourceMap()->contains(kLowerCaseResource)) - return nullptr; - - const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource); - - if (kResourceType == QMirClientNativeInterface::EglContext) - return static_cast(context->handle())->eglContext(); - else - return nullptr; -} - -void* QMirClientNativeInterface::nativeResourceForWindow(const QByteArray& resourceString, QWindow* window) -{ - const QByteArray kLowerCaseResource = resourceString.toLower(); - if (!ubuntuResourceMap()->contains(kLowerCaseResource)) - return NULL; - const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource); - - switch (kResourceType) { - case EglDisplay: - return mIntegration->eglDisplay(); - case NativeOrientation: - // Return the device's native screen orientation. - if (window) { - QMirClientScreen *ubuntuScreen = static_cast(window->screen()->handle()); - mNativeOrientation = new Qt::ScreenOrientation(ubuntuScreen->nativeOrientation()); - } else { - QPlatformScreen *platformScreen = QGuiApplication::primaryScreen()->handle(); - mNativeOrientation = new Qt::ScreenOrientation(platformScreen->nativeOrientation()); - } - return mNativeOrientation; - case MirSurface: - if (window) { - auto ubuntuWindow = static_cast(window->handle()); - if (ubuntuWindow) { - return ubuntuWindow->mirSurface(); - } else { - return nullptr; - } - } else { - return nullptr; - } - default: - return nullptr; - } -} - -void* QMirClientNativeInterface::nativeResourceForScreen(const QByteArray& resourceString, QScreen* screen) -{ - const QByteArray kLowerCaseResource = resourceString.toLower(); - if (!ubuntuResourceMap()->contains(kLowerCaseResource)) - return NULL; - const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource); - if (!screen) - screen = QGuiApplication::primaryScreen(); - auto ubuntuScreen = static_cast(screen->handle()); - if (kResourceType == QMirClientNativeInterface::Display) { - return mIntegration->eglNativeDisplay(); - // Changes to the following properties are emitted via the QMirClientNativeInterface::screenPropertyChanged - // signal fired by QMirClientScreen. Connect to this signal for these properties updates. - // WARNING: code highly thread unsafe! - } else if (kResourceType == QMirClientNativeInterface::Scale) { - // In application code, read with: - // float scale = *reinterpret_cast(nativeResourceForScreen("scale", screen())); - return &ubuntuScreen->mScale; - } else if (kResourceType == QMirClientNativeInterface::FormFactor) { - return &ubuntuScreen->mFormFactor; - } else - return NULL; -} - -// Changes to these properties are emitted via the QMirClientNativeInterface::windowPropertyChanged -// signal fired by QMirClientWindow. Connect to this signal for these properties updates. -QVariantMap QMirClientNativeInterface::windowProperties(QPlatformWindow *window) const -{ - QVariantMap propertyMap; - auto w = static_cast(window); - if (w) { - propertyMap.insert("scale", w->scale()); - propertyMap.insert("formFactor", w->formFactor()); - } - return propertyMap; -} - -QVariant QMirClientNativeInterface::windowProperty(QPlatformWindow *window, const QString &name) const -{ - auto w = static_cast(window); - if (!w) { - return QVariant(); - } - - if (name == QStringLiteral("scale")) { - return w->scale(); - } else if (name == QStringLiteral("formFactor")) { - return w->formFactor(); - } else { - return QVariant(); - } -} - -QVariant QMirClientNativeInterface::windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const -{ - QVariant returnVal = windowProperty(window, name); - if (!returnVal.isValid()) { - return defaultValue; - } else { - return returnVal; - } -} diff --git a/src/plugins/platforms/mirclient/qmirclientnativeinterface.h b/src/plugins/platforms/mirclient/qmirclientnativeinterface.h deleted file mode 100644 index eb601de301..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientnativeinterface.h +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTNATIVEINTERFACE_H -#define QMIRCLIENTNATIVEINTERFACE_H - -#include - -#include "qmirclientintegration.h" - -class QPlatformScreen; - -class QMirClientNativeInterface : public QPlatformNativeInterface { - Q_OBJECT -public: - enum ResourceType { EglDisplay, EglContext, NativeOrientation, Display, MirConnection, MirSurface, Scale, FormFactor }; - - QMirClientNativeInterface(const QMirClientClientIntegration *integration); - ~QMirClientNativeInterface(); - - // QPlatformNativeInterface methods. - void* nativeResourceForIntegration(const QByteArray &resource) override; - void* nativeResourceForContext(const QByteArray& resourceString, - QOpenGLContext* context) override; - void* nativeResourceForWindow(const QByteArray& resourceString, - QWindow* window) override; - void* nativeResourceForScreen(const QByteArray& resourceString, - QScreen* screen) override; - - QVariantMap windowProperties(QPlatformWindow *window) const override; - QVariant windowProperty(QPlatformWindow *window, const QString &name) const override; - QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const override; - - // New methods. - const QByteArray& genericEventFilterType() const { return mGenericEventFilterType; } - -Q_SIGNALS: // New signals - void screenPropertyChanged(QPlatformScreen *screen, const QString &propertyName); - -private: - const QMirClientClientIntegration *mIntegration; - const QByteArray mGenericEventFilterType; - Qt::ScreenOrientation* mNativeOrientation; -}; - -#endif // QMIRCLIENTNATIVEINTERFACE_H diff --git a/src/plugins/platforms/mirclient/qmirclientorientationchangeevent_p.h b/src/plugins/platforms/mirclient/qmirclientorientationchangeevent_p.h deleted file mode 100644 index 5abd3262dc..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientorientationchangeevent_p.h +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTORIENTATIONCHANGEEVENT_P_H -#define QMIRCLIENTORIENTATIONCHANGEEVENT_P_H - -#include -#include "qmirclientlogging.h" - -class OrientationChangeEvent : public QEvent { -public: - enum Orientation { TopUp, LeftUp, TopDown, RightUp }; - - OrientationChangeEvent(QEvent::Type type, Orientation orientation) - : QEvent(type) - , mOrientation(orientation) - { - } - - static const QEvent::Type mType; - Orientation mOrientation; -}; - -#endif // QMIRCLIENTORIENTATIONCHANGEEVENT_P_H diff --git a/src/plugins/platforms/mirclient/qmirclientplatformservices.cpp b/src/plugins/platforms/mirclient/qmirclientplatformservices.cpp deleted file mode 100644 index 1ccd57fc28..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientplatformservices.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include "qmirclientplatformservices.h" - -#include - -#include -#include - -bool QMirClientPlatformServices::openUrl(const QUrl &url) -{ - return callDispatcher(url); -} - -bool QMirClientPlatformServices::openDocument(const QUrl &url) -{ - return callDispatcher(url); -} - -bool QMirClientPlatformServices::callDispatcher(const QUrl &url) -{ - UAUrlDispatcherSession* session = ua_url_dispatcher_session(); - if (!session) - return false; - - ua_url_dispatcher_session_open(session, url.toEncoded().constData(), NULL, NULL); - - free(session); - - // We are returning true here because the other option - // is spawning a nested event loop and wait for the - // callback. But there is no guarantee on how fast - // the callback is going to be so we prefer to avoid the - // nested event loop. Long term plan is improve Qt API - // to support an async openUrl - return true; -} diff --git a/src/plugins/platforms/mirclient/qmirclientplatformservices.h b/src/plugins/platforms/mirclient/qmirclientplatformservices.h deleted file mode 100644 index a1cd5758ca..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientplatformservices.h +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTPLATFORMSERVICES_H -#define QMIRCLIENTPLATFORMSERVICES_H - -#include -#include -#include - -class QMirClientPlatformServices : public QPlatformServices { -public: - bool openUrl(const QUrl &url) override; - bool openDocument(const QUrl &url) override; - -private: - bool callDispatcher(const QUrl &url); -}; - -#endif // QMIRCLIENTPLATFORMSERVICES_H diff --git a/src/plugins/platforms/mirclient/qmirclientplugin.cpp b/src/plugins/platforms/mirclient/qmirclientplugin.cpp deleted file mode 100644 index fc44edfe40..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientplugin.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include "qmirclientplugin.h" -#include "qmirclientintegration.h" -#include "qmirclientlogging.h" - -Q_LOGGING_CATEGORY(mirclient, "qt.qpa.mirclient", QtWarningMsg) - -QPlatformIntegration *QMirClientIntegrationPlugin::create(const QString &system, - const QStringList &/*paramList*/, - int &argc, char **argv) -{ - if (system.toLower() == QLatin1String("mirclient")) { - return new QMirClientClientIntegration(argc, argv); - } else { - return 0; - } -} diff --git a/src/plugins/platforms/mirclient/qmirclientplugin.h b/src/plugins/platforms/mirclient/qmirclientplugin.h deleted file mode 100644 index 207d97b5af..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientplugin.h +++ /dev/null @@ -1,56 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTPLUGIN_H -#define QMIRCLIENTPLUGIN_H - -#include - -class QMirClientIntegrationPlugin : public QPlatformIntegrationPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "mirclient.json") - -public: - QPlatformIntegration *create(const QString &system, const QStringList ¶mList, - int &argc, char **argv) override; -}; - -#endif // QMIRCLIENTPLUGIN_H diff --git a/src/plugins/platforms/mirclient/qmirclientscreen.cpp b/src/plugins/platforms/mirclient/qmirclientscreen.cpp deleted file mode 100644 index cc8db830aa..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientscreen.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014-2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -// local -#include "qmirclientscreen.h" -#include "qmirclientlogging.h" -#include "qmirclientorientationchangeevent_p.h" -#include "qmirclientnativeinterface.h" - -#include - -// Qt -#include -#include -#include -#include -#include -#include - -#include - -static const int overrideDevicePixelRatio = qgetenv("QT_DEVICE_PIXEL_RATIO").toInt(); - -static const char *orientationToStr(Qt::ScreenOrientation orientation) { - switch (orientation) { - case Qt::PrimaryOrientation: - return "primary"; - case Qt::PortraitOrientation: - return "portrait"; - case Qt::LandscapeOrientation: - return "landscape"; - case Qt::InvertedPortraitOrientation: - return "inverted portrait"; - case Qt::InvertedLandscapeOrientation: - return "inverted landscape"; - } - Q_UNREACHABLE(); -} - -const QEvent::Type OrientationChangeEvent::mType = - static_cast(QEvent::registerEventType()); - - -QMirClientScreen::QMirClientScreen(const MirOutput *output, MirConnection *connection) - : mDevicePixelRatio(1.0) - , mFormat(QImage::Format_RGB32) - , mDepth(32) - , mDpi{0} - , mFormFactor{mir_form_factor_unknown} - , mScale{1.0} - , mOutputId(0) - , mCursor(connection) -{ - setMirOutput(output); -} - -QMirClientScreen::~QMirClientScreen() -{ -} - -void QMirClientScreen::customEvent(QEvent* event) { - Q_ASSERT(QThread::currentThread() == thread()); - - OrientationChangeEvent* oReadingEvent = static_cast(event); - switch (oReadingEvent->mOrientation) { - case OrientationChangeEvent::LeftUp: { - mCurrentOrientation = (screen()->primaryOrientation() == Qt::LandscapeOrientation) ? - Qt::InvertedPortraitOrientation : Qt::LandscapeOrientation; - break; - } - case OrientationChangeEvent::TopUp: { - mCurrentOrientation = (screen()->primaryOrientation() == Qt::LandscapeOrientation) ? - Qt::LandscapeOrientation : Qt::PortraitOrientation; - break; - } - case OrientationChangeEvent::RightUp: { - mCurrentOrientation = (screen()->primaryOrientation() == Qt::LandscapeOrientation) ? - Qt::PortraitOrientation : Qt::InvertedLandscapeOrientation; - break; - } - case OrientationChangeEvent::TopDown: { - mCurrentOrientation = (screen()->primaryOrientation() == Qt::LandscapeOrientation) ? - Qt::InvertedLandscapeOrientation : Qt::InvertedPortraitOrientation; - break; - } - } - - // Raise the event signal so that client apps know the orientation changed - qCDebug(mirclient, "QMirClientScreen::customEvent - handling orientation change to %s", orientationToStr(mCurrentOrientation)); - QWindowSystemInterface::handleScreenOrientationChange(screen(), mCurrentOrientation); -} - -void QMirClientScreen::handleWindowSurfaceResize(int windowWidth, int windowHeight) -{ - if ((windowWidth > windowHeight && mGeometry.width() < mGeometry.height()) - || (windowWidth < windowHeight && mGeometry.width() > mGeometry.height())) { - - // The window aspect ratio differ's from the screen one. This means that - // unity8 has rotated the window in its scene. - // As there's no way to express window rotation in Qt's API, we have - // Flip QScreen's dimensions so that orientation properties match - // (primaryOrientation particularly). - // FIXME: This assumes a phone scenario. Won't work, or make sense, - // on the desktop - - QRect currGeometry = mGeometry; - mGeometry.setWidth(currGeometry.height()); - mGeometry.setHeight(currGeometry.width()); - - qCDebug(mirclient, "QMirClientScreen::handleWindowSurfaceResize - new screen geometry (w=%d, h=%d)", - mGeometry.width(), mGeometry.height()); - QWindowSystemInterface::handleScreenGeometryChange(screen(), - mGeometry /* newGeometry */, - mGeometry /* newAvailableGeometry */); - - if (mGeometry.width() < mGeometry.height()) { - mCurrentOrientation = Qt::PortraitOrientation; - } else { - mCurrentOrientation = Qt::LandscapeOrientation; - } - qCDebug(mirclient, "QMirClientScreen::handleWindowSurfaceResize - new orientation %s",orientationToStr(mCurrentOrientation)); - QWindowSystemInterface::handleScreenOrientationChange(screen(), mCurrentOrientation); - } -} - -void QMirClientScreen::setMirOutput(const MirOutput *output) -{ - // Physical screen size (in mm) - mPhysicalSize.setWidth(mir_output_get_physical_width_mm(output)); - mPhysicalSize.setHeight(mir_output_get_physical_height_mm(output)); - - // Pixel Format -// mFormat = qImageFormatFromMirPixelFormat(mir_output_get_current_pixel_format(output)); // GERRY: TODO - - // Pixel depth - mDepth = 8 * MIR_BYTES_PER_PIXEL(mir_output_get_current_pixel_format(output)); - - // Mode = Resolution & refresh rate - const MirOutputMode *mode = mir_output_get_current_mode(output); - mNativeGeometry.setX(mir_output_get_position_x(output)); - mNativeGeometry.setY(mir_output_get_position_y(output)); - mNativeGeometry.setWidth(mir_output_mode_get_width(mode)); - mNativeGeometry.setHeight(mir_output_mode_get_height(mode)); - - mRefreshRate = mir_output_mode_get_refresh_rate(mode); - - // UI scale & DPR - mScale = mir_output_get_scale_factor(output); - if (overrideDevicePixelRatio > 0) { - mDevicePixelRatio = overrideDevicePixelRatio; - } else { - mDevicePixelRatio = 1.0; // FIXME - need to determine suitable DPR for the specified scale - } - - mFormFactor = mir_output_get_form_factor(output); - - mOutputId = mir_output_get_id(output); - - mGeometry.setX(mNativeGeometry.x()); - mGeometry.setY(mNativeGeometry.y()); - mGeometry.setWidth(mNativeGeometry.width()); - mGeometry.setHeight(mNativeGeometry.height()); - - // Set the default orientation based on the initial screen dimensions. - mNativeOrientation = (mGeometry.width() >= mGeometry.height()) ? Qt::LandscapeOrientation : Qt::PortraitOrientation; - - // If it's a landscape device (i.e. some tablets), start in landscape, otherwise portrait - mCurrentOrientation = (mNativeOrientation == Qt::LandscapeOrientation) ? Qt::LandscapeOrientation : Qt::PortraitOrientation; -} - -void QMirClientScreen::updateMirOutput(const MirOutput *output) -{ - auto oldRefreshRate = mRefreshRate; - auto oldScale = mScale; - auto oldFormFactor = mFormFactor; - auto oldGeometry = mGeometry; - - setMirOutput(output); - - // Emit change signals in particular order - if (oldGeometry != mGeometry) { - QWindowSystemInterface::handleScreenGeometryChange(screen(), - mGeometry /* newGeometry */, - mGeometry /* newAvailableGeometry */); - } - - if (!qFuzzyCompare(mRefreshRate, oldRefreshRate)) { - QWindowSystemInterface::handleScreenRefreshRateChange(screen(), mRefreshRate); - } - - auto nativeInterface = static_cast(qGuiApp->platformNativeInterface()); - if (!qFuzzyCompare(mScale, oldScale)) { - nativeInterface->screenPropertyChanged(this, QStringLiteral("scale")); - } - if (mFormFactor != oldFormFactor) { - nativeInterface->screenPropertyChanged(this, QStringLiteral("formFactor")); - } -} - -void QMirClientScreen::setAdditionalMirDisplayProperties(float scale, MirFormFactor formFactor, int dpi) -{ - if (mDpi != dpi) { - mDpi = dpi; - QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(), dpi, dpi); - } - - auto nativeInterface = static_cast(qGuiApp->platformNativeInterface()); - if (!qFuzzyCompare(mScale, scale)) { - mScale = scale; - nativeInterface->screenPropertyChanged(this, QStringLiteral("scale")); - } - if (mFormFactor != formFactor) { - mFormFactor = formFactor; - nativeInterface->screenPropertyChanged(this, QStringLiteral("formFactor")); - } -} - -QDpi QMirClientScreen::logicalDpi() const -{ - if (mDpi > 0) { - return QDpi(mDpi, mDpi); - } else { - return QPlatformScreen::logicalDpi(); - } -} diff --git a/src/plugins/platforms/mirclient/qmirclientscreen.h b/src/plugins/platforms/mirclient/qmirclientscreen.h deleted file mode 100644 index b31cba1964..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientscreen.h +++ /dev/null @@ -1,106 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014-2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTSCREEN_H -#define QMIRCLIENTSCREEN_H - -#include -#include - -#include // just for MirFormFactor enum - -#include "qmirclientcursor.h" - -struct MirConnection; -struct MirOutput; - -class QMirClientScreen : public QObject, public QPlatformScreen -{ - Q_OBJECT -public: - QMirClientScreen(const MirOutput *output, MirConnection *connection); - virtual ~QMirClientScreen(); - - // QPlatformScreen methods. - QImage::Format format() const override { return mFormat; } - int depth() const override { return mDepth; } - QRect geometry() const override { return mGeometry; } - QRect availableGeometry() const override { return mGeometry; } - QSizeF physicalSize() const override { return mPhysicalSize; } - qreal devicePixelRatio() const override { return mDevicePixelRatio; } - QDpi logicalDpi() const override; - Qt::ScreenOrientation nativeOrientation() const override { return mNativeOrientation; } - Qt::ScreenOrientation orientation() const override { return mNativeOrientation; } - QPlatformCursor *cursor() const override { return const_cast(&mCursor); } - - // Additional Screen properties from Mir - int mirOutputId() const { return mOutputId; } - MirFormFactor formFactor() const { return mFormFactor; } - float scale() const { return mScale; } - - // Internally used methods - void updateMirOutput(const MirOutput *output); - void setAdditionalMirDisplayProperties(float scale, MirFormFactor formFactor, int dpi); - void handleWindowSurfaceResize(int width, int height); - - // QObject methods. - void customEvent(QEvent* event) override; - -private: - void setMirOutput(const MirOutput *output); - - QRect mGeometry, mNativeGeometry; - QSizeF mPhysicalSize; - qreal mDevicePixelRatio; - Qt::ScreenOrientation mNativeOrientation; - Qt::ScreenOrientation mCurrentOrientation; - QImage::Format mFormat; - int mDepth; - int mDpi; - qreal mRefreshRate; - MirFormFactor mFormFactor; - float mScale; - int mOutputId; - QMirClientCursor mCursor; - - friend class QMirClientNativeInterface; -}; - -#endif // QMIRCLIENTSCREEN_H diff --git a/src/plugins/platforms/mirclient/qmirclientscreenobserver.cpp b/src/plugins/platforms/mirclient/qmirclientscreenobserver.cpp deleted file mode 100644 index 792aeca351..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientscreenobserver.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include "qmirclientscreenobserver.h" -#include "qmirclientscreen.h" -#include "qmirclientwindow.h" -#include "qmirclientlogging.h" - -// Qt -#include -#include - -// Mir -#include -#include - -#include - -namespace { - static void displayConfigurationChangedCallback(MirConnection */*connection*/, void* context) - { - ASSERT(context != NULL); - QMirClientScreenObserver *observer = static_cast(context); - QMetaObject::invokeMethod(observer, "update"); - } - - const char *mirFormFactorToStr(MirFormFactor formFactor) - { - switch (formFactor) { - case mir_form_factor_unknown: return "unknown"; - case mir_form_factor_phone: return "phone"; - case mir_form_factor_tablet: return "tablet"; - case mir_form_factor_monitor: return "monitor"; - case mir_form_factor_tv: return "tv"; - case mir_form_factor_projector: return "projector"; - } - Q_UNREACHABLE(); - } -} // anonymous namespace - -QMirClientScreenObserver::QMirClientScreenObserver(MirConnection *mirConnection) - : mMirConnection(mirConnection) -{ - mir_connection_set_display_config_change_callback(mirConnection, ::displayConfigurationChangedCallback, this); - update(); -} - -void QMirClientScreenObserver::update() -{ - // Wrap MirDisplayConfiguration to always delete when out of scope - auto configDeleter = [](MirDisplayConfig *config) { mir_display_config_release(config); }; - using configUp = std::unique_ptr; - configUp displayConfig(mir_connection_create_display_configuration(mMirConnection), configDeleter); - - // Mir only tells us something changed, it is up to us to figure out what. - QList newScreenList; - QList oldScreenList = mScreenList; - mScreenList.clear(); - - for (int i = 0; i < mir_display_config_get_num_outputs(displayConfig.get()); i++) { - const MirOutput *output = mir_display_config_get_output(displayConfig.get(), i); - if (mir_output_is_enabled(output)) { - QMirClientScreen *screen = findScreenWithId(oldScreenList, mir_output_get_id(output)); - if (screen) { // we've already set up this display before - screen->updateMirOutput(output); - oldScreenList.removeAll(screen); - } else { - // new display, so create QMirClientScreen for it - screen = new QMirClientScreen(output, mMirConnection); - newScreenList.append(screen); - qCDebug(mirclient) << "Added Screen with id" << mir_output_get_id(output) - << "and geometry" << screen->geometry(); - } - mScreenList.append(screen); - } - } - - // Announce old & unused Screens, should be deleted by the slot - Q_FOREACH (const auto screen, oldScreenList) { - Q_EMIT screenRemoved(screen); - } - - /* - * Mir's MirDisplayOutput does not include formFactor or scale for some reason, but Qt - * will want that information on creating the QScreen. Only way we get that info is when - * Mir positions a Window on that Screen. See "handleScreenPropertiesChange" method - */ - - // Announce new Screens - Q_FOREACH (const auto screen, newScreenList) { - Q_EMIT screenAdded(screen); - } - - qCDebug(mirclient) << "======================================="; - for (auto screen: mScreenList) { - qCDebug(mirclient) << screen << "- id:" << screen->mirOutputId() - << "geometry:" << screen->geometry() - << "form factor:" << mirFormFactorToStr(screen->formFactor()) - << "scale:" << screen->scale(); - } - qCDebug(mirclient) << "======================================="; -} - -QMirClientScreen *QMirClientScreenObserver::findScreenWithId(int id) -{ - return findScreenWithId(mScreenList, id); -} - -QMirClientScreen *QMirClientScreenObserver::findScreenWithId(const QList &list, int id) -{ - Q_FOREACH (const auto screen, list) { - if (screen->mirOutputId() == id) { - return screen; - } - } - return nullptr; -} - -void QMirClientScreenObserver::handleScreenPropertiesChange(QMirClientScreen *screen, int dpi, - MirFormFactor formFactor, float scale) -{ - screen->setAdditionalMirDisplayProperties(scale, formFactor, dpi); -} - diff --git a/src/plugins/platforms/mirclient/qmirclientscreenobserver.h b/src/plugins/platforms/mirclient/qmirclientscreenobserver.h deleted file mode 100644 index ad927319c1..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientscreenobserver.h +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTSCREENOBSERVER_H -#define QMIRCLIENTSCREENOBSERVER_H - -#include - -#include - -class QMirClientScreen; - -class QMirClientScreenObserver : public QObject -{ - Q_OBJECT - -public: - QMirClientScreenObserver(MirConnection *connection); - - QList screens() const { return mScreenList; } - QMirClientScreen *findScreenWithId(int id); - - void handleScreenPropertiesChange(QMirClientScreen *screen, int dpi, - MirFormFactor formFactor, float scale); - -Q_SIGNALS: - void screenAdded(QMirClientScreen *screen); - void screenRemoved(QMirClientScreen *screen); - -private Q_SLOTS: - void update(); - -private: - QMirClientScreen *findScreenWithId(const QList &list, int id); - void removeScreen(QMirClientScreen *screen); - - MirConnection *mMirConnection; - QList mScreenList; -}; - -#endif // QMIRCLIENTSCREENOBSERVER_H diff --git a/src/plugins/platforms/mirclient/qmirclienttheme.cpp b/src/plugins/platforms/mirclient/qmirclienttheme.cpp deleted file mode 100644 index dcfef7ca67..0000000000 --- a/src/plugins/platforms/mirclient/qmirclienttheme.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include "qmirclienttheme.h" - -#include - -const char *QMirClientTheme::name = "ubuntu"; - -QMirClientTheme::QMirClientTheme() -{ -} - -QMirClientTheme::~QMirClientTheme() -{ -} - -QVariant QMirClientTheme::themeHint(ThemeHint hint) const -{ - if (hint == QPlatformTheme::SystemIconThemeName) { - QByteArray iconTheme = qgetenv("QTUBUNTU_ICON_THEME"); - if (iconTheme.isEmpty()) { - return QVariant(QStringLiteral("ubuntu-mobile")); - } else { - return QVariant(QString(iconTheme)); - } - } else { - return QGenericUnixTheme::themeHint(hint); - } -} diff --git a/src/plugins/platforms/mirclient/qmirclienttheme.h b/src/plugins/platforms/mirclient/qmirclienttheme.h deleted file mode 100644 index 4bab1d0ee0..0000000000 --- a/src/plugins/platforms/mirclient/qmirclienttheme.h +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTTHEME_H -#define QMIRCLIENTTHEME_H - -#include - -class QMirClientTheme : public QGenericUnixTheme -{ -public: - static const char* name; - QMirClientTheme(); - virtual ~QMirClientTheme(); - - // From QPlatformTheme - QVariant themeHint(ThemeHint hint) const override; -}; - -#endif // QMIRCLIENTTHEME_H diff --git a/src/plugins/platforms/mirclient/qmirclientwindow.cpp b/src/plugins/platforms/mirclient/qmirclientwindow.cpp deleted file mode 100644 index decd21516e..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientwindow.cpp +++ /dev/null @@ -1,968 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014-2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -// Local -#include "qmirclientwindow.h" -#include "qmirclientdebugextension.h" -#include "qmirclientnativeinterface.h" -#include "qmirclientinput.h" -#include "qmirclientintegration.h" -#include "qmirclientscreen.h" -#include "qmirclientlogging.h" - -#include -#include - -// Qt -#include -#include -#include -#include -#include - -// Platform API -#include - -#include - -Q_LOGGING_CATEGORY(mirclientBufferSwap, "qt.qpa.mirclient.bufferSwap", QtWarningMsg) - -namespace -{ -const Qt::WindowType LowChromeWindowHint = (Qt::WindowType)0x00800000; - -// FIXME: this used to be defined by platform-api, but it's been removed in v3. Change ubuntu-keyboard to use -// a different enum for window roles. -enum UAUiWindowRole { - U_MAIN_ROLE = 1, - U_DASH_ROLE, - U_INDICATOR_ROLE, - U_NOTIFICATIONS_ROLE, - U_GREETER_ROLE, - U_LAUNCHER_ROLE, - U_ON_SCREEN_KEYBOARD_ROLE, - U_SHUTDOWN_DIALOG_ROLE, -}; - -struct MirSpecDeleter -{ - void operator()(MirSurfaceSpec *spec) { mir_surface_spec_release(spec); } -}; - -using Spec = std::unique_ptr; - -EGLNativeWindowType nativeWindowFor(MirSurface *surf) -{ - auto stream = mir_surface_get_buffer_stream(surf); - return reinterpret_cast(mir_buffer_stream_get_egl_native_window(stream)); -} - -const char *qtWindowStateToStr(Qt::WindowState state) -{ - switch (state) { - case Qt::WindowNoState: - return "NoState"; - case Qt::WindowFullScreen: - return "FullScreen"; - case Qt::WindowMaximized: - return "Maximized"; - case Qt::WindowMinimized: - return "Minimized"; - case Qt::WindowActive: - return "Active"; - } - Q_UNREACHABLE(); -} - -const char *mirSurfaceStateToStr(MirSurfaceState surfaceState) -{ - switch (surfaceState) { - case mir_surface_state_unknown: return "unknown"; - case mir_surface_state_restored: return "restored"; - case mir_surface_state_minimized: return "minimized"; - case mir_surface_state_maximized: return "vertmaximized"; - case mir_surface_state_vertmaximized: return "vertmaximized"; - case mir_surface_state_fullscreen: return "fullscreen"; - case mir_surface_state_horizmaximized: return "horizmaximized"; - case mir_surface_state_hidden: return "hidden"; - case mir_surface_states: Q_UNREACHABLE(); - } - Q_UNREACHABLE(); -} - -const char *mirPixelFormatToStr(MirPixelFormat pixelFormat) -{ - switch (pixelFormat) { - case mir_pixel_format_invalid: return "invalid"; - case mir_pixel_format_abgr_8888: return "ABGR8888"; - case mir_pixel_format_xbgr_8888: return "XBGR8888"; - case mir_pixel_format_argb_8888: return "ARGB8888"; - case mir_pixel_format_xrgb_8888: return "XRGB8888"; - case mir_pixel_format_bgr_888: return "BGR888"; - case mir_pixel_format_rgb_888: return "RGB888"; - case mir_pixel_format_rgb_565: return "RGB565"; - case mir_pixel_format_rgba_5551: return "RGBA5551"; - case mir_pixel_format_rgba_4444: return "RGBA4444"; - case mir_pixel_formats: Q_UNREACHABLE(); - } - Q_UNREACHABLE(); -} - -const char *mirSurfaceTypeToStr(MirSurfaceType type) -{ - switch (type) { - case mir_surface_type_normal: return "Normal"; /**< AKA "regular" */ - case mir_surface_type_utility: return "Utility"; /**< AKA "floating regular" */ - case mir_surface_type_dialog: return "Dialog"; - case mir_surface_type_gloss: return "Gloss"; - case mir_surface_type_freestyle: return "Freestyle"; - case mir_surface_type_menu: return "Menu"; - case mir_surface_type_inputmethod: return "Input Method"; /**< AKA "OSK" or handwriting etc. */ - case mir_surface_type_satellite: return "Satellite"; /**< AKA "toolbox"/"toolbar" */ - case mir_surface_type_tip: return "Tip"; /**< AKA "tooltip" */ - case mir_surface_types: Q_UNREACHABLE(); - } - return ""; -} - -MirSurfaceState qtWindowStateToMirSurfaceState(Qt::WindowState state) -{ - switch (state) { - case Qt::WindowNoState: - case Qt::WindowActive: - return mir_surface_state_restored; - case Qt::WindowFullScreen: - return mir_surface_state_fullscreen; - case Qt::WindowMaximized: - return mir_surface_state_maximized; - case Qt::WindowMinimized: - return mir_surface_state_minimized; - } - return mir_surface_state_unknown; // should never be reached -} - -MirSurfaceType qtWindowTypeToMirSurfaceType(Qt::WindowType type) -{ - switch (type & Qt::WindowType_Mask) { - case Qt::Dialog: - return mir_surface_type_dialog; - case Qt::Sheet: - case Qt::Drawer: - return mir_surface_type_utility; - case Qt::Popup: - case Qt::Tool: - return mir_surface_type_menu; - case Qt::ToolTip: - return mir_surface_type_tip; - case Qt::SplashScreen: - return mir_surface_type_freestyle; - case Qt::Window: - default: - return mir_surface_type_normal; - } -} - -WId makeId() -{ - static int id = 1; - return id++; -} - -UAUiWindowRole roleFor(QWindow *window) -{ - QVariant roleVariant = window->property("role"); - if (!roleVariant.isValid()) - return U_MAIN_ROLE; - - uint role = roleVariant.toUInt(); - if (role < U_MAIN_ROLE || role > U_SHUTDOWN_DIALOG_ROLE) - return U_MAIN_ROLE; - - return static_cast(role); -} - -QMirClientWindow *transientParentFor(QWindow *window) -{ - QWindow *parent = window->transientParent(); - return parent ? static_cast(parent->handle()) : nullptr; -} - -bool requiresParent(const MirSurfaceType type) -{ - switch (type) { - case mir_surface_type_dialog: //FIXME - not quite what the specification dictates, but is what Mir's api dictates - case mir_surface_type_utility: - case mir_surface_type_gloss: - case mir_surface_type_menu: - case mir_surface_type_satellite: - case mir_surface_type_tip: - return true; - default: - return false; - } -} - -bool requiresParent(const Qt::WindowType type) -{ - return requiresParent(qtWindowTypeToMirSurfaceType(type)); -} - -bool isMovable(const Qt::WindowType type) -{ - auto mirType = qtWindowTypeToMirSurfaceType(type); - switch (mirType) { - case mir_surface_type_menu: - case mir_surface_type_tip: - return true; - default: - return false; - } -} - -Spec makeSurfaceSpec(QWindow *window, MirPixelFormat pixelFormat, QMirClientWindow *parentWindowHandle, - MirConnection *connection) -{ - const auto geometry = window->geometry(); - const int width = geometry.width() > 0 ? geometry.width() : 1; - const int height = geometry.height() > 0 ? geometry.height() : 1; - auto type = qtWindowTypeToMirSurfaceType(window->type()); - - if (U_ON_SCREEN_KEYBOARD_ROLE == roleFor(window)) { - type = mir_surface_type_inputmethod; - } - - MirRectangle location{geometry.x(), geometry.y(), 0, 0}; - MirSurface *parent = nullptr; - if (parentWindowHandle) { - parent = parentWindowHandle->mirSurface(); - // Qt uses absolute positioning, but Mir positions surfaces relative to parent. - location.top -= parentWindowHandle->geometry().top(); - location.left -= parentWindowHandle->geometry().left(); - } - - Spec spec; - - switch (type) { - case mir_surface_type_menu: - spec = Spec{mir_connection_create_spec_for_menu(connection, width, height, pixelFormat, parent, - &location, mir_edge_attachment_any)}; - break; - case mir_surface_type_dialog: - spec = Spec{mir_connection_create_spec_for_modal_dialog(connection, width, height, pixelFormat, parent)}; - break; - case mir_surface_type_utility: - spec = Spec{mir_connection_create_spec_for_dialog(connection, width, height, pixelFormat)}; - break; - case mir_surface_type_tip: -#if MIR_CLIENT_VERSION < MIR_VERSION_NUMBER(3, 4, 0) - spec = Spec{mir_connection_create_spec_for_tooltip(connection, width, height, pixelFormat, parent, - &location)}; -#else - spec = Spec{mir_connection_create_spec_for_tip(connection, width, height, pixelFormat, parent, - &location, mir_edge_attachment_any)}; -#endif - break; - case mir_surface_type_inputmethod: - spec = Spec{mir_connection_create_spec_for_input_method(connection, width, height, pixelFormat)}; - break; - default: - spec = Spec{mir_connection_create_spec_for_normal_surface(connection, width, height, pixelFormat)}; - break; - } - - qCDebug(mirclient, "makeSurfaceSpec(window=%p): %s spec (type=0x%x, position=(%d, %d)px, size=(%dx%d)px)", - window, mirSurfaceTypeToStr(type), window->type(), location.left, location.top, width, height); - - return std::move(spec); -} - -void setSizingConstraints(MirSurfaceSpec *spec, const QSize& minSize, const QSize& maxSize, const QSize& increment) -{ - mir_surface_spec_set_min_width(spec, minSize.width()); - mir_surface_spec_set_min_height(spec, minSize.height()); - if (maxSize.width() >= minSize.width()) { - mir_surface_spec_set_max_width(spec, maxSize.width()); - } - if (maxSize.height() >= minSize.height()) { - mir_surface_spec_set_max_height(spec, maxSize.height()); - } - if (increment.width() > 0) { - mir_surface_spec_set_width_increment(spec, increment.width()); - } - if (increment.height() > 0) { - mir_surface_spec_set_height_increment(spec, increment.height()); - } -} - -MirSurface *createMirSurface(QWindow *window, int mirOutputId, QMirClientWindow *parentWindowHandle, - MirPixelFormat pixelFormat, MirConnection *connection, - mir_surface_event_callback inputCallback, void *inputContext) -{ - auto spec = makeSurfaceSpec(window, pixelFormat, parentWindowHandle, connection); - - // Install event handler as early as possible - mir_surface_spec_set_event_handler(spec.get(), inputCallback, inputContext); - - const auto title = window->title().toUtf8(); - mir_surface_spec_set_name(spec.get(), title.constData()); - - setSizingConstraints(spec.get(), window->minimumSize(), window->maximumSize(), window->sizeIncrement()); - - if (window->windowState() == Qt::WindowFullScreen) { - mir_surface_spec_set_fullscreen_on_output(spec.get(), mirOutputId); - } - - if (window->flags() & LowChromeWindowHint) { - mir_surface_spec_set_shell_chrome(spec.get(), mir_shell_chrome_low); - } - - if (!window->isVisible()) { - mir_surface_spec_set_state(spec.get(), mir_surface_state_hidden); - } - - auto surface = mir_surface_create_sync(spec.get()); - Q_ASSERT(mir_surface_is_valid(surface)); - return surface; -} - -QMirClientWindow *getParentIfNecessary(QWindow *window, QMirClientInput *input) -{ - QMirClientWindow *parentWindowHandle = nullptr; - if (requiresParent(window->type())) { - parentWindowHandle = transientParentFor(window); - if (parentWindowHandle == nullptr) { - // NOTE: Mir requires this surface have a parent. Try using the last surface to receive input as that will - // most likely be the one that caused this surface to be created - parentWindowHandle = input->lastInputWindow(); - } - } - return parentWindowHandle; -} - -MirPixelFormat disableAlphaBufferIfPossible(MirPixelFormat pixelFormat) -{ - switch (pixelFormat) { - case mir_pixel_format_abgr_8888: - return mir_pixel_format_xbgr_8888; - case mir_pixel_format_argb_8888: - return mir_pixel_format_xrgb_8888; - default: // can do nothing, leave it alone - return pixelFormat; - } -} -} //namespace - - - -class UbuntuSurface -{ -public: - UbuntuSurface(QMirClientWindow *platformWindow, EGLDisplay display, QMirClientInput *input, MirConnection *connection); - ~UbuntuSurface(); - - UbuntuSurface(const UbuntuSurface &) = delete; - UbuntuSurface& operator=(const UbuntuSurface &) = delete; - - void updateGeometry(const QRect &newGeometry); - void updateTitle(const QString& title); - void setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment); - - void onSwapBuffersDone(); - void handleSurfaceResized(int width, int height); - int needsRepaint() const; - - MirSurfaceState state() const { return mir_surface_get_state(mMirSurface); } - void setState(MirSurfaceState state); - - MirSurfaceType type() const { return mir_surface_get_type(mMirSurface); } - - void setShellChrome(MirShellChrome shellChrome); - - EGLSurface eglSurface() const { return mEglSurface; } - MirSurface *mirSurface() const { return mMirSurface; } - - void setSurfaceParent(MirSurface*); - bool hasParent() const { return mParented; } - - QSurfaceFormat format() const { return mFormat; } - - bool mNeedsExposeCatchup; - - QString persistentSurfaceId(); - -private: - static void surfaceEventCallback(MirSurface* surface, const MirEvent *event, void* context); - void postEvent(const MirEvent *event); - - QWindow * const mWindow; - QMirClientWindow * const mPlatformWindow; - QMirClientInput * const mInput; - MirConnection * const mConnection; - QMirClientWindow * mParentWindowHandle{nullptr}; - - MirSurface* mMirSurface; - const EGLDisplay mEglDisplay; - EGLSurface mEglSurface; - - bool mNeedsRepaint; - bool mParented; - QSize mBufferSize; - QSurfaceFormat mFormat; - MirPixelFormat mPixelFormat; - - QMutex mTargetSizeMutex; - QSize mTargetSize; - MirShellChrome mShellChrome; - QString mPersistentIdStr; -}; - -UbuntuSurface::UbuntuSurface(QMirClientWindow *platformWindow, EGLDisplay display, QMirClientInput *input, MirConnection *connection) - : mWindow(platformWindow->window()) - , mPlatformWindow(platformWindow) - , mInput(input) - , mConnection(connection) - , mEglDisplay(display) - , mNeedsRepaint(false) - , mParented(mWindow->transientParent() || mWindow->parent()) - , mFormat(mWindow->requestedFormat()) - , mShellChrome(mWindow->flags() & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal) -{ - // Have Qt choose most suitable EGLConfig for the requested surface format, and update format to reflect it - EGLConfig config = q_configFromGLFormat(display, mFormat, true); - if (config == 0) { - // Older Intel Atom-based devices only support OpenGL 1.4 compatibility profile but by default - // QML asks for at least OpenGL 2.0. The XCB GLX backend ignores this request and returns a - // 1.4 context, but the XCB EGL backend tries to honor it, and fails. The 1.4 context appears to - // have sufficient capabilities on MESA (i915) to render correctly however. So reduce the default - // requested OpenGL version to 1.0 to ensure EGL will give us a working context (lp:1549455). - static const bool isMesa = QString(eglQueryString(display, EGL_VENDOR)).contains(QStringLiteral("Mesa")); - if (isMesa) { - qCDebug(mirclientGraphics, "Attempting to choose OpenGL 1.4 context which may suit Mesa"); - mFormat.setMajorVersion(1); - mFormat.setMinorVersion(4); - config = q_configFromGLFormat(display, mFormat, true); - } - } - if (config == 0) { - qCritical() << "Qt failed to choose a suitable EGLConfig to suit the surface format" << mFormat; - } - - mFormat = q_glFormatFromConfig(display, config, mFormat); - - // Have Mir decide the pixel format most suited to the chosen EGLConfig. This is the only way - // Mir will know what EGLConfig has been chosen - it cannot deduce it from the buffers. - mPixelFormat = mir_connection_get_egl_pixel_format(connection, display, config); - // But the chosen EGLConfig might have an alpha buffer enabled, even if not requested by the client. - // If that's the case, try to edit the chosen pixel format in order to disable the alpha buffer. - // This is an optimization for the compositor, as it can avoid blending this surface. - if (mWindow->requestedFormat().alphaBufferSize() < 0) { - mPixelFormat = disableAlphaBufferIfPossible(mPixelFormat); - } - - const auto outputId = static_cast(mWindow->screen()->handle())->mirOutputId(); - - mParentWindowHandle = getParentIfNecessary(mWindow, input); - - mMirSurface = createMirSurface(mWindow, outputId, mParentWindowHandle, mPixelFormat, connection, surfaceEventCallback, this); - mEglSurface = eglCreateWindowSurface(mEglDisplay, config, nativeWindowFor(mMirSurface), nullptr); - - mNeedsExposeCatchup = mir_surface_get_visibility(mMirSurface) == mir_surface_visibility_occluded; - - // Window manager can give us a final size different from what we asked for - // so let's check what we ended up getting - MirSurfaceParameters parameters; - mir_surface_get_parameters(mMirSurface, ¶meters); - - auto geom = mWindow->geometry(); - geom.setWidth(parameters.width); - geom.setHeight(parameters.height); - - // Assume that the buffer size matches the surface size at creation time - mBufferSize = geom.size(); - QWindowSystemInterface::handleGeometryChange(mWindow, geom); - - qCDebug(mirclient) << "Created surface with geometry:" << geom << "title:" << mWindow->title() - << "role:" << roleFor(mWindow); - qCDebug(mirclientGraphics) - << "Requested format:" << mWindow->requestedFormat() - << "\nActual format:" << mFormat - << "with associated Mir pixel format:" << mirPixelFormatToStr(mPixelFormat); -} - -UbuntuSurface::~UbuntuSurface() -{ - if (mEglSurface != EGL_NO_SURFACE) - eglDestroySurface(mEglDisplay, mEglSurface); - if (mMirSurface) { - mir_surface_release_sync(mMirSurface); - } -} - -void UbuntuSurface::updateGeometry(const QRect &newGeometry) -{ - qCDebug(mirclient,"updateGeometry(window=%p, width=%d, height=%d)", mWindow, - newGeometry.width(), newGeometry.height()); - - Spec spec; - if (isMovable(mWindow->type())) { - spec = Spec{makeSurfaceSpec(mWindow, mPixelFormat, mParentWindowHandle, mConnection)}; - } else { - spec = Spec{mir_connection_create_spec_for_changes(mConnection)}; - mir_surface_spec_set_width(spec.get(), newGeometry.width()); - mir_surface_spec_set_height(spec.get(), newGeometry.height()); - } - mir_surface_apply_spec(mMirSurface, spec.get()); -} - -void UbuntuSurface::updateTitle(const QString& newTitle) -{ - const auto title = newTitle.toUtf8(); - Spec spec{mir_connection_create_spec_for_changes(mConnection)}; - mir_surface_spec_set_name(spec.get(), title.constData()); - mir_surface_apply_spec(mMirSurface, spec.get()); -} - -void UbuntuSurface::setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment) -{ - Spec spec{mir_connection_create_spec_for_changes(mConnection)}; - ::setSizingConstraints(spec.get(), minSize, maxSize, increment); - mir_surface_apply_spec(mMirSurface, spec.get()); -} - -void UbuntuSurface::handleSurfaceResized(int width, int height) -{ - QMutexLocker lock(&mTargetSizeMutex); - - // mir's resize event is mainly a signal that we need to redraw our content. We use the - // width/height as identifiers to figure out if this is the latest surface resize event - // that has posted, discarding any old ones. This avoids issuing too many redraw events. - // see TODO in postEvent as the ideal way we should handle this. - // The actual buffer size may or may have not changed at this point, so let the rendering - // thread drive the window geometry updates. - mNeedsRepaint = mTargetSize.width() == width && mTargetSize.height() == height; -} - -int UbuntuSurface::needsRepaint() const -{ - if (mNeedsRepaint) { - if (mTargetSize != mBufferSize) { - //If the buffer hasn't changed yet, we need at least two redraws, - //once to get the new buffer size and propagate the geometry changes - //and the second to redraw the content at the new size - return 2; - } else { - // The buffer size has already been updated so we only need one redraw - // to render at the new size - return 1; - } - } - return 0; -} - -void UbuntuSurface::setState(MirSurfaceState state) -{ - mir_wait_for(mir_surface_set_state(mMirSurface, state)); -} - -void UbuntuSurface::setShellChrome(MirShellChrome chrome) -{ - if (chrome != mShellChrome) { - auto spec = Spec{mir_connection_create_spec_for_changes(mConnection)}; - mir_surface_spec_set_shell_chrome(spec.get(), chrome); - mir_surface_apply_spec(mMirSurface, spec.get()); - - mShellChrome = chrome; - } -} - -void UbuntuSurface::onSwapBuffersDone() -{ - static int sFrameNumber = 0; - ++sFrameNumber; - - EGLint eglSurfaceWidth = -1; - EGLint eglSurfaceHeight = -1; - eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &eglSurfaceWidth); - eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &eglSurfaceHeight); - - const bool validSize = eglSurfaceWidth > 0 && eglSurfaceHeight > 0; - - if (validSize && (mBufferSize.width() != eglSurfaceWidth || mBufferSize.height() != eglSurfaceHeight)) { - - qCDebug(mirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - size changed (%d, %d) => (%d, %d)", - mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height(), eglSurfaceWidth, eglSurfaceHeight); - - mBufferSize.rwidth() = eglSurfaceWidth; - mBufferSize.rheight() = eglSurfaceHeight; - - QRect newGeometry = mPlatformWindow->geometry(); - newGeometry.setSize(mBufferSize); - - QWindowSystemInterface::handleGeometryChange(mWindow, newGeometry); - } else { - qCDebug(mirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - buffer size (%d,%d)", - mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height()); - } -} - -void UbuntuSurface::surfaceEventCallback(MirSurface *surface, const MirEvent *event, void* context) -{ - Q_UNUSED(surface); - Q_ASSERT(context != nullptr); - - auto s = static_cast(context); - s->postEvent(event); -} - -void UbuntuSurface::postEvent(const MirEvent *event) -{ - if (mir_event_type_resize == mir_event_get_type(event)) { - // TODO: The current event queue just accumulates all resize events; - // It would be nicer if we could update just one event if that event has not been dispatched. - // As a workaround, we use the width/height as an identifier of this latest event - // so the event handler (handleSurfaceResized) can discard/ignore old ones. - const auto resizeEvent = mir_event_get_resize_event(event); - const auto width = mir_resize_event_get_width(resizeEvent); - const auto height = mir_resize_event_get_height(resizeEvent); - qCDebug(mirclient, "resizeEvent(window=%p, width=%d, height=%d)", mWindow, width, height); - - QMutexLocker lock(&mTargetSizeMutex); - mTargetSize.rwidth() = width; - mTargetSize.rheight() = height; - } - - mInput->postEvent(mPlatformWindow, event); -} - -void UbuntuSurface::setSurfaceParent(MirSurface* parent) -{ - qCDebug(mirclient, "setSurfaceParent(window=%p)", mWindow); - - mParented = true; - Spec spec{mir_connection_create_spec_for_changes(mConnection)}; - mir_surface_spec_set_parent(spec.get(), parent); - mir_surface_apply_spec(mMirSurface, spec.get()); -} - -QString UbuntuSurface::persistentSurfaceId() -{ - if (mPersistentIdStr.isEmpty()) { - MirPersistentId* mirPermaId = mir_surface_request_persistent_id_sync(mMirSurface); - mPersistentIdStr = mir_persistent_id_as_string(mirPermaId); - mir_persistent_id_release(mirPermaId); - } - return mPersistentIdStr; -} - -QMirClientWindow::QMirClientWindow(QWindow *w, QMirClientInput *input, QMirClientNativeInterface *native, - QMirClientAppStateController *appState, EGLDisplay eglDisplay, - MirConnection *mirConnection, QMirClientDebugExtension *debugExt) - : QObject(nullptr) - , QPlatformWindow(w) - , mId(makeId()) - , mWindowState(w->windowState()) - , mWindowFlags(w->flags()) - , mWindowVisible(false) - , mAppStateController(appState) - , mDebugExtention(debugExt) - , mNativeInterface(native) - , mSurface(new UbuntuSurface{this, eglDisplay, input, mirConnection}) - , mScale(1.0) - , mFormFactor(mir_form_factor_unknown) -{ - mWindowExposed = mSurface->mNeedsExposeCatchup == false; - - qCDebug(mirclient, "QMirClientWindow(window=%p, screen=%p, input=%p, surf=%p) with title '%s', role: '%d'", - w, w->screen()->handle(), input, mSurface.get(), qPrintable(window()->title()), roleFor(window())); -} - -QMirClientWindow::~QMirClientWindow() -{ - qCDebug(mirclient, "~QMirClientWindow(window=%p)", this); -} - -void QMirClientWindow::handleSurfaceResized(int width, int height) -{ - QMutexLocker lock(&mMutex); - qCDebug(mirclient, "handleSurfaceResize(window=%p, size=(%dx%d)px", window(), width, height); - - mSurface->handleSurfaceResized(width, height); - - // This resize event could have occurred just after the last buffer swap for this window. - // This means the client may still be holding a buffer with the older size. The first redraw call - // will then render at the old size. After swapping the client now will get a new buffer with the - // updated size but it still needs re-rendering so another redraw may be needed. - // A mir API to drop the currently held buffer would help here, so that we wouldn't have to redraw twice - auto const numRepaints = mSurface->needsRepaint(); - lock.unlock(); - qCDebug(mirclient, "handleSurfaceResize(window=%p) redraw %d times", window(), numRepaints); - for (int i = 0; i < numRepaints; i++) { - qCDebug(mirclient, "handleSurfaceResize(window=%p) repainting size=(%dx%d)dp", window(), geometry().size().width(), geometry().size().height()); - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); - } -} - -void QMirClientWindow::handleSurfaceExposeChange(bool exposed) -{ - QMutexLocker lock(&mMutex); - qCDebug(mirclient, "handleSurfaceExposeChange(window=%p, exposed=%s)", window(), exposed ? "true" : "false"); - - mSurface->mNeedsExposeCatchup = false; - if (mWindowExposed == exposed) return; - mWindowExposed = exposed; - - lock.unlock(); - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); -} - -void QMirClientWindow::handleSurfaceFocusChanged(bool focused) -{ - qCDebug(mirclient, "handleSurfaceFocusChanged(window=%p, focused=%d)", window(), focused); - if (focused) { - mAppStateController->setWindowFocused(true); - QWindowSystemInterface::handleWindowActivated(window(), Qt::ActiveWindowFocusReason); - } else { - mAppStateController->setWindowFocused(false); - } -} - -void QMirClientWindow::handleSurfaceVisibilityChanged(bool visible) -{ - qCDebug(mirclient, "handleSurfaceVisibilityChanged(window=%p, visible=%d)", window(), visible); - - if (mWindowVisible == visible) return; - mWindowVisible = visible; - - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); -} - -void QMirClientWindow::handleSurfaceStateChanged(Qt::WindowState state) -{ - qCDebug(mirclient, "handleSurfaceStateChanged(window=%p, %s)", window(), qtWindowStateToStr(state)); - - if (mWindowState == state) return; - mWindowState = state; - - QWindowSystemInterface::handleWindowStateChanged(window(), state); -} - -void QMirClientWindow::setWindowState(Qt::WindowStates states) -{ - Qt::WindowState state = Qt::WindowNoState; - if (states & Qt::WindowMinimized) - state = Qt::WindowMinimized; - else if (states & Qt::WindowFullScreen) - state = Qt::WindowFullScreen; - else if (states & Qt::WindowMaximized) - state = Qt::WindowMaximized; - - QMutexLocker lock(&mMutex); - qCDebug(mirclient, "setWindowState(window=%p, %s)", this, qtWindowStateToStr(state)); - - if (mWindowState == state) return; - mWindowState = state; - - lock.unlock(); - updateSurfaceState(); -} - -void QMirClientWindow::setWindowFlags(Qt::WindowFlags flags) -{ - QMutexLocker lock(&mMutex); - qCDebug(mirclient, "setWindowFlags(window=%p, 0x%x)", this, (int)flags); - - if (mWindowFlags == flags) return; - mWindowFlags = flags; - - mSurface->setShellChrome(mWindowFlags & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal); -} - -QRect QMirClientWindow::geometry() const -{ - if (mDebugExtention) { - auto geom = QPlatformWindow::geometry(); - geom.moveTopLeft(mDebugExtention->mapSurfacePointToScreen(mSurface->mirSurface(), QPoint(0,0))); - return geom; - } else { - return QPlatformWindow::geometry(); - } -} - -void QMirClientWindow::setGeometry(const QRect& rect) -{ - QMutexLocker lock(&mMutex); - - if (window()->windowState() == Qt::WindowFullScreen || window()->windowState() == Qt::WindowMaximized) { - qCDebug(mirclient, "setGeometry(window=%p) - not resizing, window is maximized or fullscreen", window()); - return; - } - - qCDebug(mirclient, "setGeometry (window=%p, position=(%d, %d)dp, size=(%dx%d)dp)", - window(), rect.x(), rect.y(), rect.width(), rect.height()); - // Immediately update internal geometry so Qt believes position updated - QRect newPosition(geometry()); - newPosition.moveTo(rect.topLeft()); - QPlatformWindow::setGeometry(newPosition); - - mSurface->updateGeometry(rect); - // Note: don't call handleGeometryChange here, wait to see what Mir replies with. -} - -void QMirClientWindow::setVisible(bool visible) -{ - QMutexLocker lock(&mMutex); - qCDebug(mirclient, "setVisible (window=%p, visible=%s)", window(), visible ? "true" : "false"); - - if (mWindowVisible == visible) return; - mWindowVisible = visible; - - if (visible) { - if (!mSurface->hasParent() && window()->type() == Qt::Dialog) { - // The dialog may have been parented after creation time - // so morph it into a modal dialog - auto parent = transientParentFor(window()); - if (parent) { - mSurface->setSurfaceParent(parent->mirSurface()); - } - } - } - - lock.unlock(); - updateSurfaceState(); - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); -} - -void QMirClientWindow::setWindowTitle(const QString& title) -{ - QMutexLocker lock(&mMutex); - qCDebug(mirclient, "setWindowTitle(window=%p) title=%s)", window(), title.toUtf8().constData()); - mSurface->updateTitle(title); -} - -void QMirClientWindow::propagateSizeHints() -{ - QMutexLocker lock(&mMutex); - const auto win = window(); - qCDebug(mirclient, "propagateSizeHints(window=%p) min(%d,%d), max(%d,%d) increment(%d, %d)", - win, win->minimumSize().width(), win->minimumSize().height(), - win->maximumSize().width(), win->maximumSize().height(), - win->sizeIncrement().width(), win->sizeIncrement().height()); - mSurface->setSizingConstraints(win->minimumSize(), win->maximumSize(), win->sizeIncrement()); -} - -bool QMirClientWindow::isExposed() const -{ - // mNeedsExposeCatchup because we need to render a frame to get the expose surface event from mir. - return mWindowVisible && (mWindowExposed || (mSurface && mSurface->mNeedsExposeCatchup)); -} - -QSurfaceFormat QMirClientWindow::format() const -{ - return mSurface->format(); -} - -QPoint QMirClientWindow::mapToGlobal(const QPoint &pos) const -{ - if (mDebugExtention) { - return mDebugExtention->mapSurfacePointToScreen(mSurface->mirSurface(), pos); - } else { - return pos; - } -} - -void* QMirClientWindow::eglSurface() const -{ - return mSurface->eglSurface(); -} - -MirSurface *QMirClientWindow::mirSurface() const -{ - return mSurface->mirSurface(); -} - -WId QMirClientWindow::winId() const -{ - return mId; -} - -void QMirClientWindow::onSwapBuffersDone() -{ - QMutexLocker lock(&mMutex); - mSurface->onSwapBuffersDone(); - - if (mSurface->mNeedsExposeCatchup) { - mSurface->mNeedsExposeCatchup = false; - mWindowExposed = false; - - lock.unlock(); - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); - } -} - -void QMirClientWindow::handleScreenPropertiesChange(MirFormFactor formFactor, float scale) -{ - // Update the scale & form factor native-interface properties for the windows affected - // as there is no convenient way to emit signals for those custom properties on a QScreen - if (formFactor != mFormFactor) { - mFormFactor = formFactor; - Q_EMIT mNativeInterface->windowPropertyChanged(this, QStringLiteral("formFactor")); - } - - if (!qFuzzyCompare(scale, mScale)) { - mScale = scale; - Q_EMIT mNativeInterface->windowPropertyChanged(this, QStringLiteral("scale")); - } -} - -void QMirClientWindow::updateSurfaceState() -{ - QMutexLocker lock(&mMutex); - MirSurfaceState newState = mWindowVisible ? qtWindowStateToMirSurfaceState(mWindowState) : - mir_surface_state_hidden; - qCDebug(mirclient, "updateSurfaceState (window=%p, surfaceState=%s)", window(), mirSurfaceStateToStr(newState)); - if (newState != mSurface->state()) { - mSurface->setState(newState); - } -} - -QString QMirClientWindow::persistentSurfaceId() -{ - return mSurface->persistentSurfaceId(); -} diff --git a/src/plugins/platforms/mirclient/qmirclientwindow.h b/src/plugins/platforms/mirclient/qmirclientwindow.h deleted file mode 100644 index 6c5695d62f..0000000000 --- a/src/plugins/platforms/mirclient/qmirclientwindow.h +++ /dev/null @@ -1,118 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014-2016 Canonical, Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef QMIRCLIENTWINDOW_H -#define QMIRCLIENTWINDOW_H - -#include -#include -#include - -#include // needed only for MirFormFactor enum - -#include - -#include - -class QMirClientAppStateController; -class QMirClientDebugExtension; -class QMirClientNativeInterface; -class QMirClientInput; -class QMirClientScreen; -class UbuntuSurface; -struct MirSurface; -class MirConnection; - -class QMirClientWindow : public QObject, public QPlatformWindow -{ - Q_OBJECT -public: - QMirClientWindow(QWindow *w, QMirClientInput *input, QMirClientNativeInterface* native, - QMirClientAppStateController *appState, EGLDisplay eglDisplay, - MirConnection *mirConnection, QMirClientDebugExtension *debugExt); - virtual ~QMirClientWindow(); - - // QPlatformWindow methods. - WId winId() const override; - QRect geometry() const override; - void setGeometry(const QRect&) override; - void setWindowState(Qt::WindowStates state) override; - void setWindowFlags(Qt::WindowFlags flags) override; - void setVisible(bool visible) override; - void setWindowTitle(const QString &title) override; - void propagateSizeHints() override; - bool isExposed() const override; - - QPoint mapToGlobal(const QPoint &pos) const override; - QSurfaceFormat format() const override; - - // Additional Window properties exposed by NativeInterface - MirFormFactor formFactor() const { return mFormFactor; } - float scale() const { return mScale; } - - // New methods. - void *eglSurface() const; - MirSurface *mirSurface() const; - void handleSurfaceResized(int width, int height); - void handleSurfaceExposeChange(bool exposed); - void handleSurfaceFocusChanged(bool focused); - void handleSurfaceVisibilityChanged(bool visible); - void handleSurfaceStateChanged(Qt::WindowState state); - void onSwapBuffersDone(); - void handleScreenPropertiesChange(MirFormFactor formFactor, float scale); - QString persistentSurfaceId(); - -private: - void updateSurfaceState(); - mutable QMutex mMutex; - const WId mId; - Qt::WindowState mWindowState; - Qt::WindowFlags mWindowFlags; - bool mWindowVisible; - bool mWindowExposed; - QMirClientAppStateController *mAppStateController; - QMirClientDebugExtension *mDebugExtention; - QMirClientNativeInterface *mNativeInterface; - std::unique_ptr mSurface; - float mScale; - MirFormFactor mFormFactor; -}; - -#endif // QMIRCLIENTWINDOW_H diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro index acc55adf6f..c4f2b30965 100644 --- a/src/plugins/platforms/platforms.pro +++ b/src/plugins/platforms/platforms.pro @@ -48,6 +48,4 @@ haiku { wasm: SUBDIRS += wasm -qtConfig(mirclient): SUBDIRS += mirclient - qtConfig(integrityfb): SUBDIRS += integrity -- cgit v1.2.3 From 2e12bfdc1e537bb3cc027eed14500fe5724ab30f Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 14 Dec 2018 10:48:43 +0100 Subject: eglfs: avoid breaking builds without EGL_EXT_platform_base Change-Id: I9183e17b42c00435f20c00a414e1f20aa3972351 Fixes: QTBUG-72559 Reviewed-by: Johan Helsing --- .../eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp | 1 - .../eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.cpp | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp index 1e4f4e72c8..f154520669 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp @@ -63,7 +63,6 @@ QEglFSKmsGbmIntegration::QEglFSKmsGbmIntegration() #ifndef EGL_EXT_platform_base typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list); -typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list); #endif #ifndef EGL_PLATFORM_GBM_KHR diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.cpp index 65a7c4f38a..a93762e5b4 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.cpp @@ -45,6 +45,10 @@ QT_BEGIN_NAMESPACE +#ifndef EGL_EXT_platform_base +typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list); +#endif + void QEglFSKmsGbmWindow::resetSurface() { QEglFSKmsGbmScreen *gbmScreen = static_cast(screen()); -- cgit v1.2.3 From 3fe9f245e8fb5fa9a2336fecaabd8d677f55c5db Mon Sep 17 00:00:00 2001 From: Michal Klocek Date: Thu, 13 Sep 2018 10:54:18 +0200 Subject: Add platform native interface to offscreen plugin Adds trival support for querying "display" and "glxconfig" in case offscreen plugin is compiled with xlib support. This is required so this plugin could work with webengine. Taks-number: QTBUG-63346 Change-Id: Ie0f29385cb44429ddf383ad459e0c9f3263ccffe Reviewed-by: Laszlo Agocs --- .../platforms/offscreen/qoffscreenintegration.h | 1 + .../offscreen/qoffscreenintegration_x11.cpp | 77 +++++++++++++++------- .../offscreen/qoffscreenintegration_x11.h | 9 ++- 3 files changed, 62 insertions(+), 25 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.h b/src/plugins/platforms/offscreen/qoffscreenintegration.h index fc988126bb..098e726550 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration.h +++ b/src/plugins/platforms/offscreen/qoffscreenintegration.h @@ -41,6 +41,7 @@ #define QOFFSCREENINTEGRATION_H #include +#include #include diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp index 93566220e8..06a9bd2a4c 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp +++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp @@ -52,6 +52,30 @@ QT_BEGIN_NAMESPACE +class QOffscreenX11Info +{ +public: + QOffscreenX11Info(QOffscreenX11Connection *connection) + : m_connection(connection) + { + } + + Display *display() const { + return (Display *)m_connection->display(); + } + + Window root() const { + return DefaultRootWindow(display()); + } + + int screenNumber() const { + return m_connection->screenNumber(); + } + +private: + QOffscreenX11Connection *m_connection; +}; + QOffscreenIntegration *QOffscreenIntegration::createOffscreenIntegration() { return new QOffscreenX11Integration; @@ -77,6 +101,35 @@ QPlatformOpenGLContext *QOffscreenX11Integration::createPlatformOpenGLContext(QO return new QOffscreenX11GLXContext(m_connection->x11Info(), context); } +QPlatformNativeInterface *QOffscreenX11Integration::nativeInterface() const +{ + return const_cast(this); +} + +void *QOffscreenX11Integration::nativeResourceForScreen(const QByteArray &resource, QScreen *screen) +{ + Q_UNUSED(screen) + if (resource.toLower() == QByteArrayLiteral("display") ) { + if (!m_connection) + m_connection.reset(new QOffscreenX11Connection); + return m_connection->display(); + } + return nullptr; +} + +#ifndef QT_NO_OPENGL +void *QOffscreenX11Integration::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) { + if (resource.toLower() == QByteArrayLiteral("glxconfig") ) { + if (!m_connection) + m_connection.reset(new QOffscreenX11Connection); + QOffscreenX11Info *x11 = m_connection->x11Info(); + GLXFBConfig config = qglx_findConfig(x11->display(), x11->screenNumber(), context->format()); + return config; + } + return nullptr; +} +#endif + QOffscreenX11Connection::QOffscreenX11Connection() { XInitThreads(); @@ -93,30 +146,6 @@ QOffscreenX11Connection::~QOffscreenX11Connection() XCloseDisplay((Display *)m_display); } -class QOffscreenX11Info -{ -public: - QOffscreenX11Info(QOffscreenX11Connection *connection) - : m_connection(connection) - { - } - - Display *display() const { - return (Display *)m_connection->display(); - } - - Window root() const { - return DefaultRootWindow(display()); - } - - int screenNumber() const { - return m_connection->screenNumber(); - } - -private: - QOffscreenX11Connection *m_connection; -}; - QOffscreenX11Info *QOffscreenX11Connection::x11Info() { if (!m_x11Info) diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h index 5e1c6b799b..a1986fdc94 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h +++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h @@ -52,12 +52,19 @@ QT_BEGIN_NAMESPACE class QOffscreenX11Connection; class QOffscreenX11Info; -class QOffscreenX11Integration : public QOffscreenIntegration +class QOffscreenX11Integration : public QOffscreenIntegration, public QPlatformNativeInterface { public: bool hasCapability(QPlatformIntegration::Capability cap) const override; QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override; + QPlatformNativeInterface *nativeInterface()const override; + + // QPlatformNativeInterface + void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen) override; +#ifndef QT_NO_OPENGL + void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) override; +#endif private: mutable QScopedPointer m_connection; -- cgit v1.2.3 From 2c60844badd8fb07dd4844926345c924679f20fb Mon Sep 17 00:00:00 2001 From: Nicolas Fella Date: Wed, 30 Jan 2019 14:13:12 +0100 Subject: [platform/android] Add native file dialog Add basic native file open dialog on Android. Not all features of QFileDialog can be mapped to the Android file dialog. Most notably there is no "Save" dialog. The dialog returns a content:// URL. Patch 251038 adds support for those to QFile. Change-Id: I13d02103edcd9a089afcce8193432f24b2e0fe43 Reviewed-by: BogDan Vatra --- src/plugins/platforms/android/android.pro | 6 +- .../android/qandroidplatformfiledialoghelper.cpp | 149 +++++++++++++++++++++ .../android/qandroidplatformfiledialoghelper.h | 81 +++++++++++ .../platforms/android/qandroidplatformtheme.cpp | 5 + 4 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp create mode 100644 src/plugins/platforms/android/qandroidplatformfiledialoghelper.h (limited to 'src/plugins') diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro index 73db9e93a3..f91db1ab5f 100644 --- a/src/plugins/platforms/android/android.pro +++ b/src/plugins/platforms/android/android.pro @@ -46,7 +46,8 @@ SOURCES += $$PWD/androidplatformplugin.cpp \ $$PWD/qandroidplatformopenglcontext.cpp \ $$PWD/qandroidplatformforeignwindow.cpp \ $$PWD/qandroideventdispatcher.cpp \ - $$PWD/qandroidplatformoffscreensurface.cpp + $$PWD/qandroidplatformoffscreensurface.cpp \ + $$PWD/qandroidplatformfiledialoghelper.cpp HEADERS += $$PWD/qandroidplatformintegration.h \ $$PWD/androiddeadlockprotector.h \ @@ -75,7 +76,8 @@ HEADERS += $$PWD/qandroidplatformintegration.h \ $$PWD/qandroidplatformopenglcontext.h \ $$PWD/qandroidplatformforeignwindow.h \ $$PWD/qandroideventdispatcher.h \ - $$PWD/qandroidplatformoffscreensurface.h + $$PWD/qandroidplatformoffscreensurface.h \ + $$PWD/qandroidplatformfiledialoghelper.h qtConfig(android-style-assets): SOURCES += $$PWD/extract.cpp else: SOURCES += $$PWD/extract-dummy.cpp diff --git a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp new file mode 100644 index 0000000000..4fb271a75c --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB) +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qandroidplatformfiledialoghelper.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace QtAndroidFileDialogHelper { + +#define RESULT_OK -1 +#define REQUEST_CODE 1305 // Arbitrary + +QAndroidPlatformFileDialogHelper::QAndroidPlatformFileDialogHelper() + : QPlatformFileDialogHelper() + , m_selectedFile() +{ +} + +bool QAndroidPlatformFileDialogHelper::handleActivityResult(jint requestCode, jint resultCode, jobject data) +{ + if (requestCode != REQUEST_CODE) + return false; + + if (resultCode == RESULT_OK) { + const QJNIObjectPrivate intent = QJNIObjectPrivate::fromLocalRef(data); + const QJNIObjectPrivate uri = intent.callObjectMethod("getData", "()Landroid/net/Uri;"); + const QString uriStr = uri.callObjectMethod("toString", "()Ljava/lang/String;").toString(); + m_selectedFile = QUrl(uriStr); + Q_EMIT fileSelected(m_selectedFile); + Q_EMIT accept(); + } else { + Q_EMIT reject(); + } + + return true; +} + +bool QAndroidPlatformFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) +{ + Q_UNUSED(windowFlags) + Q_UNUSED(windowModality) + Q_UNUSED(parent) + + if (options()->fileMode() != QFileDialogOptions::FileMode::ExistingFile) + return false; + + QtAndroidPrivate::registerActivityResultListener(this); + + const QJNIObjectPrivate ACTION_OPEN_DOCUMENT = QJNIObjectPrivate::getStaticObjectField("android/content/Intent", "ACTION_OPEN_DOCUMENT", "Ljava/lang/String;"); + QJNIObjectPrivate intent("android/content/Intent", "(Ljava/lang/String;)V", ACTION_OPEN_DOCUMENT.object()); + const QJNIObjectPrivate CATEGORY_OPENABLE = QJNIObjectPrivate::getStaticObjectField("android/content/Intent", "CATEGORY_OPENABLE", "Ljava/lang/String;"); + intent.callObjectMethod("addCategory", "(Ljava/lang/String;)Landroid/content/Intent;", CATEGORY_OPENABLE.object()); + intent.callObjectMethod("setType", "(Ljava/lang/String;)Landroid/content/Intent;", QJNIObjectPrivate::fromString(QStringLiteral("*/*")).object()); + + const QJNIObjectPrivate activity(QtAndroid::activity()); + activity.callMethod("startActivityForResult", "(Landroid/content/Intent;I)V", intent.object(), REQUEST_CODE); + + return true; +} + +void QAndroidPlatformFileDialogHelper::exec() +{ +} + +void QAndroidPlatformFileDialogHelper::hide() +{ +} + +QString QAndroidPlatformFileDialogHelper::selectedNameFilter() const +{ + return QString(); +} + +void QAndroidPlatformFileDialogHelper::selectNameFilter(const QString &filter) +{ + Q_UNUSED(filter) +} + +void QAndroidPlatformFileDialogHelper::setFilter() +{ +} + +QList QAndroidPlatformFileDialogHelper::selectedFiles() const +{ + return {m_selectedFile}; +} + +void QAndroidPlatformFileDialogHelper::selectFile(const QUrl &file) +{ + Q_UNUSED(file) +} + +QUrl QAndroidPlatformFileDialogHelper::directory() const +{ + return QUrl(); +} + +void QAndroidPlatformFileDialogHelper::setDirectory(const QUrl &directory) +{ + Q_UNUSED(directory) +} + +bool QAndroidPlatformFileDialogHelper::defaultNameFilterDisables() const +{ + return false; +} +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h new file mode 100644 index 0000000000..e445aa2fef --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB) +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QANDROIDPLATFORMFILEDIALOGHELPER_H +#define QANDROIDPLATFORMFILEDIALOGHELPER_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace QtAndroidFileDialogHelper { + +class QAndroidPlatformFileDialogHelper: public QPlatformFileDialogHelper, public QtAndroidPrivate::ActivityResultListener +{ + Q_OBJECT + +public: + QAndroidPlatformFileDialogHelper(); + void exec() override; + + bool show(Qt::WindowFlags windowFlags, + Qt::WindowModality windowModality, + QWindow *parent) override; + void hide() override; + + QString selectedNameFilter() const override; + void selectNameFilter(const QString &filter) override; + void setFilter() override; + QList selectedFiles() const override; + void selectFile(const QUrl &file) override; + QUrl directory() const override; + void setDirectory(const QUrl &directory) override; + bool defaultNameFilterDisables() const override; + bool handleActivityResult(jint requestCode, jint resultCode, jobject data) override; + +private: + QUrl m_selectedFile; +}; + +} +QT_END_NAMESPACE + +#endif // QANDROIDPLATFORMFILEDIALOGHELPER_H diff --git a/src/plugins/platforms/android/qandroidplatformtheme.cpp b/src/plugins/platforms/android/qandroidplatformtheme.cpp index b891407c44..a78a62337f 100644 --- a/src/plugins/platforms/android/qandroidplatformtheme.cpp +++ b/src/plugins/platforms/android/qandroidplatformtheme.cpp @@ -44,6 +44,7 @@ #include "qandroidplatformmenu.h" #include "qandroidplatformmenuitem.h" #include "qandroidplatformdialoghelpers.h" +#include "qandroidplatformfiledialoghelper.h" #include #include @@ -512,6 +513,8 @@ bool QAndroidPlatformTheme::usePlatformNativeDialog(QPlatformTheme::DialogType t { if (type == MessageDialog) return qEnvironmentVariableIntValue("QT_USE_ANDROID_NATIVE_DIALOGS") == 1; + if (type == FileDialog) + return true; return false; } @@ -520,6 +523,8 @@ QPlatformDialogHelper *QAndroidPlatformTheme::createPlatformDialogHelper(QPlatfo switch (type) { case MessageDialog: return new QtAndroidDialogHelpers::QAndroidPlatformMessageDialogHelper; + case FileDialog: + return new QtAndroidFileDialogHelper::QAndroidPlatformFileDialogHelper; default: return 0; } -- cgit v1.2.3 From df2b76046de4af7a47fa8303d5f261e3c5d120fe Mon Sep 17 00:00:00 2001 From: Dominik Holland Date: Wed, 7 Nov 2018 10:18:14 +0100 Subject: eglfs: Add vsync support when using NVIDIA eglstreams Similar to the kms backend a flip event handler can be retrieved using the drmEvent API to implement vsync. For this to work the acquire calls need to be done manuallly and the automatic acquiring needs to be disabled. Change-Id: I670d288ef68eb49846108db2a31993c6167d9313 Reviewed-by: Laszlo Agocs --- .../qeglfskmsegldeviceintegration.cpp | 50 ++++++++++++++++++++++ .../qeglfskmsegldeviceintegration.h | 2 + 2 files changed, 52 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp index ab39af6b80..9f4c9f5703 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp @@ -114,14 +114,18 @@ public: : QEglFSWindow(w) , m_integration(integration) , m_egl_stream(EGL_NO_STREAM_KHR) + , m_framePending(false) { } void invalidateSurface() override; void resetSurface() override; + void flip(); + static void pageFlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data); const QEglFSKmsEglDeviceIntegration *m_integration; EGLStreamKHR m_egl_stream; EGLint m_latency; + bool m_framePending; }; void QEglFSKmsEglDeviceWindow::invalidateSurface() @@ -142,6 +146,9 @@ void QEglFSKmsEglDeviceWindow::resetSurface() streamAttribs[streamAttribCount++] = EGL_STREAM_FIFO_LENGTH_KHR; streamAttribs[streamAttribCount++] = fifoLength; } + + streamAttribs[streamAttribCount++] = EGL_CONSUMER_AUTO_ACQUIRE_EXT; + streamAttribs[streamAttribCount++] = EGL_FALSE; streamAttribs[streamAttribCount++] = EGL_NONE; m_egl_stream = m_integration->m_funcs->create_stream(display, streamAttribs); @@ -239,6 +246,49 @@ void QEglFSKmsEglDeviceWindow::resetSurface() qCDebug(qLcEglfsKmsDebug, "Created stream producer surface %p", m_surface); } +void QEglFSKmsEglDeviceWindow::flip() +{ + EGLDisplay display = screen()->display(); + + EGLAttrib acquire_attribs[3] = { EGL_NONE }; + + acquire_attribs[0] = EGL_DRM_FLIP_EVENT_DATA_NV; + acquire_attribs[1] = (EGLAttrib)this; + acquire_attribs[2] = EGL_NONE; + + if (m_egl_stream != EGL_NO_STREAM_KHR) + if (!m_integration->m_funcs->acquire_stream_attrib_nv(display, m_egl_stream, acquire_attribs)) + qWarning("eglStreamConsumerAcquireAttribNV failed: eglError: %x", eglGetError()); + + m_framePending = true; + + while (m_framePending) { + drmEventContext drmEvent; + memset(&drmEvent, 0, sizeof(drmEvent)); + drmEvent.version = 3; + drmEvent.vblank_handler = nullptr; + drmEvent.page_flip_handler = pageFlipHandler; + drmHandleEvent(m_integration->m_device->fd(), &drmEvent); + } +} + +void QEglFSKmsEglDeviceWindow::pageFlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data) +{ + Q_UNUSED(fd); + Q_UNUSED(sequence); + Q_UNUSED(tv_sec); + Q_UNUSED(tv_usec); + + QEglFSKmsEglDeviceWindow *window = static_cast(user_data); + window->m_framePending = false; +} + +void QEglFSKmsEglDeviceIntegration::presentBuffer(QPlatformSurface *surface) +{ + QEglFSKmsEglDeviceWindow *eglWindow = static_cast(surface); + eglWindow->flip(); +} + QEglFSWindow *QEglFSKmsEglDeviceIntegration::createWindow(QWindow *window) const { QEglFSKmsEglDeviceWindow *eglWindow = new QEglFSKmsEglDeviceWindow(window, this); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h index 5819d82ebf..0c64d83b12 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h @@ -62,6 +62,8 @@ public: bool supportsPBuffers() const override; QEglFSWindow *createWindow(QWindow *window) const override; + void presentBuffer(QPlatformSurface *surface); + EGLDeviceEXT eglDevice() const { return m_egl_device; } protected: -- cgit v1.2.3 From 6b8610f4e8b72895bfa4228cca2230f31c259d80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 12 Feb 2019 13:55:52 +0100 Subject: macOS: Add explicit auto-release pool for requestActivateWindow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The API is often called from main before entering the event loop, and the making the window first responder and key will autorelease both the window and view. Change-Id: Ie2a7dc14652015cbe802b57696e4a82d564e2dc0 Reviewed-by: Morten Johan Sørvig Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoawindow.mm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 724c9485bd..ebdd51acb4 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1512,9 +1512,9 @@ void QCocoaWindow::deliverUpdateRequest() void QCocoaWindow::requestActivateWindow() { - NSWindow *window = [m_view window]; - [window makeFirstResponder:m_view]; - [window makeKeyWindow]; + QMacAutoReleasePool pool; + [m_view.window makeFirstResponder:m_view]; + [m_view.window makeKeyWindow]; } QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel) -- cgit v1.2.3 From 0ad651579fe9055e52d4a6754a95de35f7b9bf52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 7 Feb 2019 17:27:18 +0100 Subject: macOS: Don't rely on QGuiApplication::instance() during CVDisplayLink callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The display-link callback comes in on a secondary thread, so there's a possible race in using QGuiApplication::instance() to check whether or not we're on the main thread. Change-Id: Ic26bca8f5f54847a1e1b11dc92e786693c86e9de Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qcocoascreen.mm | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm index 36c11ba8af..80dd7e40d3 100644 --- a/src/plugins/platforms/cocoa/qcocoascreen.mm +++ b/src/plugins/platforms/cocoa/qcocoascreen.mm @@ -269,15 +269,12 @@ struct DeferredDebugHelper void QCocoaScreen::deliverUpdateRequests() { - if (!QGuiApplication::instance()) - return; - // The CVDisplayLink callback is a notification that it's a good time to produce a new frame. // Since the callback is delivered on a separate thread we have to marshal it over to the // main thread, as Qt requires update requests to be delivered there. This needs to happen // asynchronously, as otherwise we may end up deadlocking if the main thread calls back // into any of the CVDisplayLink APIs. - if (QThread::currentThread() != QGuiApplication::instance()->thread()) { + if (!NSThread.isMainThread) { // We're explicitly not using the data of the GCD source to track the pending updates, // as the data isn't reset to 0 until after the event handler, and also doesn't update // during the event handler, both of which we need to track late frames. -- cgit v1.2.3 From 77389ad8ff9fd3dc56f5a398fab11a993e7a621c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Sun, 10 Feb 2019 17:39:06 +0100 Subject: macOS: Remove screen-update disable during resize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was needed as a workaround for the window border and window content becoming out of sync when we were drawing and flushing to the layer from another thread using OpenGL. Since we've disabled ThreadedOpenGL we can remove this workaround for now. The workaround also had other problems, as windowWillResize: did not turn out to be a reliable signal to know when a window was about to resize. Since we override windowWillUseStandardFrame:, we would not get the callback when zooming windows. Conversely, if we removed the windowWillUseStandardFrame: override, we would get a single callback for windowWillResize:, and then multiple callbacks that the window had resized. In addition, windowWillResize: is not only used as a callback, but also as a way to let the window delegate restrict the size, so it's called when e.g. AppKit determines the standard frame of the window -- an operation that doesn't involve an actual resize operation. If we re-introduce a workaround using screen-update disabling we need a better hook than windowWillResize:, and we need to track when we disable screen updates so that we can pair them up with corresponding screen update enables, otherwise we'll get log messages in the console about "SLSReenableUpdate: unbalanced enable/disable update". Change-Id: Ifca8892083c8666976391a4ada8f8d1471493943 Fixes: QTBUG-73726 Task-number: QTBUG-69321 Reviewed-by: Morten Johan Sørvig Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qnswindowdelegate.mm | 34 ------------------------ 1 file changed, 34 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index 14f1ca0114..087cb3651f 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm @@ -102,40 +102,6 @@ static QCocoaWindow *toPlatformWindow(NSWindow *window) return QCocoaScreen::mapToNative(maximizedFrame); } -#pragma clang diagnostic push -// NSDisableScreenUpdates and NSEnableScreenUpdates are deprecated, but the -// NSAnimationContext API that replaces them doesn't handle the use-case of -// cross-thread screen update synchronization. -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)frameSize -{ - Q_ASSERT(toPlatformWindow(window)); - - qCDebug(lcQpaWindow) << window << "will resize to" << QSizeF::fromCGSize(frameSize) - << "- disabling screen updates temporarily"; - - // There may be separate threads rendering to CA layers in this window, - // and if any of them do a swap while the resize is still in progress, - // the visual bounds of that layer will be updated before the visual - // bounds of the window frame, resulting in flickering while resizing. - - // To prevent this we disable screen updates for the whole process until - // the resize is complete, which makes the whole thing visually atomic. - NSDisableScreenUpdates(); - - return frameSize; -} - -- (void)windowDidResize:(NSNotification *)notification -{ - NSWindow *window = notification.object; - Q_ASSERT(toPlatformWindow(window)); - - qCDebug(lcQpaWindow) << window << "was resized - re-enabling screen updates"; - NSEnableScreenUpdates(); -} -#pragma clang diagnostic pop - - (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu { Q_UNUSED(menu); -- cgit v1.2.3 From 38504041148f2d1cffea6520ea448dd4171adb0b Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Mon, 4 Feb 2019 19:25:31 +0100 Subject: Windows QPA: Handle mouse input using legacy messages This change reverts to using legacy mouse messages when handling mouse and touchpad input, while using pointer messages to handle touchscreen and pen input. The use of pointer messages to handle everything, added in 5.12.0, caused issues in some particular cases, due mainly to differences in behavior or bugs in the pointer messages, which required workarounds in the Windows QPA, which didn't work well in all cases and led to additional issues. For instance, DoDragDrop() does not work when called by pointer (or touch/pen) handlers, but only after OS-synthesized legacy mouse messages are generated. Also, in some cases pointer messages for mouse movement are generated as non-client for client area events. Modal loops like the ones in window resize/move and menu handling caused some issues with pointer messages, as well. Also, we have to handle the OS-synthesized legacy mouse message generated for touch and pen. Ignoring them while letting the gui layer synthesize mouse events for touch/pen may break Drag and Drop by triggering DoDragDrop() before legacy messages, which can result in a hang inside the DoDragDrop() modal loop. This change should fix most regressions related to pointer messages, while keeping the enhancements in pen and touch input. Fixes: QTBUG-73389 Fixes: QTBUG-72624 Fixes: QTBUG-72801 Fixes: QTBUG-73290 Fixes: QTBUG-72458 Fixes: QTBUG-73358 Fixes: QTBUG-72992 Change-Id: I919f78930d3965270ef2094401e827ab87174979 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowscontext.cpp | 20 +- .../platforms/windows/qwindowspointerhandler.cpp | 483 +++++++-------------- .../platforms/windows/qwindowspointerhandler.h | 6 +- 3 files changed, 165 insertions(+), 344 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 2b96fb3a5e..41655dbd57 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -334,12 +334,8 @@ bool QWindowsContext::initTouch(unsigned integrationOptions) if (!touchDevice) return false; - if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) { - QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false); - } else { - if (!(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch)) - touchDevice->setCapabilities(touchDevice->capabilities() | QTouchDevice::MouseEmulation); - } + if (!(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch)) + touchDevice->setCapabilities(touchDevice->capabilities() | QTouchDevice::MouseEmulation); QWindowSystemInterface::registerTouchDevice(touchDevice); @@ -376,7 +372,6 @@ bool QWindowsContext::initPointer(unsigned integrationOptions) if (!QWindowsContext::user32dll.supportsPointerApi()) return false; - QWindowsContext::user32dll.enableMouseInPointer(TRUE); d->m_systemInfo |= QWindowsContext::SI_SupportsPointer; return true; } @@ -1218,9 +1213,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::ExposeEvent: return platformWindow->handleWmPaint(hwnd, message, wParam, lParam); case QtWindows::NonClientMouseEvent: - if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled()) + if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled()) + return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result); + else return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result); - break; case QtWindows::NonClientPointerEvent: if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled()) return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result); @@ -1246,10 +1242,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, window = window->parent(); if (!window) return false; - if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer)) - return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result); - else + if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(window, hwnd, et, msg, result); + else + return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result); } break; case QtWindows::TouchEvent: diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 203d803a1b..f1960f1585 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -50,9 +50,6 @@ #include "qwindowswindow.h" #include "qwindowsintegration.h" #include "qwindowsscreen.h" -#if QT_CONFIG(draganddrop) -# include "qwindowsdrag.h" -#endif #include #include @@ -78,111 +75,9 @@ enum { QT_PT_TOUCHPAD = 5, // MinGW is missing PT_TOUCHPAD }; -struct PointerTouchEventInfo { - QPointer window; - QList points; - Qt::KeyboardModifiers modifiers; -}; - -struct PointerTabletEventInfo { - QPointer window; - QPointF local; - QPointF global; - int device; - int pointerType; - Qt::MouseButtons buttons; - qreal pressure; - int xTilt; - int yTilt; - qreal tangentialPressure; - qreal rotation; - int z; - qint64 uid; - Qt::KeyboardModifiers modifiers; -}; - -static QQueue touchEventQueue; -static QQueue tabletEventQueue; - -static void enqueueTouchEvent(QWindow *window, - const QList &points, - Qt::KeyboardModifiers modifiers) -{ - PointerTouchEventInfo eventInfo; - eventInfo.window = window; - eventInfo.points = points; - eventInfo.modifiers = modifiers; - touchEventQueue.enqueue(eventInfo); -} - -static void enqueueTabletEvent(QWindow *window, const QPointF &local, const QPointF &global, - int device, int pointerType, Qt::MouseButtons buttons, qreal pressure, - int xTilt, int yTilt, qreal tangentialPressure, qreal rotation, - int z, qint64 uid, Qt::KeyboardModifiers modifiers) -{ - PointerTabletEventInfo eventInfo; - eventInfo.window = window; - eventInfo.local = local; - eventInfo.global = global; - eventInfo.device = device; - eventInfo.pointerType = pointerType; - eventInfo.buttons = buttons; - eventInfo.pressure = pressure; - eventInfo.xTilt = xTilt; - eventInfo.yTilt = yTilt; - eventInfo.tangentialPressure = tangentialPressure; - eventInfo.rotation = rotation; - eventInfo.z = z; - eventInfo.uid = uid; - eventInfo.modifiers = modifiers; - tabletEventQueue.enqueue(eventInfo); -} - -static void flushTouchEvents(QTouchDevice *touchDevice) -{ - while (!touchEventQueue.isEmpty()) { - PointerTouchEventInfo eventInfo = touchEventQueue.dequeue(); - if (eventInfo.window) { - QWindowSystemInterface::handleTouchEvent(eventInfo.window, - touchDevice, - eventInfo.points, - eventInfo.modifiers); - } - } -} - -static void flushTabletEvents() -{ - while (!tabletEventQueue.isEmpty()) { - PointerTabletEventInfo eventInfo = tabletEventQueue.dequeue(); - if (eventInfo.window) { - QWindowSystemInterface::handleTabletEvent(eventInfo.window, - eventInfo.local, - eventInfo.global, - eventInfo.device, - eventInfo.pointerType, - eventInfo.buttons, - eventInfo.pressure, - eventInfo.xTilt, - eventInfo.yTilt, - eventInfo.tangentialPressure, - eventInfo.rotation, - eventInfo.z, - eventInfo.uid, - eventInfo.modifiers); - } - } -} - bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result) { *result = 0; - - // If we are inside the move/resize modal loop, let DefWindowProc() handle it (but process NC button release). - QWindowsWindow *platformWindow = static_cast(window->handle()); - if (msg.message != WM_NCPOINTERUP && platformWindow->testFlag(QWindowsWindow::ResizeMoveActive)) - return false; - const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam); POINTER_INPUT_TYPE pointerType; @@ -191,30 +86,12 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q return false; } - m_lastPointerType = pointerType; - - // Handle non-client pen/touch as generic mouse events for compatibility with QDockWindow. - if ((pointerType == QT_PT_TOUCH || pointerType == QT_PT_PEN) && (et & QtWindows::NonClientEventFlag)) { - POINTER_INFO pointerInfo; - if (!QWindowsContext::user32dll.getPointerInfo(pointerId, &pointerInfo)) { - qWarning() << "GetPointerInfo() failed:" << qt_error_string(); - return false; - } - if (pointerInfo.pointerFlags & (POINTER_FLAG_UP | POINTER_FLAG_DOWN)) - return translateMouseTouchPadEvent(window, hwnd, et, msg, &pointerInfo); - return false; - } - switch (pointerType) { case QT_PT_POINTER: case QT_PT_MOUSE: case QT_PT_TOUCHPAD: { - POINTER_INFO pointerInfo; - if (!QWindowsContext::user32dll.getPointerInfo(pointerId, &pointerInfo)) { - qWarning() << "GetPointerInfo() failed:" << qt_error_string(); - return false; - } - return translateMouseTouchPadEvent(window, hwnd, et, msg, &pointerInfo); + // Let Mouse/TouchPad be handled using legacy messages. + return false; } case QT_PT_TOUCH: { quint32 pointerCount = 0; @@ -290,76 +167,71 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q return false; } -static void getMouseEventInfo(UINT message, POINTER_BUTTON_CHANGE_TYPE changeType, QEvent::Type *eventType, Qt::MouseButton *mouseButton) -{ - static const QHash buttonMapping { - {POINTER_CHANGE_FIRSTBUTTON_DOWN, Qt::LeftButton}, - {POINTER_CHANGE_FIRSTBUTTON_UP, Qt::LeftButton}, - {POINTER_CHANGE_SECONDBUTTON_DOWN, Qt::RightButton}, - {POINTER_CHANGE_SECONDBUTTON_UP, Qt::RightButton}, - {POINTER_CHANGE_THIRDBUTTON_DOWN, Qt::MiddleButton}, - {POINTER_CHANGE_THIRDBUTTON_UP, Qt::MiddleButton}, - {POINTER_CHANGE_FOURTHBUTTON_DOWN, Qt::XButton1}, - {POINTER_CHANGE_FOURTHBUTTON_UP, Qt::XButton1}, - {POINTER_CHANGE_FIFTHBUTTON_DOWN, Qt::XButton2}, - {POINTER_CHANGE_FIFTHBUTTON_UP, Qt::XButton2}, - }; - - static const POINTER_BUTTON_CHANGE_TYPE downChanges[] = { - POINTER_CHANGE_FIRSTBUTTON_DOWN, - POINTER_CHANGE_SECONDBUTTON_DOWN, - POINTER_CHANGE_THIRDBUTTON_DOWN, - POINTER_CHANGE_FOURTHBUTTON_DOWN, - POINTER_CHANGE_FIFTHBUTTON_DOWN, - }; - - static const POINTER_BUTTON_CHANGE_TYPE upChanges[] = { - POINTER_CHANGE_FIRSTBUTTON_UP, - POINTER_CHANGE_SECONDBUTTON_UP, - POINTER_CHANGE_THIRDBUTTON_UP, - POINTER_CHANGE_FOURTHBUTTON_UP, - POINTER_CHANGE_FIFTHBUTTON_UP, - }; - - if (!eventType || !mouseButton) - return; - - const bool nonClient = message == WM_NCPOINTERUPDATE || - message == WM_NCPOINTERDOWN || - message == WM_NCPOINTERUP; - - if (std::find(std::begin(downChanges), - std::end(downChanges), changeType) < std::end(downChanges)) { - *eventType = nonClient ? QEvent::NonClientAreaMouseButtonPress : - QEvent::MouseButtonPress; - } else if (std::find(std::begin(upChanges), - std::end(upChanges), changeType) < std::end(upChanges)) { - *eventType = nonClient ? QEvent::NonClientAreaMouseButtonRelease : - QEvent::MouseButtonRelease; - } else if (message == WM_POINTERWHEEL || message == WM_POINTERHWHEEL) { - *eventType = QEvent::Wheel; - } else { - *eventType = nonClient ? QEvent::NonClientAreaMouseMove : - QEvent::MouseMove; - } +namespace { +struct MouseEvent { + QEvent::Type type; + Qt::MouseButton button; +}; +} // namespace - *mouseButton = buttonMapping.value(changeType, Qt::NoButton); +static inline Qt::MouseButton extraButton(WPARAM wParam) // for WM_XBUTTON... +{ + return GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? Qt::BackButton : Qt::ForwardButton; } -static Qt::MouseButtons mouseButtonsFromPointerFlags(POINTER_FLAGS pointerFlags) +static inline MouseEvent eventFromMsg(const MSG &msg) { - Qt::MouseButtons result = Qt::NoButton; - if (pointerFlags & POINTER_FLAG_FIRSTBUTTON) - result |= Qt::LeftButton; - if (pointerFlags & POINTER_FLAG_SECONDBUTTON) - result |= Qt::RightButton; - if (pointerFlags & POINTER_FLAG_THIRDBUTTON) - result |= Qt::MiddleButton; - if (pointerFlags & POINTER_FLAG_FOURTHBUTTON) - result |= Qt::XButton1; - if (pointerFlags & POINTER_FLAG_FIFTHBUTTON) - result |= Qt::XButton2; - return result; + switch (msg.message) { + case WM_MOUSEMOVE: + return {QEvent::MouseMove, Qt::NoButton}; + case WM_LBUTTONDOWN: + return {QEvent::MouseButtonPress, Qt::LeftButton}; + case WM_LBUTTONUP: + return {QEvent::MouseButtonRelease, Qt::LeftButton}; + case WM_LBUTTONDBLCLK: // Qt QPA does not handle double clicks, send as press + return {QEvent::MouseButtonPress, Qt::LeftButton}; + case WM_MBUTTONDOWN: + return {QEvent::MouseButtonPress, Qt::MidButton}; + case WM_MBUTTONUP: + return {QEvent::MouseButtonRelease, Qt::MidButton}; + case WM_MBUTTONDBLCLK: + return {QEvent::MouseButtonPress, Qt::MidButton}; + case WM_RBUTTONDOWN: + return {QEvent::MouseButtonPress, Qt::RightButton}; + case WM_RBUTTONUP: + return {QEvent::MouseButtonRelease, Qt::RightButton}; + case WM_RBUTTONDBLCLK: + return {QEvent::MouseButtonPress, Qt::RightButton}; + case WM_XBUTTONDOWN: + return {QEvent::MouseButtonPress, extraButton(msg.wParam)}; + case WM_XBUTTONUP: + return {QEvent::MouseButtonRelease, extraButton(msg.wParam)}; + case WM_XBUTTONDBLCLK: + return {QEvent::MouseButtonPress, extraButton(msg.wParam)}; + case WM_NCMOUSEMOVE: + return {QEvent::NonClientAreaMouseMove, Qt::NoButton}; + case WM_NCLBUTTONDOWN: + return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton}; + case WM_NCLBUTTONUP: + return {QEvent::NonClientAreaMouseButtonRelease, Qt::LeftButton}; + case WM_NCLBUTTONDBLCLK: + return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton}; + case WM_NCMBUTTONDOWN: + return {QEvent::NonClientAreaMouseButtonPress, Qt::MidButton}; + case WM_NCMBUTTONUP: + return {QEvent::NonClientAreaMouseButtonRelease, Qt::MidButton}; + case WM_NCMBUTTONDBLCLK: + return {QEvent::NonClientAreaMouseButtonPress, Qt::MidButton}; + case WM_NCRBUTTONDOWN: + return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton}; + case WM_NCRBUTTONUP: + return {QEvent::NonClientAreaMouseButtonRelease, Qt::RightButton}; + case WM_NCRBUTTONDBLCLK: + return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton}; + default: // WM_MOUSELEAVE + break; + } + return {QEvent::None, Qt::NoButton}; } static Qt::MouseButtons mouseButtonsFromKeyState(WPARAM keyState) @@ -419,15 +291,6 @@ static bool isValidWheelReceiver(QWindow *candidate) return false; } -static bool isMenuWindow(QWindow *window) -{ - if (window) - if (QObject *fo = window->focusObject()) - if (fo->inherits("QMenu")) - return true; - return false; -} - static QTouchDevice *createTouchDevice() { const int digitizers = GetSystemMetrics(SM_DIGITIZER); @@ -553,71 +416,6 @@ void QWindowsPointerHandler::handleEnterLeave(QWindow *window, m_previousCaptureWindow = hasCapture ? window : nullptr; } -bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND hwnd, - QtWindows::WindowsEventType et, - MSG msg, PVOID vPointerInfo) -{ - POINTER_INFO *pointerInfo = static_cast(vPointerInfo); - const QPoint globalPos = QPoint(pointerInfo->ptPixelLocation.x, pointerInfo->ptPixelLocation.y); - const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos); - const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); - const Qt::MouseButtons mouseButtons = mouseButtonsFromPointerFlags(pointerInfo->pointerFlags); - QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos); - - switch (msg.message) { - case WM_NCPOINTERDOWN: - case WM_NCPOINTERUP: - case WM_NCPOINTERUPDATE: - case WM_POINTERDOWN: - case WM_POINTERUP: - case WM_POINTERUPDATE: { - - QEvent::Type eventType; - Qt::MouseButton button; - getMouseEventInfo(msg.message, pointerInfo->ButtonChangeType, &eventType, &button); - - if (et & QtWindows::NonClientEventFlag) { - QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons, button, eventType, - keyModifiers, Qt::MouseEventNotSynthesized); - return false; // To allow window dragging, etc. - } else { - - handleCaptureRelease(window, currentWindowUnderPointer, hwnd, eventType, mouseButtons); - handleEnterLeave(window, currentWindowUnderPointer, globalPos); - - QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, button, eventType, - keyModifiers, Qt::MouseEventNotSynthesized); - - // The initial down click over the QSizeGrip area, which posts a resize WM_SYSCOMMAND - // has go to through DefWindowProc() for resizing to work, so we return false here, - // unless the click was on a menu, as it would mess with menu processing. - return msg.message != WM_POINTERDOWN || isMenuWindow(window); - } - } - case WM_POINTERHWHEEL: - case WM_POINTERWHEEL: { - - if (!isValidWheelReceiver(window)) - return true; - - int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam); - - // Qt horizontal wheel rotation orientation is opposite to the one in WM_POINTERHWHEEL - if (msg.message == WM_POINTERHWHEEL) - delta = -delta; - - const QPoint angleDelta = (msg.message == WM_POINTERHWHEEL || (keyModifiers & Qt::AltModifier)) ? - QPoint(delta, 0) : QPoint(0, delta); - - QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers); - return true; - } - case WM_POINTERLEAVE: - return true; - } - return false; -} - bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vTouchInfo, quint32 count) @@ -653,15 +451,14 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, QList touchPoints; - bool primaryPointer = false; - bool pressRelease = false; - if (QWindowsContext::verbose > 1) qCDebug(lcQpaEvents).noquote().nospace() << showbase << __FUNCTION__ << " message=" << hex << msg.message << " count=" << dec << count; + Qt::TouchPointStates allStates = 0; + for (quint32 i = 0; i < count; ++i) { if (QWindowsContext::verbose > 1) qCDebug(lcQpaEvents).noquote().nospace() << showbase @@ -670,7 +467,13 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, << " flags=" << hex << touchInfo[i].pointerInfo.pointerFlags; QWindowSystemInterface::TouchPoint touchPoint; - touchPoint.id = touchInfo[i].pointerInfo.pointerId; + const quint32 pointerId = touchInfo[i].pointerInfo.pointerId; + int id = m_touchInputIDToTouchPointID.value(pointerId, -1); + if (id == -1) { + id = m_touchInputIDToTouchPointID.size(); + m_touchInputIDToTouchPointID.insert(pointerId, id); + } + touchPoint.id = id; touchPoint.pressure = (touchInfo[i].touchMask & TOUCH_MASK_PRESSURE) ? touchInfo[i].pressure / 1024.0 : 1.0; if (m_lastTouchPositions.contains(touchPoint.id)) @@ -691,32 +494,27 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_DOWN) { touchPoint.state = Qt::TouchPointPressed; m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition); - pressRelease = true; } else if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_UP) { touchPoint.state = Qt::TouchPointReleased; m_lastTouchPositions.remove(touchPoint.id); - pressRelease = true; } else { touchPoint.state = stationaryTouchPoint ? Qt::TouchPointStationary : Qt::TouchPointMoved; m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition); } - if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_PRIMARY) - primaryPointer = true; + allStates |= touchPoint.state; touchPoints.append(touchPoint); // Avoid getting repeated messages for this frame if there are multiple pointerIds QWindowsContext::user32dll.skipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId); } - if (primaryPointer && !pressRelease) { - // Postpone event delivery to avoid hanging inside DoDragDrop(). - // Only the primary pointer will generate mouse messages. - enqueueTouchEvent(window, touchPoints, QWindowsKeyMapper::queryKeyboardModifiers()); - } else { - flushTouchEvents(m_touchDevice); - QWindowSystemInterface::handleTouchEvent(window, m_touchDevice, touchPoints, - QWindowsKeyMapper::queryKeyboardModifiers()); - } + + // all touch points released, forget the ids we've seen. + if (allStates == Qt::TouchPointReleased) + m_touchInputIDToTouchPointID.clear(); + + QWindowSystemInterface::handleTouchEvent(window, m_touchDevice, touchPoints, + QWindowsKeyMapper::queryKeyboardModifiers()); return false; // Allow mouse messages to be generated. } @@ -807,10 +605,9 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin } const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); - // Postpone event delivery to avoid hanging inside DoDragDrop(). - enqueueTabletEvent(target, localPos, hiResGlobalPos, device, type, mouseButtons, - pressure, xTilt, yTilt, tangentialPressure, rotation, z, - pointerId, keyModifiers); + QWindowSystemInterface::handleTabletEvent(target, localPos, hiResGlobalPos, device, type, mouseButtons, + pressure, xTilt, yTilt, tangentialPressure, rotation, z, + pointerId, keyModifiers); return false; // Allow mouse messages to be generated. } } @@ -835,18 +632,46 @@ static inline bool isMouseEventSynthesizedFromPenOrTouch() return ((::GetMessageExtraInfo() & SIGNATURE_MASK) == MI_WP_SIGNATURE); } -// Process old-style mouse messages here. -bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result) +bool QWindowsPointerHandler::translateMouseWheelEvent(QWindow *window, + QWindow *currentWindowUnderPointer, + MSG msg, + QPoint globalPos, + Qt::KeyboardModifiers keyModifiers) { - // Generate enqueued events. - flushTouchEvents(m_touchDevice); - flushTabletEvents(); + QWindow *receiver = currentWindowUnderPointer; + if (!isValidWheelReceiver(receiver)) + receiver = window; + if (!isValidWheelReceiver(receiver)) + return true; + + int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam); + // Qt horizontal wheel rotation orientation is opposite to the one in WM_MOUSEHWHEEL + if (msg.message == WM_MOUSEHWHEEL) + delta = -delta; + + const QPoint angleDelta = (msg.message == WM_MOUSEHWHEEL || (keyModifiers & Qt::AltModifier)) ? + QPoint(delta, 0) : QPoint(0, delta); + + QPoint localPos = QWindowsGeometryHint::mapFromGlobal(receiver, globalPos); + + QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers); + return true; +} + +// Process legacy mouse messages here. +bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, + HWND hwnd, + QtWindows::WindowsEventType et, + MSG msg, + LRESULT *result) +{ *result = 0; const QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)); QPoint localPos; QPoint globalPos; + if ((et == QtWindows::MouseWheelEvent) || (et & QtWindows::NonClientEventFlag)) { globalPos = eventPos; localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, eventPos); @@ -857,46 +682,39 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); const Qt::MouseButtons mouseButtons = mouseButtonsFromKeyState(msg.wParam); + QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos); - // Handle "press and hold for right-clicking". - // We have to synthesize it here as it only comes from Windows as a fake RMB. - // MS docs say we could use bit 7 from extraInfo to distinguish pen from touch, - // but on the Surface it is set for both. So we use the last pointer type. - if (isMouseEventSynthesizedFromPenOrTouch()) { - if ((msg.message == WM_RBUTTONDOWN || msg.message == WM_RBUTTONUP) - && (((m_lastPointerType == QT_PT_PEN) - && QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents)) - || ((m_lastPointerType == QT_PT_TOUCH) - && QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)))) { - QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, Qt::RightButton, - (msg.message == WM_RBUTTONDOWN) ? QEvent::MouseButtonPress - : QEvent::MouseButtonRelease, - keyModifiers, Qt::MouseEventSynthesizedBySystem); - } - // Messages synthesized from touch/pen are only used for flushing queues and press&hold. - return false; + if (et == QtWindows::MouseWheelEvent) + return translateMouseWheelEvent(window, currentWindowUnderPointer, msg, globalPos, keyModifiers); + + // Windows sends a mouse move with no buttons pressed to signal "Enter" + // when a window is shown over the cursor. Discard the event and only use + // it for generating QEvent::Enter to be consistent with other platforms - + // X11 and macOS. + bool discardEvent = false; + if (msg.message == WM_MOUSEMOVE) { + static QPoint lastMouseMovePos; + if (msg.wParam == 0 && (m_windowUnderPointer.isNull() || globalPos == lastMouseMovePos)) + discardEvent = true; + lastMouseMovePos = globalPos; } - if (et == QtWindows::MouseWheelEvent) { - - if (!isValidWheelReceiver(window)) - return true; - - int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam); - - // Qt horizontal wheel rotation orientation is opposite to the one in WM_MOUSEHWHEEL - if (msg.message == WM_MOUSEHWHEEL) - delta = -delta; + Qt::MouseEventSource source = Qt::MouseEventNotSynthesized; + if (isMouseEventSynthesizedFromPenOrTouch()) { + if (QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch) + return false; + source = Qt::MouseEventSynthesizedBySystem; + } - const QPoint angleDelta = (msg.message == WM_MOUSEHWHEEL || (keyModifiers & Qt::AltModifier)) ? - QPoint(delta, 0) : QPoint(0, delta); + const MouseEvent mouseEvent = eventFromMsg(msg); - QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers); - return true; + if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) { + QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons, + mouseEvent.button, mouseEvent.type, keyModifiers, source); + return false; // Allow further event processing } if (msg.message == WM_MOUSELEAVE) { - if (window == m_currentWindow) { QWindow *leaveTarget = m_windowUnderPointer ? m_windowUnderPointer : m_currentWindow; qCDebug(lcQpaEvents) << "Leaving window " << leaveTarget; @@ -904,14 +722,21 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW m_windowUnderPointer = nullptr; m_currentWindow = nullptr; } + return true; + } - } else if (msg.message == WM_MOUSEMOVE) { + handleCaptureRelease(window, currentWindowUnderPointer, hwnd, mouseEvent.type, mouseButtons); + handleEnterLeave(window, currentWindowUnderPointer, globalPos); - QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos); - handleCaptureRelease(window, currentWindowUnderPointer, hwnd, QEvent::MouseMove, mouseButtons); - handleEnterLeave(window, currentWindowUnderPointer, globalPos); + if (!discardEvent && mouseEvent.type != QEvent::None) { + QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, + mouseEvent.button, mouseEvent.type, keyModifiers, source); } - return false; + + // QTBUG-48117, force synchronous handling for the extra buttons so that WM_APPCOMMAND + // is sent for unhandled WM_XBUTTONDOWN. + return (msg.message != WM_XBUTTONUP && msg.message != WM_XBUTTONDOWN && msg.message != WM_XBUTTONDBLCLK) + || QWindowSystemInterface::flushWindowSystemEvents(); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.h b/src/plugins/platforms/windows/qwindowspointerhandler.h index ec3179e821..aebef062bc 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.h +++ b/src/plugins/platforms/windows/qwindowspointerhandler.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -66,19 +66,19 @@ public: void clearWindowUnderMouse() { m_windowUnderPointer = nullptr; } private: - bool translateMouseTouchPadEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPointerInfo); 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); + bool translateMouseWheelEvent(QWindow *window, QWindow *currentWindowUnderPointer, MSG msg, QPoint globalPos, Qt::KeyboardModifiers keyModifiers); void handleCaptureRelease(QWindow *window, QWindow *currentWindowUnderPointer, HWND hwnd, QEvent::Type eventType, Qt::MouseButtons mouseButtons); void handleEnterLeave(QWindow *window, QWindow *currentWindowUnderPointer, QPoint globalPos); QTouchDevice *m_touchDevice = nullptr; QHash m_lastTouchPositions; + QHash m_touchInputIDToTouchPointID; QPointer m_windowUnderPointer; QPointer m_currentWindow; QWindow *m_previousCaptureWindow = nullptr; bool m_needsEnterOnPointerUpdate = false; - DWORD m_lastPointerType = 0; }; QT_END_NAMESPACE -- cgit v1.2.3 From 81fd7f4c8af260d753a834480f790c82fb161889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 12 Feb 2019 14:06:08 +0100 Subject: macOS: Add auto-release pool during QCocoaScreen::deliverUpdateRequests() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Checking the application's keyWindow will autorelease the window, and there's no root pool in place when called from the display-link thread. Change-Id: Ic43164ad6397c92b858fb549f7a00e28b6110849 Reviewed-by: Morten Johan Sørvig Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoascreen.mm | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm index 80dd7e40d3..830a387fd1 100644 --- a/src/plugins/platforms/cocoa/qcocoascreen.mm +++ b/src/plugins/platforms/cocoa/qcocoascreen.mm @@ -269,6 +269,8 @@ struct DeferredDebugHelper void QCocoaScreen::deliverUpdateRequests() { + QMacAutoReleasePool pool; + // The CVDisplayLink callback is a notification that it's a good time to produce a new frame. // Since the callback is delivered on a separate thread we have to marshal it over to the // main thread, as Qt requires update requests to be delivered there. This needs to happen -- cgit v1.2.3 From 960af0d64de576321db91ccbe426891465b24540 Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Wed, 30 Jan 2019 18:17:39 +1000 Subject: wasm: remove EM_ASM calls in wasm platform plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I8453836b6730d18eaaa4ffe1fb9cb3933079ebee Reviewed-by: Edward Welbourne Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/wasm/qwasmcursor.cpp | 7 ++--- .../platforms/wasm/qwasmeventtranslator.cpp | 33 +++++++++++----------- src/plugins/platforms/wasm/qwasmintegration.cpp | 17 ++++------- src/plugins/platforms/wasm/qwasmscreen.cpp | 5 ++-- 4 files changed, 27 insertions(+), 35 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/wasm/qwasmcursor.cpp b/src/plugins/platforms/wasm/qwasmcursor.cpp index 54804a55b3..90431ab6a5 100644 --- a/src/plugins/platforms/wasm/qwasmcursor.cpp +++ b/src/plugins/platforms/wasm/qwasmcursor.cpp @@ -32,6 +32,7 @@ #include #include +#include void QWasmCursor::changeCursor(QCursor *windowCursor, QWindow *window) { @@ -52,11 +53,7 @@ void QWasmCursor::changeCursor(QCursor *windowCursor, QWindow *window) htmlCursorName = "auto"; // Set cursor on the main canvas - EM_ASM_ARGS({ - if (Module['canvas']) { - Module['canvas'].style['cursor'] = Pointer_stringify($0); - } - }, htmlCursorName.constData()); + emscripten::val::global("window").set("cursor", emscripten::val(htmlCursorName.constData())); } QByteArray QWasmCursor::cursorShapeToHtml(Qt::CursorShape shape) diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp index 8ab109f03c..ea88ef59a0 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp @@ -52,12 +52,17 @@ static bool g_usePlatformMacCtrlMetaSwitching = false; bool g_useNaturalScrolling = true; // natural scrolling is default on linux/windows -void setNaturalScrolling(bool use) { - g_useNaturalScrolling = use; +static void mouseWheelEvent(emscripten::val event) { + + emscripten::val wheelInterted = event["webkitDirectionInvertedFromDevice"]; + + if (wheelInterted.as()) { + g_useNaturalScrolling = true; + } } EMSCRIPTEN_BINDINGS(mouse_module) { - function("setNaturalScrolling", &setNaturalScrolling); + function("mouseWheelEvent", &mouseWheelEvent); } QWasmEventTranslator::QWasmEventTranslator(QObject *parent) @@ -93,23 +98,19 @@ QWasmEventTranslator::QWasmEventTranslator(QObject *parent) GenericPlatform, MacOSPlatform }; - Platform platform = - Platform(EM_ASM_INT("if (navigator.platform.includes(\"Mac\")) return 1; return 0;")); - + Platform platform = Platform(emscripten::val::global("navigator")["platform"] + .call("includes", emscripten::val("Mac"))); g_usePlatformMacCtrlMetaSwitching = (platform == MacOSPlatform); if (platform == MacOSPlatform) { g_useNaturalScrolling = false; // make this !default on macOS - EM_ASM( - if (window.safari !== undefined) {//this only works on safari - Module["canvas"].addEventListener('wheel', mouseWheelEvent); - function mouseWheelEvent(e) { - if (event.webkitDirectionInvertedFromDevice) { - Module.setNaturalScrolling(event.webkitDirectionInvertedFromDevice); - } - } - } - ); + + if (emscripten::val::global("window")["safari"].isUndefined()) { + + emscripten::val::global("canvas").call("addEventListener", + std::string("wheel"), + val::module_property("mouseWheelEvent")); + } } } diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp index 1be909f0a0..7a44c47893 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.cpp +++ b/src/plugins/platforms/wasm/qwasmintegration.cpp @@ -55,7 +55,7 @@ using namespace emscripten; QT_BEGIN_NAMESPACE -void browserBeforeUnload() +void browserBeforeUnload(emscripten::val) { QWasmIntegration::QWasmBrowserExit(); } @@ -83,11 +83,8 @@ QWasmIntegration::QWasmIntegration() m_eventTranslator = new QWasmEventTranslator; - EM_ASM(// exit app if browser closes - window.onbeforeunload = function () { - Module.browserBeforeUnload(); - }; - ); + emscripten::val::global("window").set("onbeforeunload", val::module_property("browserBeforeUnload")); + } QWasmIntegration::~QWasmIntegration() @@ -187,11 +184,9 @@ int QWasmIntegration::uiEvent_cb(int eventType, const EmscriptenUiEvent *e, void static void set_canvas_size(double width, double height) { - EM_ASM_({ - var canvas = Module.canvas; - canvas.width = $0; - canvas.height = $1; - }, width, height); + emscripten::val canvas = emscripten::val::global("canvas"); + canvas.set("width", width); + canvas.set("height", height); } void QWasmIntegration::updateQScreenAndCanvasRenderSize() diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp index 93e9906ffc..37f1efadc6 100644 --- a/src/plugins/platforms/wasm/qwasmscreen.cpp +++ b/src/plugins/platforms/wasm/qwasmscreen.cpp @@ -30,6 +30,7 @@ #include "qwasmscreen.h" #include "qwasmwindow.h" #include "qwasmcompositor.h" +#include #include #ifndef QT_NO_OPENGL @@ -77,9 +78,7 @@ qreal QWasmScreen::devicePixelRatio() const // HTML window dpr if the OpenGL driver/GPU allocates a less than // full resolution surface. Use emscripten_webgl_get_drawing_buffer_size() // and compute the dpr instead. - double htmlWindowDpr = EM_ASM_DOUBLE({ - return window.devicePixelRatio; - }); + double htmlWindowDpr = emscripten::val::global("window")["devicePixelRatio"].as(); return qreal(htmlWindowDpr); } -- cgit v1.2.3 From 7d2d1eb9e051ad01dc5c5c3053c58364885bdc07 Mon Sep 17 00:00:00 2001 From: Volker Krause Date: Sat, 26 Jan 2019 18:30:56 +0100 Subject: Add file engine for Android content URLs The "file dialog" on Android returns such URLs, which so far required special-casing this in application code. With this change QFile can consume those URLs directly. Change-Id: I489c0db112cf1dc7497e7a90f0e9a79ea8fa5237 Reviewed-by: Nicolas Fella Reviewed-by: BogDan Vatra Reviewed-by: Aleix Pol Gonzalez --- src/plugins/platforms/android/android.pro | 2 + .../platforms/android/androidcontentfileengine.cpp | 92 ++++++++++++++++++++++ .../platforms/android/androidcontentfileengine.h | 60 ++++++++++++++ src/plugins/platforms/android/androidjnimain.cpp | 5 ++ 4 files changed, 159 insertions(+) create mode 100644 src/plugins/platforms/android/androidcontentfileengine.cpp create mode 100644 src/plugins/platforms/android/androidcontentfileengine.h (limited to 'src/plugins') diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro index f91db1ab5f..78632a9bea 100644 --- a/src/plugins/platforms/android/android.pro +++ b/src/plugins/platforms/android/android.pro @@ -20,6 +20,7 @@ INCLUDEPATH += \ $$QT_SOURCE_TREE/src/3rdparty/android SOURCES += $$PWD/androidplatformplugin.cpp \ + $$PWD/androidcontentfileengine.cpp \ $$PWD/androiddeadlockprotector.cpp \ $$PWD/androidjnimain.cpp \ $$PWD/androidjniaccessibility.cpp \ @@ -50,6 +51,7 @@ SOURCES += $$PWD/androidplatformplugin.cpp \ $$PWD/qandroidplatformfiledialoghelper.cpp HEADERS += $$PWD/qandroidplatformintegration.h \ + $$PWD/androidcontentfileengine.h \ $$PWD/androiddeadlockprotector.h \ $$PWD/androidjnimain.h \ $$PWD/androidjniaccessibility.h \ diff --git a/src/plugins/platforms/android/androidcontentfileengine.cpp b/src/plugins/platforms/android/androidcontentfileengine.cpp new file mode 100644 index 0000000000..1444407195 --- /dev/null +++ b/src/plugins/platforms/android/androidcontentfileengine.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Volker Krause +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "androidcontentfileengine.h" + +#include +#include + +#include + +AndroidContentFileEngine::AndroidContentFileEngine(const QString &fileName) + : QFSFileEngine(fileName) +{ +} + +bool AndroidContentFileEngine::open(QIODevice::OpenMode openMode) +{ + QString openModeStr; + if (openMode & QFileDevice::ReadOnly) { + openModeStr += QLatin1Char('r'); + } + if (openMode & QFileDevice::WriteOnly) { + openModeStr += QLatin1Char('w'); + } + if (openMode & QFileDevice::Truncate) { + openModeStr += QLatin1Char('t'); + } else if (openMode & QFileDevice::Append) { + openModeStr += QLatin1Char('a'); + } + + const auto fd = QJNIObjectPrivate::callStaticMethod("org/qtproject/qt5/android/QtNative", + "openFdForContentUrl", + "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I", + QtAndroidPrivate::context(), + QJNIObjectPrivate::fromString(fileName(DefaultName)).object(), + QJNIObjectPrivate::fromString(openModeStr).object()); + + if (fd < 0) { + return false; + } + + return QFSFileEngine::open(openMode, fd, QFile::AutoCloseHandle); +} + + +AndroidContentFileEngineHandler::AndroidContentFileEngineHandler() = default; +AndroidContentFileEngineHandler::~AndroidContentFileEngineHandler() = default; + +QAbstractFileEngine* AndroidContentFileEngineHandler::create(const QString &fileName) const +{ + if (!fileName.startsWith(QLatin1String("content"))) { + return nullptr; + } + + return new AndroidContentFileEngine(fileName); +} diff --git a/src/plugins/platforms/android/androidcontentfileengine.h b/src/plugins/platforms/android/androidcontentfileengine.h new file mode 100644 index 0000000000..db3def03d6 --- /dev/null +++ b/src/plugins/platforms/android/androidcontentfileengine.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Volker Krause +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ANDROIDCONTENTFILEENGINE_H +#define ANDROIDCONTENTFILEENGINE_H + +#include + +class AndroidContentFileEngine : public QFSFileEngine +{ +public: + AndroidContentFileEngine(const QString &fileName); + bool open(QIODevice::OpenMode openMode) override; +}; + +class AndroidContentFileEngineHandler : public QAbstractFileEngineHandler +{ +public: + AndroidContentFileEngineHandler(); + ~AndroidContentFileEngineHandler(); + QAbstractFileEngine *create(const QString &fileName) const override; +}; + +#endif // ANDROIDCONTENTFILEENGINE_H diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 13d41bea99..37cfbc13ec 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -49,6 +49,7 @@ #include "androidjniinput.h" #include "androidjniclipboard.h" #include "androidjnimenu.h" +#include "androidcontentfileengine.h" #include "androiddeadlockprotector.h" #include "qandroidplatformdialoghelpers.h" #include "qandroidplatformintegration.h" @@ -116,6 +117,7 @@ static double m_scaledDensity = 0; static double m_density = 1.0; static AndroidAssetsFileEngineHandler *m_androidAssetsFileEngineHandler = nullptr; +static AndroidContentFileEngineHandler *m_androidContentFileEngineHandler = nullptr; @@ -445,6 +447,7 @@ static jboolean startQtAndroidPlugin(JNIEnv *env, jobject /*object*/, jstring pa { m_androidPlatformIntegration = nullptr; m_androidAssetsFileEngineHandler = new AndroidAssetsFileEngineHandler(); + m_androidContentFileEngineHandler = new AndroidContentFileEngineHandler(); m_mainLibraryHnd = nullptr; { // Set env. vars const char *nativeString = env->GetStringUTFChars(environmentString, 0); @@ -555,6 +558,8 @@ static void quitQtAndroidPlugin(JNIEnv *env, jclass /*clazz*/) m_androidPlatformIntegration = nullptr; delete m_androidAssetsFileEngineHandler; m_androidAssetsFileEngineHandler = nullptr; + delete m_androidContentFileEngineHandler; + m_androidContentFileEngineHandler = nullptr; } static void terminateQt(JNIEnv *env, jclass /*clazz*/) -- cgit v1.2.3 From 48f5b671a3102df50115e566c01298f3e9106654 Mon Sep 17 00:00:00 2001 From: Michal Klocek Date: Mon, 19 Nov 2018 15:49:48 +0100 Subject: Add native handle for context in offscreen plugin Offscreen plugin can be compiled with x11 support. In case of glx add missing native handle for context. This fixes crashes of running web engine with offscreenplugin (with glx support). Task-number: QTBUG-63346 Change-Id: Ia717ad2551536fbfdfb6633e506704a3ebe42a2b Reviewed-by: Laszlo Agocs --- src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp index 06a9bd2a4c..38d06a4131 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp +++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp @@ -41,6 +41,7 @@ #include #include +#include #include #include @@ -228,6 +229,9 @@ QOffscreenX11GLXContext::QOffscreenX11GLXContext(QOffscreenX11Info *x11, QOpenGL d->window = createDummyWindow(x11, visualInfo); XFree(visualInfo); } + if (d->context) + context->setNativeHandle(QVariant::fromValue(QGLXNativeContext(d->context))); + } QOffscreenX11GLXContext::~QOffscreenX11GLXContext() -- cgit v1.2.3 From 652e9146ac3a28a166928f7e594dfa1c3514e912 Mon Sep 17 00:00:00 2001 From: Michal Klocek Date: Fri, 8 Feb 2019 13:51:05 +0100 Subject: Fix incorrect surface type in offscreen plugin In case we use glx backend set correct surface. Task-number: QTBUG-63346 Change-Id: I5827bf5b8e4ed60b933c25ce234fdd4a3dd20c88 Reviewed-by: Laszlo Agocs --- src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp index 38d06a4131..2e9f1eec2c 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp +++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp @@ -87,6 +87,7 @@ bool QOffscreenX11Integration::hasCapability(QPlatformIntegration::Capability ca switch (cap) { case OpenGL: return true; case ThreadedOpenGL: return true; + case RasterGLSurface: return true; default: return QOffscreenIntegration::hasCapability(cap); } } @@ -196,6 +197,12 @@ QOffscreenX11GLXContext::QOffscreenX11GLXContext(QOffscreenX11Info *x11, QOpenGL d->x11 = x11; d->format = context->format(); + if (d->format.renderableType() == QSurfaceFormat::DefaultRenderableType) + d->format.setRenderableType(QSurfaceFormat::OpenGL); + + if (d->format.renderableType() != QSurfaceFormat::OpenGL) + return; + d->shareContext = 0; if (context->shareHandle()) d->shareContext = static_cast(context->shareHandle())->d->context; -- cgit v1.2.3 From 6bad49308a9d943200fd48a8c9f732de20250bed Mon Sep 17 00:00:00 2001 From: Michal Klocek Date: Fri, 8 Feb 2019 14:00:42 +0100 Subject: Fix handling of glxconfig and glxcontext in offscreen plugin Return glxconfig and glxcontext, it is needed by share context in chromium. Task-number: QTBUG-63346 Change-Id: Ief15bf7170af9cf61a71453043a2629a4bcbcdc2 Reviewed-by: Laszlo Agocs --- .../offscreen/qoffscreenintegration_x11.cpp | 38 +++++++++++++++++----- .../offscreen/qoffscreenintegration_x11.h | 3 ++ 2 files changed, 32 insertions(+), 9 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp index 2e9f1eec2c..2532cedc70 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp +++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp @@ -122,11 +122,16 @@ void *QOffscreenX11Integration::nativeResourceForScreen(const QByteArray &resour #ifndef QT_NO_OPENGL void *QOffscreenX11Integration::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) { if (resource.toLower() == QByteArrayLiteral("glxconfig") ) { - if (!m_connection) - m_connection.reset(new QOffscreenX11Connection); - QOffscreenX11Info *x11 = m_connection->x11Info(); - GLXFBConfig config = qglx_findConfig(x11->display(), x11->screenNumber(), context->format()); - return config; + if (context) { + QOffscreenX11GLXContext *glxPlatformContext = static_cast(context->handle()); + return glxPlatformContext->glxConfig(); + } + } + if (resource.toLower() == QByteArrayLiteral("glxcontext") ) { + if (context) { + QOffscreenX11GLXContext *glxPlatformContext = static_cast(context->handle()); + return glxPlatformContext->glxContext(); + } } return nullptr; } @@ -158,11 +163,12 @@ QOffscreenX11Info *QOffscreenX11Connection::x11Info() class QOffscreenX11GLXContextData { public: - QOffscreenX11Info *x11; + QOffscreenX11Info *x11 = nullptr; QSurfaceFormat format; - GLXContext context; - GLXContext shareContext; - Window window; + GLXContext context = nullptr; + GLXContext shareContext = nullptr; + GLXFBConfig config = nullptr; + Window window = 0; }; static Window createDummyWindow(QOffscreenX11Info *x11, XVisualInfo *visualInfo) @@ -173,6 +179,7 @@ static Window createDummyWindow(QOffscreenX11Info *x11, XVisualInfo *visualInfo) a.border_pixel = BlackPixel(x11->display(), x11->screenNumber()); a.colormap = cmap; + Window window = XCreateWindow(x11->display(), x11->root(), 0, 0, 100, 100, 0, visualInfo->depth, InputOutput, visualInfo->visual, @@ -194,6 +201,7 @@ static Window createDummyWindow(QOffscreenX11Info *x11, GLXFBConfig config) QOffscreenX11GLXContext::QOffscreenX11GLXContext(QOffscreenX11Info *x11, QOpenGLContext *context) : d(new QOffscreenX11GLXContextData) { + d->x11 = x11; d->format = context->format(); @@ -208,6 +216,8 @@ QOffscreenX11GLXContext::QOffscreenX11GLXContext(QOffscreenX11Info *x11, QOpenGL d->shareContext = static_cast(context->shareHandle())->d->context; GLXFBConfig config = qglx_findConfig(x11->display(), x11->screenNumber(), d->format); + d->config = config; + if (config) { d->context = glXCreateNewContext(x11->display(), config, GLX_RGBA_TYPE, d->shareContext, true); if (!d->context && d->shareContext) { @@ -291,4 +301,14 @@ bool QOffscreenX11GLXContext::isValid() const return d->context && d->window; } +void *QOffscreenX11GLXContext::glxContext() const +{ + return d->context; +} + +void *QOffscreenX11GLXContext::glxConfig() const +{ + return d->config; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h index a1986fdc94..5ef51a15a8 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h +++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h @@ -104,6 +104,9 @@ public: bool isSharing() const override; bool isValid() const override; + void *glxConfig() const; + void *glxContext() const; + private: QScopedPointer d; }; -- cgit v1.2.3 From a2c9f9433a772c03e6aaf820910487d794280c3a Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Wed, 6 Feb 2019 11:24:17 +0100 Subject: winrt: Handle WaitForWindowExposed As winrt does not have native windows, exposure check was just done by checking, whether the window is the active window. If a window is shown fullscreen though, winrtscreen will be resized. This resize triggers a resize of every maximized or fullscreen window that is shown. If we enter or leave full screen mode, we have to wait until the screen resize and the subsequent window resizes are done and only then we can consider the windows properly exposed. This patch reverts 54bcb9d42f5ceaafcca426dc2a5cc25d299d5a3d and thus unblacklists tst_QGraphicsItem::cursor on WinRT. Fixes: QTBUG-73545 Change-Id: If469fce319ed6b3a5d56b7bf3cbc11929b72bb11 Reviewed-by: Andre de la Rocha Reviewed-by: Qt CI Bot Reviewed-by: Maurice Kalinowski --- src/plugins/platforms/winrt/qwinrtscreen.cpp | 18 +++++++++++++++++- src/plugins/platforms/winrt/qwinrtscreen.h | 3 +++ src/plugins/platforms/winrt/qwinrtwindow.cpp | 5 ++++- 3 files changed, 24 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 7f1854c601..e611c7be24 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -511,6 +511,7 @@ public: QWindow *currentPressWindow = nullptr; QWindow *currentTargetWindow = nullptr; bool firstMouseMove = true; + bool resizePending = false; }; // To be called from the XAML thread @@ -1402,6 +1403,18 @@ void QWinRTScreen::emulateMouseMove(const QPointF &point, MousePositionTransitio Qt::NoModifier); } +void QWinRTScreen::setResizePending() +{ + Q_D(QWinRTScreen); + d->resizePending = true; +} + +bool QWinRTScreen::resizePending() const +{ + Q_D(const QWinRTScreen); + return d->resizePending; +} + HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args) { Q_D(QWinRTScreen); @@ -1507,7 +1520,7 @@ HRESULT QWinRTScreen::onRedirectReleased(ICorePointerRedirector *, IPointerEvent return onPointerUpdated(nullptr, args); } -HRESULT QWinRTScreen::onWindowSizeChanged(IApplicationView *, IInspectable *) +HRESULT QWinRTScreen::onWindowSizeChanged(IApplicationView *w, IInspectable *) { Q_D(QWinRTScreen); @@ -1527,6 +1540,9 @@ HRESULT QWinRTScreen::onWindowSizeChanged(IApplicationView *, IInspectable *) QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry()); QPlatformScreen::resizeMaximizedWindows(); handleExpose(); + // If we "emulate" a resize, w will be nullptr.Checking w shows whether it's a real resize + if (w) + d->resizePending = false; return S_OK; } diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h index e28cfd8cc8..63c254940d 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -136,6 +136,9 @@ public: void emulateMouseMove(const QPointF &point, MousePositionTransition transition); + void setResizePending(); + bool resizePending() const; + private: void handleExpose(); diff --git a/src/plugins/platforms/winrt/qwinrtwindow.cpp b/src/plugins/platforms/winrt/qwinrtwindow.cpp index 83c3715bfd..73816b6512 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.cpp +++ b/src/plugins/platforms/winrt/qwinrtwindow.cpp @@ -225,7 +225,8 @@ bool QWinRTWindow::isActive() const bool QWinRTWindow::isExposed() const { - const bool exposed = isActive(); + Q_D(const QWinRTWindow); + const bool exposed = isActive() && !d->screen->resizePending(); return exposed; } @@ -360,6 +361,7 @@ void QWinRTWindow::setWindowState(Qt::WindowStates state) qCDebug(lcQpaWindows) << "Failed to enter full screen mode."; return; } + d->screen->setResizePending(); d->state = state; return; } @@ -384,6 +386,7 @@ void QWinRTWindow::setWindowState(Qt::WindowStates state) qCDebug(lcQpaWindows) << "Failed to exit full screen mode."; return; } + d->screen->setResizePending(); } if (d->state & Qt::WindowMinimized || state == Qt::WindowNoState || state == Qt::WindowActive) -- cgit v1.2.3 From 2c6c724949374b17bd3da2938fe8747b480d575a Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Thu, 22 Feb 2018 04:35:25 +1000 Subject: wasm: add clipboard support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This feature uses the js Clipboard API and is supported only in Chrome, as Firefox only supports reading the clipboard in browser extensions. It also requires https or localhost access, otherwise access to the clipboard is blocked by chrome. Chrome users will be able to copy/paste text to and from the system clipbaord. Other browsers will be able to use the clipboard from within the same application. Currently only supports text and html. Task-number: QTBUG-64638 Change-Id: Ie6de9d10812b776519bd6115593b433fe77059fe Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/wasm/qwasmclipboard.cpp | 204 +++++++++++++++++++++ src/plugins/platforms/wasm/qwasmclipboard.h | 59 ++++++ .../platforms/wasm/qwasmeventtranslator.cpp | 23 ++- src/plugins/platforms/wasm/qwasmintegration.cpp | 18 +- src/plugins/platforms/wasm/qwasmintegration.h | 8 +- src/plugins/platforms/wasm/wasm.pro | 6 +- 6 files changed, 307 insertions(+), 11 deletions(-) create mode 100644 src/plugins/platforms/wasm/qwasmclipboard.cpp create mode 100644 src/plugins/platforms/wasm/qwasmclipboard.h (limited to 'src/plugins') diff --git a/src/plugins/platforms/wasm/qwasmclipboard.cpp b/src/plugins/platforms/wasm/qwasmclipboard.cpp new file mode 100644 index 0000000000..ec058f05dd --- /dev/null +++ b/src/plugins/platforms/wasm/qwasmclipboard.cpp @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwasmclipboard.h" +#include "qwasmwindow.h" + +#include +#include +#include + +#include +#include + +using namespace emscripten; + +// there has got to be a better way... +static QByteArray g_clipboardArray; +static QByteArray g_clipboardFormat; + +static val getClipboardData() +{ + return val(g_clipboardArray.constData()); +} + +static val getClipboardFormat() +{ + return val(g_clipboardFormat.constData()); +} + +static void pasteClipboardData(emscripten::val format, emscripten::val dataPtr) +{ + QString formatString = QString::fromStdString(format.as()); + QByteArray dataArray = QByteArray::fromStdString(dataPtr.as()); + QMimeData *mMimeData = new QMimeData; + mMimeData->setData(formatString, dataArray); + QWasmClipboard::qWasmClipboardPaste(mMimeData); +} + +static void qClipboardPromiseResolve(emscripten::val something) +{ + pasteClipboardData(emscripten::val("text/plain"), something); +} + +static void qClipboardCopyTo(val event) +{ + val target = event["target"]; + val clipboard = event["clipboardData"]; + + val module = val::global("Module"); + val clipdata = module.call("getClipboardData"); + val clipFormat = module.call("getClipboardFormat"); + clipboard.call("setData", clipFormat, clipdata); + target.call("preventDefault"); +} + +static void qClipboardPasteTo(val event) +{ + val target = event["clipboardData"]; + val module = val::global("Module"); + val clipdata = module.call("getClipboardData"); + + const std::string data = clipdata.as(); + if (data.length() > 0) { + QString qstr = QString::fromStdString(data); + QMimeData *mMimeData = new QMimeData; + mMimeData->setText(qstr); + QWasmClipboard::qWasmClipboardPaste(mMimeData); + } +} + +EMSCRIPTEN_BINDINGS(clipboard_module) { + function("getClipboardData", &getClipboardData); + function("getClipboardFormat", &getClipboardFormat); + function("pasteClipboardData", &pasteClipboardData); + function("qClipboardPromiseResolve", &qClipboardPromiseResolve); + function("qClipboardCopyTo", &qClipboardCopyTo); + function("qClipboardPasteTo", &qClipboardPasteTo); +} + +QWasmClipboard::QWasmClipboard() : + hasClipboardApi(false) +{ + initClipboardEvents(); +} + +QWasmClipboard::~QWasmClipboard() +{ + g_clipboardArray.clear(); + g_clipboardFormat.clear(); +} + +QMimeData* QWasmClipboard::mimeData(QClipboard::Mode mode) +{ + if (mode != QClipboard::Clipboard) + return nullptr; + + return QPlatformClipboard::mimeData(mode); +} + +void QWasmClipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode) +{ + if (mimeData->hasText()) { + g_clipboardFormat = mimeData->formats().at(0).toUtf8(); + g_clipboardArray = mimeData->text().toUtf8(); + } else if (mimeData->hasHtml()) { + g_clipboardFormat =mimeData->formats().at(0).toUtf8(); + g_clipboardArray = mimeData->html().toUtf8(); + } + + QPlatformClipboard::setMimeData(mimeData, mode); +} + +bool QWasmClipboard::supportsMode(QClipboard::Mode mode) const +{ + return mode == QClipboard::Clipboard; +} + +bool QWasmClipboard::ownsMode(QClipboard::Mode mode) const +{ + Q_UNUSED(mode); + return false; +} + +void QWasmClipboard::qWasmClipboardPaste(QMimeData *mData) +{ + QWasmIntegration::get()->clipboard()->setMimeData(mData, QClipboard::Clipboard); + + QWindowSystemInterface::handleKeyEvent( + 0, QEvent::KeyPress, Qt::Key_V, Qt::ControlModifier, "V"); +} + +void QWasmClipboard::initClipboardEvents() +{ + val navigator = val::global("navigator"); + val permissions = navigator["permissions"]; + val clipboard = navigator["clipboard"]; + + hasClipboardApi = (!clipboard.isUndefined()); + if (hasClipboardApi) { + val readPermissionsMap = val::object(); + readPermissionsMap.set("name", val("clipboard-read")); + permissions.call("query", readPermissionsMap); + + val writePermissionsMap = val::object(); + writePermissionsMap.set("name", val("clipboard-write")); + permissions.call("query", writePermissionsMap); + + } else { + + val window = val::global("window"); + window.call("addEventListener", std::string("paste"), + val::module_property("qClipboardPasteTo")); + + window.call("addEventListener", std::string("copy"), + val::module_property("qClipboardCopyTo")); + } +} + +void QWasmClipboard::readTextFromClipboard() +{ + if (QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) { + val navigator = val::global("navigator"); + val textPromise = navigator["clipboard"].call("readText"); + val readTextResolve = val::global("Module")["qClipboardPromiseResolve"]; + textPromise.call("then", readTextResolve); + } +} + +void QWasmClipboard::writeTextToClipboard() +{ + if (QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) { + val module = val::global("Module"); + val txt = module.call("getClipboardData"); + val format = module.call("getClipboardFormat"); + val navigator = val::global("navigator"); + navigator["clipboard"].call("writeText", txt.as()); + } +} diff --git a/src/plugins/platforms/wasm/qwasmclipboard.h b/src/plugins/platforms/wasm/qwasmclipboard.h new file mode 100644 index 0000000000..e64b2e5007 --- /dev/null +++ b/src/plugins/platforms/wasm/qwasmclipboard.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWasmClipboard_H +#define QWasmClipboard_H + +#include + +#include +#include + +#include + +class QWasmClipboard : public QObject, public QPlatformClipboard +{ +public: + QWasmClipboard(); + virtual ~QWasmClipboard(); + + // QPlatformClipboard methods. + QMimeData* mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override; + void setMimeData(QMimeData* data, QClipboard::Mode mode = QClipboard::Clipboard) override; + bool supportsMode(QClipboard::Mode mode) const override; + bool ownsMode(QClipboard::Mode mode) const override; + + static void qWasmClipboardPaste(QMimeData *mData); + void initClipboardEvents(); + bool hasClipboardApi; + void readTextFromClipboard(); + void writeTextToClipboard(); +}; + +#endif // QWASMCLIPBOARD_H diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp index ea88ef59a0..df81413d5c 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp @@ -31,6 +31,7 @@ #include "qwasmeventdispatcher.h" #include "qwasmcompositor.h" #include "qwasmintegration.h" +#include "qwasmclipboard.h" #include #include @@ -175,10 +176,26 @@ int QWasmEventTranslator::keyboard_cb(int eventType, const EmscriptenKeyboardEve if (keyType == QEvent::None) return 0; - QString keyText = alphanumeric ? QString(keyEvent->key) : QString(); - bool accepted = QWindowSystemInterface::handleKeyEvent( - 0, keyType, qtKey, translateKeyboardEventModifier(keyEvent), keyText); + QFlags mods = translateKeyboardEventModifier(keyEvent); + bool accepted = false; + + if (keyType == QEvent::KeyPress && + mods.testFlag(Qt::ControlModifier) + && qtKey == Qt::Key_V) { + QWasmIntegration::get()->getWasmClipboard()->readTextFromClipboard(); + } else { + QString keyText = alphanumeric ? QString(keyEvent->key) : QString(); + accepted = QWindowSystemInterface::handleKeyEvent( + 0, keyType, qtKey, translateKeyboardEventModifier(keyEvent), keyText); + } + + if (keyType == QEvent::KeyPress && + mods.testFlag(Qt::ControlModifier) + && qtKey == Qt::Key_C) { + QWasmIntegration::get()->getWasmClipboard()->writeTextToClipboard(); + } QWasmEventDispatcher::maintainTimers(); + return accepted ? 1 : 0; } diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp index 7a44c47893..6f96ec69da 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.cpp +++ b/src/plugins/platforms/wasm/qwasmintegration.cpp @@ -33,6 +33,7 @@ #include "qwasmcompositor.h" #include "qwasmopenglcontext.h" #include "qwasmtheme.h" +#include "qwasmclipboard.h" #include "qwasmwindow.h" #ifndef QT_NO_OPENGL @@ -65,17 +66,16 @@ EMSCRIPTEN_BINDINGS(my_module) function("browserBeforeUnload", &browserBeforeUnload); } -static QWasmIntegration *globalHtml5Integration; -QWasmIntegration *QWasmIntegration::get() { return globalHtml5Integration; } +QWasmIntegration *QWasmIntegration::s_instance; QWasmIntegration::QWasmIntegration() : m_fontDb(nullptr), m_compositor(new QWasmCompositor), m_screen(new QWasmScreen(m_compositor)), - m_eventDispatcher(nullptr) + m_eventDispatcher(nullptr), + m_clipboard(new QWasmClipboard) { - - globalHtml5Integration = this; + s_instance = this; updateQScreenAndCanvasRenderSize(); screenAdded(m_screen); @@ -93,6 +93,7 @@ QWasmIntegration::~QWasmIntegration() destroyScreen(m_screen); delete m_fontDb; delete m_eventTranslator; + s_instance = nullptr; } void QWasmIntegration::QWasmBrowserExit() @@ -211,4 +212,11 @@ void QWasmIntegration::updateQScreenAndCanvasRenderSize() QWasmIntegration::get()->m_compositor->redrawWindowContent(); } +QPlatformClipboard* QWasmIntegration::clipboard() const +{ + if (!m_clipboard) + m_clipboard = new QWasmClipboard; + return m_clipboard; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h index ebc3d9d431..4c5aeb4ebc 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.h +++ b/src/plugins/platforms/wasm/qwasmintegration.h @@ -49,6 +49,7 @@ class QWasmEventDispatcher; class QWasmScreen; class QWasmCompositor; class QWasmBackingStore; +class QWasmClipboard; class QWasmIntegration : public QObject, public QPlatformIntegration { @@ -68,12 +69,14 @@ public: QVariant styleHint(QPlatformIntegration::StyleHint hint) const override; QStringList themeNames() const override; QPlatformTheme *createPlatformTheme(const QString &name) const override; + QPlatformClipboard *clipboard() const override; - static QWasmIntegration *get(); QWasmScreen *screen() { return m_screen; } QWasmCompositor *compositor() { return m_compositor; } QWasmEventTranslator *eventTranslator() { return m_eventTranslator; } + QWasmClipboard *getWasmClipboard() { return m_clipboard; } + static QWasmIntegration *get() { return s_instance; } static void QWasmBrowserExit(); static void updateQScreenAndCanvasRenderSize(); @@ -85,6 +88,9 @@ private: mutable QWasmEventDispatcher *m_eventDispatcher; static int uiEvent_cb(int eventType, const EmscriptenUiEvent *e, void *userData); mutable QHash m_backingStores; + + mutable QWasmClipboard *m_clipboard; + static QWasmIntegration *s_instance; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/wasm.pro b/src/plugins/platforms/wasm/wasm.pro index eaaba53aa2..5aa6dfccf3 100644 --- a/src/plugins/platforms/wasm/wasm.pro +++ b/src/plugins/platforms/wasm/wasm.pro @@ -18,7 +18,8 @@ SOURCES = \ qwasmcompositor.cpp \ qwasmcursor.cpp \ qwasmopenglcontext.cpp \ - qwasmtheme.cpp + qwasmtheme.cpp \ + qwasmclipboard.cpp HEADERS = \ qwasmintegration.h \ @@ -31,7 +32,8 @@ HEADERS = \ qwasmstylepixmaps_p.h \ qwasmcursor.h \ qwasmopenglcontext.h \ - qwasmtheme.h + qwasmtheme.h \ + qwasmclipboard.h wasmfonts.files = \ ../../../3rdparty/wasm/Vera.ttf \ -- cgit v1.2.3 From 94a4f06fb88ec6c7fa5e31dfd28af4e9b3cdbdd8 Mon Sep 17 00:00:00 2001 From: Michal Klocek Date: Fri, 8 Feb 2019 15:31:15 +0100 Subject: Add run-time qpa offscreen glx support selection Introduce QT_QPA_OFFSCREEN_NO_GLX to run offscreen qpa without glx even if compiled with x11 support. Task-number: QTBUG-63346 Change-Id: I647bf5df27f095c3dd27a90415cc9c445df93fd1 Reviewed-by: Laszlo Agocs --- src/plugins/platforms/offscreen/offscreen.pro | 3 -- .../platforms/offscreen/qoffscreenintegration.cpp | 14 +++++++ .../offscreen/qoffscreenintegration_dummy.cpp | 45 ---------------------- .../offscreen/qoffscreenintegration_x11.cpp | 5 --- 4 files changed, 14 insertions(+), 53 deletions(-) delete mode 100644 src/plugins/platforms/offscreen/qoffscreenintegration_dummy.cpp (limited to 'src/plugins') diff --git a/src/plugins/platforms/offscreen/offscreen.pro b/src/plugins/platforms/offscreen/offscreen.pro index 392ee8bed1..a8f230a7b1 100644 --- a/src/plugins/platforms/offscreen/offscreen.pro +++ b/src/plugins/platforms/offscreen/offscreen.pro @@ -21,9 +21,6 @@ qtConfig(system-xcb):qtConfig(xlib):qtConfig(opengl):!qtConfig(opengles2) { SOURCES += qoffscreenintegration_x11.cpp HEADERS += qoffscreenintegration_x11.h QT += glx_support-private - system(echo "Using X11 offscreen integration with GLX") -} else { - SOURCES += qoffscreenintegration_dummy.cpp } PLUGIN_TYPE = platforms diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp index 9815be16a3..efd8fdf3fa 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp +++ b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp @@ -66,6 +66,10 @@ #include +#if QT_CONFIG(system_xcb) && QT_CONFIG(xlib) && QT_CONFIG(opengl) && !QT_CONFIG(opengles2) +#include "qoffscreenintegration_x11.h" +#endif + QT_BEGIN_NAMESPACE class QCoreTextFontEngine; @@ -219,4 +223,14 @@ QPlatformServices *QOffscreenIntegration::services() const return m_services.data(); } +QOffscreenIntegration *QOffscreenIntegration::createOffscreenIntegration() +{ +#if QT_CONFIG(system_xcb) && QT_CONFIG(xlib) && QT_CONFIG(opengl) && !QT_CONFIG(opengles2) + QByteArray glx = qgetenv("QT_QPA_OFFSCREEN_NO_GLX"); + if (glx.isEmpty()) + return new QOffscreenX11Integration; +#endif + return new QOffscreenIntegration; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_dummy.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration_dummy.cpp deleted file mode 100644 index 78b289ea49..0000000000 --- a/src/plugins/platforms/offscreen/qoffscreenintegration_dummy.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qoffscreenintegration.h" - -QOffscreenIntegration *QOffscreenIntegration::createOffscreenIntegration() -{ - return new QOffscreenIntegration; -} diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp index 2532cedc70..92fc8aa57a 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp +++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp @@ -77,11 +77,6 @@ private: QOffscreenX11Connection *m_connection; }; -QOffscreenIntegration *QOffscreenIntegration::createOffscreenIntegration() -{ - return new QOffscreenX11Integration; -} - bool QOffscreenX11Integration::hasCapability(QPlatformIntegration::Capability cap) const { switch (cap) { -- cgit v1.2.3 From c7318e899ea00cf9f3979c8876b2402187000905 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 13 Feb 2019 15:28:44 +0100 Subject: macOS: Remove dead code in window activation handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I321ab68b51c4ba63204c0e15fec74164e2c93d34 Reviewed-by: Timur Pocheptsov Reviewed-by: Tor Arne Vestbø --- .../platforms/cocoa/qcocoaapplicationdelegate.mm | 24 ---------------------- 1 file changed, 24 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index 44ab16d300..9e3c89b6a4 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -353,21 +353,6 @@ QT_USE_NAMESPACE [reflectionDelegate applicationDidBecomeActive:notification]; QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive); -/* - onApplicationChangedActivation(true); - - if (!QWidget::mouseGrabber()){ - // Update enter/leave immidiatly, don't wait for a move event. But only - // if no grab exists (even if the grab points to this widget, it seems, ref X11) - QPoint qlocal, qglobal; - QWidget *widgetUnderMouse = 0; - qt_mac_getTargetForMouseEvent(0, QEvent::Enter, qlocal, qglobal, 0, &widgetUnderMouse); - QApplicationPrivate::dispatchEnterLeave(widgetUnderMouse, 0); - qt_last_mouse_receiver = widgetUnderMouse; - qt_last_native_mouse_receiver = widgetUnderMouse ? - (widgetUnderMouse->internalWinId() ? widgetUnderMouse : widgetUnderMouse->nativeParentWidget()) : 0; - } -*/ } - (void)applicationDidResignActive:(NSNotification *)notification @@ -377,15 +362,6 @@ QT_USE_NAMESPACE [reflectionDelegate applicationDidResignActive:notification]; QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); -/* - onApplicationChangedActivation(false); - - if (!QWidget::mouseGrabber()) - QApplicationPrivate::dispatchEnterLeave(0, qt_last_mouse_receiver); - qt_last_mouse_receiver = 0; - qt_last_native_mouse_receiver = 0; - qt_button_down = 0; -*/ } - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag -- cgit v1.2.3 From 025128a7e0d7100da7e1705cd448012e0421e05b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 12 Feb 2019 20:07:35 +0100 Subject: macOS: Simplify QCocoaWindow::setVisible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't need all the checks for the event dispatcher, it should always be there. Change-Id: Ib89a9c1c5524b49c2d85fae12425d19ced960597 Reviewed-by: Timur Pocheptsov Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qcocoawindow.mm | 50 +++++++++++------------------ 1 file changed, 18 insertions(+), 32 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index ebdd51acb4..ec7ad38be5 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -303,13 +303,17 @@ void QCocoaWindow::setVisible(bool visible) { qCDebug(lcQpaWindow) << "QCocoaWindow::setVisible" << window() << visible; - m_inSetVisible = true; + QScopedValueRollback rollback(m_inSetVisible, true); QMacAutoReleasePool pool; QCocoaWindow *parentCocoaWindow = nullptr; if (window()->transientParent()) parentCocoaWindow = static_cast(window()->transientParent()->handle()); + auto eventDispatcher = [] { + return static_cast(QObjectPrivate::get(qApp->eventDispatcher())); + }; + if (visible) { // We need to recreate if the modality has changed as the style mask will need updating recreateWindowIfNeeded(); @@ -350,28 +354,15 @@ void QCocoaWindow::setVisible(bool visible) applyWindowState(window()->windowStates()); if (window()->windowState() != Qt::WindowMinimized) { - if ((window()->modality() == Qt::WindowModal - || window()->type() == Qt::Sheet) - && parentCocoaWindow) { - // show the window as a sheet + if (parentCocoaWindow && (window()->modality() == Qt::WindowModal || window()->type() == Qt::Sheet)) { + // Show the window as a sheet [parentCocoaWindow->nativeWindow() beginSheet:m_view.window completionHandler:nil]; - } else if (window()->modality() != Qt::NonModal) { - // show the window as application modal - QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast(QGuiApplication::instance()->eventDispatcher()); - Q_ASSERT(cocoaEventDispatcher); - QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = static_cast(QObjectPrivate::get(cocoaEventDispatcher)); - cocoaEventDispatcherPrivate->beginModalSession(window()); + } else if (window()->modality() == Qt::ApplicationModal) { + // Show the window as application modal + eventDispatcher()->beginModalSession(window()); m_hasModalSession = true; - } else if ([m_view.window canBecomeKeyWindow]) { - QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast(QGuiApplication::instance()->eventDispatcher()); - QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = nullptr; - if (cocoaEventDispatcher) - cocoaEventDispatcherPrivate = static_cast(QObjectPrivate::get(cocoaEventDispatcher)); - - if (cocoaEventDispatcherPrivate && cocoaEventDispatcherPrivate->cocoaModalSessionStack.isEmpty()) - [m_view.window makeKeyAndOrderFront:nil]; - else - [m_view.window orderFront:nil]; + } else if (m_view.window.canBecomeKeyWindow && eventDispatcher()->cocoaModalSessionStack.isEmpty()) { + [m_view.window makeKeyAndOrderFront:nil]; } else { [m_view.window orderFront:nil]; } @@ -396,21 +387,18 @@ void QCocoaWindow::setVisible(bool visible) } } } + // In some cases, e.g. QDockWidget, the content view is hidden before moving to its own // Cocoa window, and then shown again. Therefore, we test for the view being hidden even // if it's attached to an NSWindow. if ([m_view isHidden]) [m_view setHidden:NO]; + } else { - // qDebug() << "close" << this; - QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast(QGuiApplication::instance()->eventDispatcher()); - QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = nullptr; - if (cocoaEventDispatcher) - cocoaEventDispatcherPrivate = static_cast(QObjectPrivate::get(cocoaEventDispatcher)); + // Window not visible, hide it if (isContentView()) { if (m_hasModalSession) { - if (cocoaEventDispatcherPrivate) - cocoaEventDispatcherPrivate->endModalSession(window()); + eventDispatcher()->endModalSession(window()); m_hasModalSession = false; } else { if ([m_view.window isSheet]) { @@ -421,8 +409,7 @@ void QCocoaWindow::setVisible(bool visible) [m_view.window orderOut:nil]; - if (m_view.window == [NSApp keyWindow] - && !(cocoaEventDispatcherPrivate && cocoaEventDispatcherPrivate->currentModalSession())) { + if (m_view.window == [NSApp keyWindow] && !eventDispatcher()->currentModalSession()) { // Probably because we call runModalSession: outside [NSApp run] in QCocoaEventDispatcher // (e.g., when show()-ing a modal QDialog instead of exec()-ing it), it can happen that // the current NSWindow is still key after being ordered out. Then, after checking we @@ -434,6 +421,7 @@ void QCocoaWindow::setVisible(bool visible) } else { [m_view setHidden:YES]; } + removeMonitor(); if (window()->type() == Qt::Popup || window()->type() == Qt::ToolTip) @@ -447,8 +435,6 @@ void QCocoaWindow::setVisible(bool visible) nativeParentWindow.styleMask |= NSWindowStyleMaskResizable; } } - - m_inSetVisible = false; } NSInteger QCocoaWindow::windowLevel(Qt::WindowFlags flags) -- cgit v1.2.3 From c36c5e9b552f826c96bf066252b49de03921c03f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 12 Feb 2019 20:33:13 +0100 Subject: macOS: Modernize worksWhenModal handling The code in QCocoaEventDispatcher was dead and could be removed. Change-Id: I0c57e64791045d65033376c096220983059028ba Reviewed-by: Timur Pocheptsov --- .../platforms/cocoa/qcocoaeventdispatcher.h | 1 - .../platforms/cocoa/qcocoaeventdispatcher.mm | 41 ---------------------- src/plugins/platforms/cocoa/qcocoawindow.mm | 30 +++++++--------- src/plugins/platforms/cocoa/qnswindow.h | 1 + src/plugins/platforms/cocoa/qnswindow.mm | 13 +++++++ 5 files changed, 27 insertions(+), 59 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h index ebf33cf4e2..44a9c52b7b 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h @@ -168,7 +168,6 @@ public: uint processEventsCalled; NSModalSession currentModalSessionCached; NSModalSession currentModalSession(); - void updateChildrenWorksWhenModal(); void temporarilyStopAllModalSessions(); void beginModalSession(QWindow *widget); void endModalSession(QWindow *widget); diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm index b0f2b6d940..b944c3d28c 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm @@ -672,45 +672,6 @@ NSModalSession QCocoaEventDispatcherPrivate::currentModalSession() return currentModalSessionCached; } -static void setChildrenWorksWhenModal(QWindow *window, bool worksWhenModal) -{ - Q_UNUSED(window) - Q_UNUSED(worksWhenModal) - - // For NSPanels (but not NSWindows, sadly), we can set the flag - // worksWhenModal, so that they are active even when they are not modal. -/* - ### not ported - QList dialogs = window->findChildren(); - for (int i=0; i(window) setWorksWhenModal:worksWhenModal]; - if (worksWhenModal && [window isVisible]){ - [window orderFront:window]; - } - } - } -*/ -} - -void QCocoaEventDispatcherPrivate::updateChildrenWorksWhenModal() -{ - // Make the dialog children of the window - // active. And make the dialog children of - // the previous modal dialog unactive again: - QMacAutoReleasePool pool; - int size = cocoaModalSessionStack.size(); - if (size > 0){ - if (QWindow *prevModal = cocoaModalSessionStack[size-1].window) - setChildrenWorksWhenModal(prevModal, true); - if (size > 1){ - if (QWindow *prevModal = cocoaModalSessionStack[size-2].window) - setChildrenWorksWhenModal(prevModal, false); - } - } -} - void QCocoaEventDispatcherPrivate::cleanupModalSessions() { // Go through the list of modal sessions, and end those @@ -743,7 +704,6 @@ void QCocoaEventDispatcherPrivate::cleanupModalSessions() cocoaModalSessionStack.remove(i); } - updateChildrenWorksWhenModal(); cleanupModalSessionsNeeded = false; } @@ -764,7 +724,6 @@ void QCocoaEventDispatcherPrivate::beginModalSession(QWindow *window) // stopped in cleanupModalSessions()). QCocoaModalSessionInfo info = {window, nullptr, nullptr}; cocoaModalSessionStack.push(info); - updateChildrenWorksWhenModal(); currentModalSessionCached = nullptr; } diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index ec7ad38be5..5a26f57c8c 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -367,23 +367,19 @@ void QCocoaWindow::setVisible(bool visible) [m_view.window orderFront:nil]; } - // We want the events to properly reach the popup, dialog, and tool - if ((window()->type() == Qt::Popup || window()->type() == Qt::Dialog || window()->type() == Qt::Tool) - && [m_view.window isKindOfClass:[NSPanel class]]) { - ((NSPanel *)m_view.window).worksWhenModal = YES; - if (!(parentCocoaWindow && window()->transientParent()->isActive()) && window()->type() == Qt::Popup) { - removeMonitor(); - NSEventMask eventMask = NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown - | NSEventMaskOtherMouseDown | NSEventMaskMouseMoved; - monitor = [NSEvent addGlobalMonitorForEventsMatchingMask:eventMask handler:^(NSEvent *e) { - const auto button = cocoaButton2QtButton(e); - const auto buttons = currentlyPressedMouseButtons(); - const auto eventType = cocoaEvent2QtMouseEvent(e); - const auto globalPoint = QCocoaScreen::mapFromNative(NSEvent.mouseLocation); - const auto localPoint = window()->mapFromGlobal(globalPoint.toPoint()); - QWindowSystemInterface::handleMouseEvent(window(), localPoint, globalPoint, buttons, button, eventType); - }]; - } + // Close popup when clicking outside it + if (window()->type() == Qt::Popup && !(parentCocoaWindow && window()->transientParent()->isActive())) { + removeMonitor(); + NSEventMask eventMask = NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown + | NSEventMaskOtherMouseDown | NSEventMaskMouseMoved; + monitor = [NSEvent addGlobalMonitorForEventsMatchingMask:eventMask handler:^(NSEvent *e) { + const auto button = cocoaButton2QtButton(e); + const auto buttons = currentlyPressedMouseButtons(); + const auto eventType = cocoaEvent2QtMouseEvent(e); + const auto globalPoint = QCocoaScreen::mapFromNative(NSEvent.mouseLocation); + const auto localPoint = window()->mapFromGlobal(globalPoint.toPoint()); + QWindowSystemInterface::handleMouseEvent(window(), localPoint, globalPoint, buttons, button, eventType); + }]; } } } diff --git a/src/plugins/platforms/cocoa/qnswindow.h b/src/plugins/platforms/cocoa/qnswindow.h index 64f1ed0802..dcbcd58901 100644 --- a/src/plugins/platforms/cocoa/qnswindow.h +++ b/src/plugins/platforms/cocoa/qnswindow.h @@ -62,6 +62,7 @@ QT_FORWARD_DECLARE_CLASS(QCocoaWindow) @protocol QNSWindowProtocol @optional - (BOOL)canBecomeKeyWindow; +- (BOOL)worksWhenModal; - (void)sendEvent:(NSEvent*)theEvent; - (void)closeAndRelease; - (void)dealloc; diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm index c17ad47aba..28a9fa8607 100644 --- a/src/plugins/platforms/cocoa/qnswindow.mm +++ b/src/plugins/platforms/cocoa/qnswindow.mm @@ -177,6 +177,19 @@ static bool isMouseEvent(NSEvent *ev) return canBecomeMain; } +- (BOOL)worksWhenModal +{ + if ([self isKindOfClass:[QNSPanel class]]) { + if (QCocoaWindow *pw = self.platformWindow) { + Qt::WindowType type = pw->window()->type(); + if (type == Qt::Popup || type == Qt::Dialog || type == Qt::Tool) + return YES; + } + } + + return qt_objcDynamicSuper(); +} + - (BOOL)isOpaque { return self.platformWindow ? -- cgit v1.2.3 From 6273b484b35479eb5788425c8d90acacdf239623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 12 Feb 2019 20:55:31 +0100 Subject: macOS: Remove redundant tracking of modal sessions in QCocoaWindow Change-Id: I43a40889b0731e4b480155256fc51eaa836e62a3 Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qcocoaeventdispatcher.h | 1 + src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm | 5 +++++ src/plugins/platforms/cocoa/qcocoawindow.h | 1 - src/plugins/platforms/cocoa/qcocoawindow.mm | 9 +++------ 4 files changed, 9 insertions(+), 7 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h index 44a9c52b7b..9771cd0289 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h @@ -171,6 +171,7 @@ public: void temporarilyStopAllModalSessions(); void beginModalSession(QWindow *widget); void endModalSession(QWindow *widget); + bool hasModalSession() const; void cleanupModalSessions(); void cancelWaitForMoreEvents(); diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm index b944c3d28c..84ffadea83 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm @@ -672,6 +672,11 @@ NSModalSession QCocoaEventDispatcherPrivate::currentModalSession() return currentModalSessionCached; } +bool QCocoaEventDispatcherPrivate::hasModalSession() const +{ + return !cocoaModalSessionStack.isEmpty(); +} + void QCocoaEventDispatcherPrivate::cleanupModalSessions() { // Go through the list of modal sessions, and end those diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 0a913ef66e..fef72bc496 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -253,7 +253,6 @@ public: // for QNSView bool m_needsInvalidateShadow; - bool m_hasModalSession; bool m_frameStrutEventsEnabled; QRect m_exposedRect; int m_registerTouchCount; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 5a26f57c8c..2718dc9600 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -153,7 +153,6 @@ QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle) , m_inSetStyleMask(false) , m_menubar(nullptr) , m_needsInvalidateShadow(false) - , m_hasModalSession(false) , m_frameStrutEventsEnabled(false) , m_registerTouchCount(0) , m_resizableTransientParent(false) @@ -360,8 +359,7 @@ void QCocoaWindow::setVisible(bool visible) } else if (window()->modality() == Qt::ApplicationModal) { // Show the window as application modal eventDispatcher()->beginModalSession(window()); - m_hasModalSession = true; - } else if (m_view.window.canBecomeKeyWindow && eventDispatcher()->cocoaModalSessionStack.isEmpty()) { + } else if (m_view.window.canBecomeKeyWindow && !eventDispatcher()->hasModalSession()) { [m_view.window makeKeyAndOrderFront:nil]; } else { [m_view.window orderFront:nil]; @@ -393,9 +391,8 @@ void QCocoaWindow::setVisible(bool visible) } else { // Window not visible, hide it if (isContentView()) { - if (m_hasModalSession) { + if (eventDispatcher()->hasModalSession()) { eventDispatcher()->endModalSession(window()); - m_hasModalSession = false; } else { if ([m_view.window isSheet]) { Q_ASSERT_X(parentCocoaWindow, "QCocoaWindow", "Window modal dialog has no transient parent."); @@ -405,7 +402,7 @@ void QCocoaWindow::setVisible(bool visible) [m_view.window orderOut:nil]; - if (m_view.window == [NSApp keyWindow] && !eventDispatcher()->currentModalSession()) { + if (m_view.window == [NSApp keyWindow] && !eventDispatcher()->hasModalSession()) { // Probably because we call runModalSession: outside [NSApp run] in QCocoaEventDispatcher // (e.g., when show()-ing a modal QDialog instead of exec()-ing it), it can happen that // the current NSWindow is still key after being ordered out. Then, after checking we -- cgit v1.2.3 From 5242126a610ebe76513cee22ecd8b5354bbf96b7 Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Tue, 17 Jul 2018 14:58:41 +1000 Subject: wasm: improve key handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow for extended non English keys Task-number: QTBUG-68189 Task-number: QTBUG-69392 Change-Id: I12187ebc1250a5c29022cd2d3ad3a77eb45c06a8 Reviewed-by: Morten Johan Sørvig --- .../platforms/wasm/qwasmeventtranslator.cpp | 544 +++++++++++++++------ src/plugins/platforms/wasm/qwasmeventtranslator.h | 178 ++----- 2 files changed, 452 insertions(+), 270 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp index df81413d5c..ddf0ff61e5 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp @@ -40,6 +40,9 @@ #include #include +#include +#include + #include #include @@ -47,6 +50,257 @@ QT_BEGIN_NAMESPACE using namespace emscripten; +typedef struct emkb2qt { + const char *em; + unsigned int qt; + + constexpr bool operator <=(const emkb2qt &that) const noexcept + { + return !(strcmp(that) > 0); + } + + bool operator <(const emkb2qt &that) const noexcept + { + return ::strcmp(em, that.em) < 0; + } + constexpr int strcmp(const emkb2qt &that, const int i = 0) const + { + return em[i] == 0 && that.em[i] == 0 ? 0 + : em[i] == 0 ? -1 + : that.em[i] == 0 ? 1 + : em[i] < that.em[i] ? -1 + : em[i] > that.em[i] ? 1 + : strcmp(that, i + 1); + } +} emkb2qt_t; + +template +struct Emkb2Qt +{ + static constexpr const char storage[sizeof ... (EmChar) + 1] = {EmChar..., '\0'}; + using Type = emkb2qt_t; + static constexpr Type data() noexcept { return Type{storage, Qt}; } +}; + +template constexpr char Emkb2Qt::storage[]; + +static constexpr const auto KeyTbl = qMakeArray( + QSortedData< + Emkb2Qt< Qt::Key_Escape, 'E','s','c','a','p','e' >, + Emkb2Qt< Qt::Key_Tab, 'T','a','b' >, + Emkb2Qt< Qt::Key_Backspace, 'B','a','c','k','s','p','a','c','e' >, + Emkb2Qt< Qt::Key_Return, 'E','n','t','e','r' >, + Emkb2Qt< Qt::Key_Insert, 'I','n','s','e','r','t' >, + Emkb2Qt< Qt::Key_Delete, 'D','e','l','e','t','e' >, + Emkb2Qt< Qt::Key_Pause, 'P','a','u','s','e' >, + Emkb2Qt< Qt::Key_Pause, 'C','l','e','a','r' >, + Emkb2Qt< Qt::Key_Home, 'H','o','m','e' >, + Emkb2Qt< Qt::Key_End, 'E','n','d' >, + Emkb2Qt< Qt::Key_Left, 'A','r','r','o','w','L','e','f','t' >, + Emkb2Qt< Qt::Key_Up, 'A','r','r','o','w','U','p' >, + Emkb2Qt< Qt::Key_Right, 'A','r','r','o','w','R','i','g','h','t' >, + Emkb2Qt< Qt::Key_Down, 'A','r','r','o','w','D','o','w','n' >, + Emkb2Qt< Qt::Key_PageUp, 'P','a','g','e','U','p' >, + Emkb2Qt< Qt::Key_PageDown, 'P','a','g','e','D','o','w','n' >, + Emkb2Qt< Qt::Key_Shift, 'S','h','i','f','t' >, + Emkb2Qt< Qt::Key_Control, 'C','o','n','t','r','o','l' >, + Emkb2Qt< Qt::Key_Meta, 'O','S'>, + Emkb2Qt< Qt::Key_Alt, 'A','l','t','L','e','f','t' >, + Emkb2Qt< Qt::Key_Alt, 'A','l','t' >, + Emkb2Qt< Qt::Key_CapsLock, 'C','a','p','s','L','o','c','k' >, + Emkb2Qt< Qt::Key_NumLock, 'N','u','m','L','o','c','k' >, + Emkb2Qt< Qt::Key_ScrollLock, 'S','c','r','o','l','l','L','o','c','k' >, + Emkb2Qt< Qt::Key_F1, 'F','1' >, + Emkb2Qt< Qt::Key_F2, 'F','2' >, + Emkb2Qt< Qt::Key_F3, 'F','3' >, + Emkb2Qt< Qt::Key_F4, 'F','4' >, + Emkb2Qt< Qt::Key_F5, 'F','5' >, + Emkb2Qt< Qt::Key_F6, 'F','6' >, + Emkb2Qt< Qt::Key_F7, 'F','7' >, + Emkb2Qt< Qt::Key_F8, 'F','8' >, + Emkb2Qt< Qt::Key_F9, 'F','9' >, + Emkb2Qt< Qt::Key_F10, 'F','1','0' >, + Emkb2Qt< Qt::Key_F11, 'F','1','1' >, + Emkb2Qt< Qt::Key_F12, 'F','1','2' >, + Emkb2Qt< Qt::Key_F13, 'F','1','3' >, + Emkb2Qt< Qt::Key_F14, 'F','1','4' >, + Emkb2Qt< Qt::Key_F15, 'F','1','5' >, + Emkb2Qt< Qt::Key_F16, 'F','1','6' >, + Emkb2Qt< Qt::Key_F17, 'F','1','7' >, + Emkb2Qt< Qt::Key_F18, 'F','1','8' >, + Emkb2Qt< Qt::Key_F19, 'F','1','9' >, + Emkb2Qt< Qt::Key_F20, 'F','2','0' >, + Emkb2Qt< Qt::Key_F21, 'F','2','1' >, + Emkb2Qt< Qt::Key_F22, 'F','2','2' >, + Emkb2Qt< Qt::Key_F23, 'F','2','3' >, + Emkb2Qt< Qt::Key_Space, ' ' >, + Emkb2Qt< Qt::Key_Comma, ',' >, + Emkb2Qt< Qt::Key_Minus, '-' >, + Emkb2Qt< Qt::Key_Period, '.' >, + Emkb2Qt< Qt::Key_Slash, '/' >, + Emkb2Qt< Qt::Key_0, '0' >, + Emkb2Qt< Qt::Key_1, '1' >, + Emkb2Qt< Qt::Key_2, '2' >, + Emkb2Qt< Qt::Key_3, '3' >, + Emkb2Qt< Qt::Key_4, '4' >, + Emkb2Qt< Qt::Key_5, '5' >, + Emkb2Qt< Qt::Key_6, '6' >, + Emkb2Qt< Qt::Key_7, '7' >, + Emkb2Qt< Qt::Key_8, '8' >, + Emkb2Qt< Qt::Key_9, '9' >, + Emkb2Qt< Qt::Key_Semicolon, ';' >, + Emkb2Qt< Qt::Key_Equal, '=' >, + Emkb2Qt< Qt::Key_A, 'K','e','y','A' >, + Emkb2Qt< Qt::Key_B, 'K','e','y','B' >, + Emkb2Qt< Qt::Key_C, 'K','e','y','C' >, + Emkb2Qt< Qt::Key_D, 'K','e','y','D' >, + Emkb2Qt< Qt::Key_E, 'K','e','y','E' >, + Emkb2Qt< Qt::Key_F, 'K','e','y','F' >, + Emkb2Qt< Qt::Key_G, 'K','e','y','G' >, + Emkb2Qt< Qt::Key_H, 'K','e','y','H' >, + Emkb2Qt< Qt::Key_I, 'K','e','y','I' >, + Emkb2Qt< Qt::Key_J, 'K','e','y','J' >, + Emkb2Qt< Qt::Key_K, 'K','e','y','K' >, + Emkb2Qt< Qt::Key_L, 'K','e','y','L' >, + Emkb2Qt< Qt::Key_M, 'K','e','y','M' >, + Emkb2Qt< Qt::Key_N, 'K','e','y','N' >, + Emkb2Qt< Qt::Key_O, 'K','e','y','O' >, + Emkb2Qt< Qt::Key_P, 'K','e','y','P' >, + Emkb2Qt< Qt::Key_Q, 'K','e','y','Q' >, + Emkb2Qt< Qt::Key_R, 'K','e','y','R' >, + Emkb2Qt< Qt::Key_S, 'K','e','y','S' >, + Emkb2Qt< Qt::Key_T, 'K','e','y','T' >, + Emkb2Qt< Qt::Key_U, 'K','e','y','U' >, + Emkb2Qt< Qt::Key_V, 'K','e','y','V' >, + Emkb2Qt< Qt::Key_W, 'K','e','y','W' >, + Emkb2Qt< Qt::Key_X, 'K','e','y','X' >, + Emkb2Qt< Qt::Key_Y, 'K','e','y','Y' >, + Emkb2Qt< Qt::Key_Z, 'K','e','y','Z' >, + Emkb2Qt< Qt::Key_BracketLeft, '[' >, + Emkb2Qt< Qt::Key_Backslash, '\\' >, + Emkb2Qt< Qt::Key_BracketRight, ']' >, + Emkb2Qt< Qt::Key_Apostrophe, '\'' >, + Emkb2Qt< Qt::Key_QuoteLeft, 'B','a','c','k','q','u','o','t','e' >, + Emkb2Qt< Qt::Key_multiply, 'N','u','m','p','a','d','M','u','l','t','i','p','l','y' >, + Emkb2Qt< Qt::Key_Minus, 'N','u','m','p','a','d','S','u','b','t','r','a','c','t' >, + Emkb2Qt< Qt::Key_Period, 'N','u','m','p','a','d','D','e','c','i','m','a','l' >, + Emkb2Qt< Qt::Key_Plus, 'N','u','m','p','a','d','A','d','d' >, + Emkb2Qt< Qt::Key_division, 'N','u','m','p','a','d','D','i','v','i','d','e' >, + Emkb2Qt< Qt::Key_Equal, 'N','u','m','p','a','d','E','q','u','a','l' >, + Emkb2Qt< Qt::Key_0, 'N','u','m','p','a','d','0' >, + Emkb2Qt< Qt::Key_1, 'N','u','m','p','a','d','1' >, + Emkb2Qt< Qt::Key_2, 'N','u','m','p','a','d','2' >, + Emkb2Qt< Qt::Key_3, 'N','u','m','p','a','d','3' >, + Emkb2Qt< Qt::Key_4, 'N','u','m','p','a','d','4' >, + Emkb2Qt< Qt::Key_5, 'N','u','m','p','a','d','5' >, + Emkb2Qt< Qt::Key_6, 'N','u','m','p','a','d','6' >, + Emkb2Qt< Qt::Key_7, 'N','u','m','p','a','d','7' >, + Emkb2Qt< Qt::Key_8, 'N','u','m','p','a','d','8' >, + Emkb2Qt< Qt::Key_9, 'N','u','m','p','a','d','9' >, + Emkb2Qt< Qt::Key_Comma, 'N','u','m','p','a','d','C','o','m','m','a' >, + Emkb2Qt< Qt::Key_Enter, 'N','u','m','p','a','d','E','n','t','e','r' >, + Emkb2Qt< Qt::Key_Paste, 'P','a','s','t','e' >, + Emkb2Qt< Qt::Key_AltGr, 'A','l','t','R','i','g','h','t' >, + Emkb2Qt< Qt::Key_Help, 'H','e','l','p' >, + Emkb2Qt< Qt::Key_Equal, '=' >, + Emkb2Qt< Qt::Key_yen, 'I','n','t','l','Y','e','n' >, + + Emkb2Qt< Qt::Key_Exclam, '\x21' >, + Emkb2Qt< Qt::Key_QuoteDbl, '\x22' >, + Emkb2Qt< Qt::Key_NumberSign, '\x23' >, + Emkb2Qt< Qt::Key_Dollar, '\x24' >, + Emkb2Qt< Qt::Key_Percent, '\x25' >, + Emkb2Qt< Qt::Key_Ampersand, '\x26' >, + Emkb2Qt< Qt::Key_ParenLeft, '\x28' >, + Emkb2Qt< Qt::Key_ParenRight, '\x29' >, + Emkb2Qt< Qt::Key_Asterisk, '\x2a' >, + Emkb2Qt< Qt::Key_Plus, '\x2b' >, + Emkb2Qt< Qt::Key_Colon, '\x3a' >, + Emkb2Qt< Qt::Key_Semicolon, '\x3b' >, + Emkb2Qt< Qt::Key_Less, '\x3c' >, + Emkb2Qt< Qt::Key_Equal, '\x3d' >, + Emkb2Qt< Qt::Key_Greater, '\x3e' >, + Emkb2Qt< Qt::Key_Question, '\x3f' >, + Emkb2Qt< Qt::Key_At, '\x40' >, + Emkb2Qt< Qt::Key_BracketLeft, '\x5b' >, + Emkb2Qt< Qt::Key_Backslash, '\x5c' >, + Emkb2Qt< Qt::Key_BracketRight, '\x5d' >, + Emkb2Qt< Qt::Key_AsciiCircum, '\x5e' >, + Emkb2Qt< Qt::Key_Underscore, '\x5f' >, + Emkb2Qt< Qt::Key_QuoteLeft, '\x60'>, + Emkb2Qt< Qt::Key_BraceLeft, '\x7b'>, + Emkb2Qt< Qt::Key_Bar, '\x7c'>, + Emkb2Qt< Qt::Key_BraceRight, '\x7d'>, + Emkb2Qt< Qt::Key_AsciiTilde, '\x7e'>, + Emkb2Qt< Qt::Key_Space, '\x20' >, + Emkb2Qt< Qt::Key_Comma, '\x2c' >, + Emkb2Qt< Qt::Key_Minus, '\x2d' >, + Emkb2Qt< Qt::Key_Period, '\x2e' >, + Emkb2Qt< Qt::Key_Slash, '\x2f' >, + Emkb2Qt< Qt::Key_Apostrophe, '\x27' >, + Emkb2Qt< Qt::Key_Menu, 'C','o','n','t','e','x','t','M','e','n','u' >, + + Emkb2Qt< Qt::Key_Agrave, '\xc3','\xa0' >, + Emkb2Qt< Qt::Key_Aacute, '\xc3','\xa1' >, + Emkb2Qt< Qt::Key_Acircumflex, '\xc3','\xa2' >, + Emkb2Qt< Qt::Key_Adiaeresis, '\xc3','\xa4' >, + Emkb2Qt< Qt::Key_AE, '\xc3','\xa6' >, + Emkb2Qt< Qt::Key_Atilde, '\xc3','\xa3' >, + Emkb2Qt< Qt::Key_Aring, '\xc3','\xa5' >, + Emkb2Qt< Qt::Key_Ccedilla, '\xc3','\xa7' >, + Emkb2Qt< Qt::Key_Egrave, '\xc3','\xa8' >, + Emkb2Qt< Qt::Key_Eacute, '\xc3','\xa9' >, + Emkb2Qt< Qt::Key_Ecircumflex, '\xc3','\xaa' >, + Emkb2Qt< Qt::Key_Ediaeresis, '\xc3','\xab' >, + Emkb2Qt< Qt::Key_Icircumflex, '\xc3','\xae' >, + Emkb2Qt< Qt::Key_Idiaeresis, '\xc3','\xaf' >, + Emkb2Qt< Qt::Key_Ocircumflex, '\xc3','\xb4' >, + Emkb2Qt< Qt::Key_Odiaeresis, '\xc3','\xb6' >, + Emkb2Qt< Qt::Key_Ograve, '\xc3','\xb2' >, + Emkb2Qt< Qt::Key_Oacute, '\xc3','\xb3' >, + Emkb2Qt< Qt::Key_Ooblique, '\xc3','\xb8' >, + Emkb2Qt< Qt::Key_Otilde, '\xc3','\xb5' >, + Emkb2Qt< Qt::Key_Ucircumflex, '\xc3','\xbb' >, + Emkb2Qt< Qt::Key_Udiaeresis, '\xc3','\xbc' >, + Emkb2Qt< Qt::Key_Ugrave, '\xc3','\xb9' >, + Emkb2Qt< Qt::Key_Uacute, '\xc3','\xba' >, + Emkb2Qt< Qt::Key_Ntilde, '\xc3','\xb1' >, + Emkb2Qt< Qt::Key_ydiaeresis, '\xc3','\xbf' > + >::Data{} + ); + +static constexpr const auto DeadKeyShiftTbl = qMakeArray( + QSortedData< + // shifted + Emkb2Qt< Qt::Key_Agrave, '\xc3','\x80' >, + Emkb2Qt< Qt::Key_Aacute, '\xc3','\x81' >, + Emkb2Qt< Qt::Key_Acircumflex, '\xc3','\x82' >, + Emkb2Qt< Qt::Key_Adiaeresis, '\xc3','\x84' >, + Emkb2Qt< Qt::Key_AE, '\xc3','\x86' >, + Emkb2Qt< Qt::Key_Atilde, '\xc3','\x83' >, + Emkb2Qt< Qt::Key_Aring, '\xc3','\x85' >, + Emkb2Qt< Qt::Key_Egrave, '\xc3','\x88' >, + Emkb2Qt< Qt::Key_Eacute, '\xc3','\x89' >, + Emkb2Qt< Qt::Key_Ecircumflex, '\xc3','\x8a' >, + Emkb2Qt< Qt::Key_Ediaeresis, '\xc3','\x8b' >, + Emkb2Qt< Qt::Key_Icircumflex, '\xc3','\x8e' >, + Emkb2Qt< Qt::Key_Idiaeresis, '\xc3','\x8f' >, + Emkb2Qt< Qt::Key_Ocircumflex, '\xc3','\x94' >, + Emkb2Qt< Qt::Key_Odiaeresis, '\xc3','\x96' >, + Emkb2Qt< Qt::Key_Ograve, '\xc3','\x92' >, + Emkb2Qt< Qt::Key_Oacute, '\xc3','\x93' >, + Emkb2Qt< Qt::Key_Ooblique, '\xc3','\x98' >, + Emkb2Qt< Qt::Key_Otilde, '\xc3','\x95' >, + Emkb2Qt< Qt::Key_Ucircumflex, '\xc3','\x9b' >, + Emkb2Qt< Qt::Key_Udiaeresis, '\xc3','\x9c' >, + Emkb2Qt< Qt::Key_Ugrave, '\xc3','\x99' >, + Emkb2Qt< Qt::Key_Uacute, '\xc3','\x9a' >, + Emkb2Qt< Qt::Key_Ntilde, '\xc3','\x91' >, + Emkb2Qt< Qt::Key_Ccedilla, '\xc3','\x87' >, + Emkb2Qt< Qt::Key_ydiaeresis, '\xc3','\x8f' > + >::Data{} +); + // macOS CTRL <-> META switching. We most likely want to enable // the existing switching code in QtGui, but for now do it here. static bool g_usePlatformMacCtrlMetaSwitching = false; @@ -155,148 +409,44 @@ QFlags QWasmEventTranslator::translateMouseEventModifier(c int QWasmEventTranslator::keyboard_cb(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData) { - Q_UNUSED(userData) - - bool alphanumeric; - Qt::Key qtKey = translateEmscriptKey(keyEvent, &alphanumeric); - - QEvent::Type keyType = QEvent::None; - switch (eventType) { - case EMSCRIPTEN_EVENT_KEYPRESS: - case EMSCRIPTEN_EVENT_KEYDOWN: //down - keyType = QEvent::KeyPress; - break; - case EMSCRIPTEN_EVENT_KEYUP: //up - keyType = QEvent::KeyRelease; - break; - default: - break; - }; - - if (keyType == QEvent::None) - return 0; - - QFlags mods = translateKeyboardEventModifier(keyEvent); - bool accepted = false; - - if (keyType == QEvent::KeyPress && - mods.testFlag(Qt::ControlModifier) - && qtKey == Qt::Key_V) { - QWasmIntegration::get()->getWasmClipboard()->readTextFromClipboard(); - } else { - QString keyText = alphanumeric ? QString(keyEvent->key) : QString(); - accepted = QWindowSystemInterface::handleKeyEvent( - 0, keyType, qtKey, translateKeyboardEventModifier(keyEvent), keyText); - } - - if (keyType == QEvent::KeyPress && - mods.testFlag(Qt::ControlModifier) - && qtKey == Qt::Key_C) { - QWasmIntegration::get()->getWasmClipboard()->writeTextToClipboard(); - } - QWasmEventDispatcher::maintainTimers(); + QWasmEventTranslator *wasmTranslator = reinterpret_cast(userData); + bool accepted = wasmTranslator->processKeyboard(eventType, keyEvent); return accepted ? 1 : 0; } -Qt::Key QWasmEventTranslator::translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey, bool *outAlphanumeric) +Qt::Key QWasmEventTranslator::translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey) { - Qt::Key qtKey; - if (outAlphanumeric) - *outAlphanumeric = false; - - switch (emscriptKey->keyCode) { - case KeyMultiply: qtKey = Qt::Key_Asterisk; *outAlphanumeric = true; break; - case KeyAdd: qtKey = Qt::Key_Plus; *outAlphanumeric = true; break; - case KeyMinus: qtKey = Qt::Key_Minus; *outAlphanumeric = true; break; - case KeySubtract: qtKey = Qt::Key_Minus; *outAlphanumeric = true; break; - case KeyDecimal: qtKey = Qt::Key_Period; *outAlphanumeric = true; break; - case KeyDivide: qtKey = Qt::Key_Slash; *outAlphanumeric = true; break; - case KeyNumPad0: qtKey = Qt::Key_0; *outAlphanumeric = true; break; - case KeyNumPad1: qtKey = Qt::Key_1; *outAlphanumeric = true; break; - case KeyNumPad2: qtKey = Qt::Key_2; *outAlphanumeric = true; break; - case KeyNumPad3: qtKey = Qt::Key_3; *outAlphanumeric = true; break; - case KeyNumPad4: qtKey = Qt::Key_4; *outAlphanumeric = true; break; - case KeyNumPad5: qtKey = Qt::Key_5; *outAlphanumeric = true; break; - case KeyNumPad6: qtKey = Qt::Key_6; *outAlphanumeric = true; break; - case KeyNumPad7: qtKey = Qt::Key_7; *outAlphanumeric = true; break; - case KeyNumPad8: qtKey = Qt::Key_8; *outAlphanumeric = true; break; - case KeyNumPad9: qtKey = Qt::Key_9; *outAlphanumeric = true; break; - case KeyComma: qtKey = Qt::Key_Comma; *outAlphanumeric = true; break; - case KeyPeriod: qtKey = Qt::Key_Period; *outAlphanumeric = true; break; - case KeySlash: qtKey = Qt::Key_Slash; *outAlphanumeric = true; break; - case KeySemiColon: qtKey = Qt::Key_Semicolon; *outAlphanumeric = true; break; - case KeyEquals: qtKey = Qt::Key_Equal; *outAlphanumeric = true; break; - case KeyOpenBracket: qtKey = Qt::Key_BracketLeft; *outAlphanumeric = true; break; - case KeyCloseBracket: qtKey = Qt::Key_BracketRight; *outAlphanumeric = true; break; - case KeyBackSlash: qtKey = Qt::Key_Backslash; *outAlphanumeric = true; break; - case KeyMeta: - Q_FALLTHROUGH(); - case KeyMetaRight: - qtKey = Qt::Key_Meta; - break; - case KeyTab: qtKey = Qt::Key_Tab; break; - case KeyClear: qtKey = Qt::Key_Clear; break; - case KeyBackSpace: qtKey = Qt::Key_Backspace; break; - case KeyEnter: qtKey = Qt::Key_Return; break; - case KeyShift: qtKey = Qt::Key_Shift; break; - case KeyControl: qtKey = Qt::Key_Control; break; - case KeyAlt: qtKey = Qt::Key_Alt; break; - case KeyCapsLock: qtKey = Qt::Key_CapsLock; break; - case KeyEscape: qtKey = Qt::Key_Escape; break; - case KeyPageUp: qtKey = Qt::Key_PageUp; break; - case KeyPageDown: qtKey = Qt::Key_PageDown; break; - case KeyEnd: qtKey = Qt::Key_End; break; - case KeyHome: qtKey = Qt::Key_Home; break; - case KeyLeft: qtKey = Qt::Key_Left; break; - case KeyUp: qtKey = Qt::Key_Up; break; - case KeyRight: qtKey = Qt::Key_Right; break; - case KeyDown: qtKey = Qt::Key_Down; break; - case KeyBrightnessDown: qtKey = Qt::Key_MonBrightnessDown; break; - case KeyBrightnessUp: qtKey = Qt::Key_MonBrightnessUp; break; - case KeyMediaTrackPrevious: qtKey = Qt::Key_MediaPrevious; break; - case KeyMediaPlayPause: qtKey = Qt::Key_MediaTogglePlayPause; break; - case KeyMediaTrackNext: qtKey = Qt::Key_MediaNext; break; - case KeyAudioVolumeMute: qtKey = Qt::Key_VolumeMute; break; - case KeyAudioVolumeDown: qtKey = Qt::Key_VolumeDown; break; - case KeyAudioVolumeUp: qtKey = Qt::Key_VolumeUp; break; - case KeyDelete: qtKey = Qt::Key_Delete; break; - - case KeyF1: qtKey = Qt::Key_F1; break; - case KeyF2: qtKey = Qt::Key_F2; break; - case KeyF3: qtKey = Qt::Key_F3; break; - case KeyF4: qtKey = Qt::Key_F4; break; - case KeyF5: qtKey = Qt::Key_F5; break; - case KeyF6: qtKey = Qt::Key_F6; break; - case KeyF7: qtKey = Qt::Key_F7; break; - case KeyF8: qtKey = Qt::Key_F8; break; - case KeyF9: qtKey = Qt::Key_F9; break; - case KeyF10: qtKey = Qt::Key_F10; break; - case KeyF11: qtKey = Qt::Key_F11; break; - case KeyF12: qtKey = Qt::Key_F12; break; - case 124: qtKey = Qt::Key_F13; break; - case 125: qtKey = Qt::Key_F14; break; - - case KeySpace: - default: - if (outAlphanumeric) - *outAlphanumeric = true; - qtKey = static_cast(emscriptKey->keyCode); - break; - } + Qt::Key qtKey = Qt::Key_unknown; + + if (qstrncmp(emscriptKey->code, "Key", 3) == 0 || qstrncmp(emscriptKey->code, "Numpad", 6) == 0) { - // Handle Mac command key. Using event->keyCode as above is - // no reliable since the codes differ between browsers. - if (qstrncmp(emscriptKey->key, "Meta", 4) == 0) { - qtKey = Qt::Key_Meta; - *outAlphanumeric = false; + emkb2qt_t searchKey{emscriptKey->code, 0}; // search emcsripten code + auto it1 = std::lower_bound(KeyTbl.cbegin(), KeyTbl.cend(), searchKey); + if (it1 != KeyTbl.end() && !(searchKey < *it1)) { + qtKey = static_cast(it1->qt); + } + } else if (qstrncmp(emscriptKey->key, "Dead", 4) == 0 ) { + emkb2qt_t searchKey1{emscriptKey->code, 0}; + for (auto it1 = KeyTbl.cbegin(); it1 != KeyTbl.end(); ++it1) + if (it1 != KeyTbl.end() && (qstrcmp(searchKey1.em, it1->em) == 0)) { + qtKey = static_cast(it1->qt); + } } - if (g_usePlatformMacCtrlMetaSwitching) { - if (qtKey == Qt::Key_Meta) - qtKey = Qt::Key_Control; - else if (qtKey == Qt::Key_Control) - qtKey = Qt::Key_Meta; + if (qtKey == Qt::Key_unknown) { + emkb2qt_t searchKey{emscriptKey->key, 0}; // search unicode key + auto it1 = std::lower_bound(KeyTbl.cbegin(), KeyTbl.cend(), searchKey); + if (it1 != KeyTbl.end() && !(searchKey < *it1)) { + qtKey = static_cast(it1->qt); + } + } + if (qtKey == Qt::Key_unknown) {//try harder with shifted number keys + emkb2qt_t searchKey1{emscriptKey->key, 0}; + for (auto it1 = KeyTbl.cbegin(); it1 != KeyTbl.end(); ++it1) + if (it1 != KeyTbl.end() && (qstrcmp(searchKey1.em, it1->em) == 0)) { + qtKey = static_cast(it1->qt); + } } return qtKey; @@ -481,7 +631,6 @@ int QWasmEventTranslator::focus_cb(int /*eventType*/, const EmscriptenFocusEvent int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData) { Q_UNUSED(eventType) - Q_UNUSED(userData) EmscriptenMouseEvent mouseEvent = wheelEvent->mouse; @@ -501,7 +650,8 @@ int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wh if (g_useNaturalScrolling) //macOS platform has document oriented scrolling scrollFactor = -scrollFactor; - Qt::KeyboardModifiers modifiers = translateMouseEventModifier(&mouseEvent); + QWasmEventTranslator *translator = (QWasmEventTranslator*)userData; + Qt::KeyboardModifiers modifiers = translator->translateMouseEventModifier(&mouseEvent); auto timestamp = mouseEvent.timestamp; QPoint globalPoint(mouseEvent.canvasX, mouseEvent.canvasY); @@ -514,8 +664,8 @@ int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wh if (wheelEvent->deltaY != 0) pixelDelta.setY(wheelEvent->deltaY * scrollFactor); if (wheelEvent->deltaX != 0) pixelDelta.setX(wheelEvent->deltaX * scrollFactor); - QWindowSystemInterface::handleWheelEvent(window2, timestamp, localPoint, globalPoint, QPoint(), pixelDelta, modifiers); - + QWindowSystemInterface::handleWheelEvent(window2, timestamp, localPoint, + globalPoint, QPoint(), pixelDelta, modifiers); QWasmEventDispatcher::maintainTimers(); return 1; @@ -562,12 +712,16 @@ int QWasmEventTranslator::touchCallback(int eventType, const EmscriptenTouchEven } QWasmEventTranslator *wasmEventTranslator = (QWasmEventTranslator*)userData; - QFlags keyModifier = translatKeyModifier(touchEvent); + QFlags keyModifier = wasmEventTranslator->translatKeyModifier(touchEvent); if (eventType != EMSCRIPTEN_EVENT_TOUCHCANCEL) - QWindowSystemInterface::handleTouchEvent(window2, wasmEventTranslator->getTimestamp(), wasmEventTranslator->touchDevice, touchPointList, keyModifier); + QWindowSystemInterface::handleTouchEvent + (window2, wasmEventTranslator->getTimestamp(), + wasmEventTranslator->touchDevice, + touchPointList, keyModifier); else - QWindowSystemInterface::handleTouchCancelEvent(window2, wasmEventTranslator->getTimestamp(), wasmEventTranslator->touchDevice, keyModifier); + QWindowSystemInterface::handleTouchCancelEvent(window2, wasmEventTranslator->getTimestamp(), + wasmEventTranslator->touchDevice, keyModifier); QWasmEventDispatcher::maintainTimers(); return 1; @@ -578,4 +732,112 @@ quint64 QWasmEventTranslator::getTimestamp() return QDeadlineTimer::current().deadlineNSecs() / 1000; } +Qt::Key QWasmEventTranslator::translateDeadKey(Qt::Key deadKey, Qt::Key accentBaseKey) +{ + Qt::Key wasmKey = Qt::Key_unknown; + switch (deadKey) { +#ifdef Q_OS_MACOS + case Qt::Key_QuoteLeft: // ` macOS: Key_Dead_Grave +#else + case Qt::Key_O: // ´ Key_Dead_Grave +#endif + wasmKey = graveKeyTable.value(accentBaseKey); + break; + case Qt::Key_E: // ´ Key_Dead_Acute + wasmKey = acuteKeyTable.value(accentBaseKey); + break; + case Qt::Key_AsciiTilde: + case Qt::Key_N:// Key_Dead_Tilde + wasmKey = tildeKeyTable.value(accentBaseKey); + break; +#ifndef Q_OS_MACOS + case Qt::Key_QuoteLeft: +#endif + case Qt::Key_U:// ¨ Key_Dead_Diaeresis + wasmKey = diaeresisKeyTable.value(accentBaseKey); + break; + case Qt::Key_I:// macOS Key_Dead_Circumflex + case Qt::Key_6:// linux + case Qt::Key_Apostrophe:// linux + wasmKey = circumflexKeyTable.value(accentBaseKey); + break; + break; + default: + break; + }; + + return wasmKey; +} + +bool QWasmEventTranslator::processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent) +{ + Qt::Key qtKey = translateEmscriptKey(keyEvent); + + Qt::KeyboardModifiers modifiers = translateKeyboardEventModifier(keyEvent); + + QString keyText; + QEvent::Type keyType = QEvent::None; + switch (eventType) { + case EMSCRIPTEN_EVENT_KEYPRESS: + case EMSCRIPTEN_EVENT_KEYDOWN: // down + keyType = QEvent::KeyPress; + + if (m_emDeadKey != Qt::Key_unknown) { + + Qt::Key transformedKey = translateDeadKey(m_emDeadKey, qtKey); + + if (transformedKey != Qt::Key_unknown) + qtKey = transformedKey; + + if (keyEvent->shiftKey == 0) { + for (auto it = KeyTbl.cbegin(); it != KeyTbl.end(); ++it) { + if (it != KeyTbl.end() && (qtKey == static_cast(it->qt))) { + keyText = it->em; + m_emDeadKey = Qt::Key_unknown; + break; + } + } + } else { + for (auto it = DeadKeyShiftTbl.cbegin(); it != DeadKeyShiftTbl.end(); ++it) { + if (it != DeadKeyShiftTbl.end() && (qtKey == static_cast(it->qt))) { + keyText = it->em; + m_emDeadKey = Qt::Key_unknown; + break; + } + } + } + } + if (qstrncmp(keyEvent->key, "Dead", 4) == 0 || qtKey == Qt::Key_AltGr) { + qtKey = translateEmscriptKey(keyEvent); + m_emStickyDeadKey = true; + if (keyEvent->shiftKey == 1 && qtKey == Qt::Key_QuoteLeft) + qtKey = Qt::Key_AsciiTilde; + m_emDeadKey = qtKey; + } + break; + case EMSCRIPTEN_EVENT_KEYUP: // up + keyType = QEvent::KeyRelease; + if (m_emStickyDeadKey && qtKey != Qt::Key_Alt) { + m_emStickyDeadKey = false; + } + break; + default: + break; + }; + + if (keyType == QEvent::None) + return 0; + + bool accepted = false; + + if (keyText.isEmpty()) + keyText = QString(keyEvent->key); + if (keyText.size() > 1) + keyText.clear(); + accepted = QWindowSystemInterface::handleKeyEvent( + 0, keyType, qtKey, modifiers, keyText); + QWasmEventDispatcher::maintainTimers(); + return accepted ? 1 : 0; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.h b/src/plugins/platforms/wasm/qwasmeventtranslator.h index f3dff8e48c..25e2a630b6 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.h +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.h @@ -36,6 +36,7 @@ #include #include "qwasmwindow.h" #include +#include QT_BEGIN_NAMESPACE @@ -45,130 +46,6 @@ class QWasmEventTranslator : public QObject { Q_OBJECT - enum KeyCode { - // numpad - KeyNumPad0 = 0x60, - KeyNumPad1 = 0x61, - KeyNumPad2 = 0x62, - KeyNumPad3 = 0x63, - KeyNumPad4 = 0x64, - KeyNumPad5 = 0x65, - KeyNumPad6 = 0x66, - KeyNumPad7 = 0x67, - KeyNumPad8 = 0x68, - KeyNumPad9 = 0x69, - KeyMultiply = 0x6A, - KeyAdd = 0x6B, - KeySeparator = 0x6C, - KeySubtract = 0x6D, - KeyDecimal = 0x6E, - KeyDivide = 0x6F, - KeyMeta = 0x5B, - KeyMetaRight = 0x5C, - //////// - KeyClear = 0x90, - KeyEnter = 0xD, - KeyBackSpace = 0x08, - KeyCancel = 0x03, - KeyTab = 0x09, - KeyShift = 0x10, - KeyControl = 0x11, - KeyAlt = 0x12, - KeyPause = 0x13, - KeyCapsLock = 0x14, - KeyEscape = 0x1B, - KeySpace = 0x20, - KeyPageUp = 0x21, - KeyPageDown = 0x22, - KeyEnd = 0x23, - KeyHome = 0x24, - KeyLeft = 0x25, - KeyUp = 0x26, - KeyRight = 0x27, - KeyDown = 0x28, - KeyComma = 0xBC, - KeyPeriod = 0xBE, - KeySlash = 0xBF, - KeyZero = 0x30, - KeyOne = 0x31, - KeyTwo = 0x32, - KeyThree = 0x33, - KeyFour = 0x34, - KeyFive = 0x35, - KeySix = 0x36, - KeySeven = 0x37, - KeyEight = 0x38, - KeyNine = 0x39, - KeyBrightnessDown = 0xD8, - KeyBrightnessUp = 0xD9, - KeyMediaTrackPrevious = 0xB1, - KeyMediaPlayPause = 0xB3, - KeyMediaTrackNext = 0xB0, - KeyAudioVolumeMute = 0xAD, - KeyAudioVolumeDown = 0xAE, - KeyAudioVolumeUp = 0xAF, - KeySemiColon = 0xBA, - KeyEquals = 0xBB, - KeyMinus = 0xBD, - KeyA = 0x41, - KeyB = 0x42, - KeyC = 0x43, - KeyD = 0x44, - KeyE = 0x45, - KeyF = 0x46, - KeyG = 0x47, - KeyH = 0x48, - KeyI = 0x49, - KeyJ = 0x4A, - KeyK = 0x4B, - KeyL = 0x4C, - KeyM = 0x4D, - KeyN = 0x4E, - KeyO = 0x4F, - KeyP = 0x50, - KeyQ = 0x51, - KeyR = 0x52, - KeyS = 0x53, - KeyT = 0x54, - KeyU = 0x55, - KeyV = 0x56, - KeyW = 0x57, - KeyX = 0x58, - KeyY = 0x59, - KeyZ = 0x5A, - KeyOpenBracket = 0xDB, - KeyBackSlash = 0xDC, - KeyCloseBracket = 0xDD, - KeyF1 = 0x70, - KeyF2 = 0x71, - KeyF3 = 0x72, - KeyF4 = 0x73, - KeyF5 = 0x74, - KeyF6 = 0x75, - KeyF7 = 0x76, - KeyF8 = 0x77, - KeyF9 = 0x78, - KeyF10 = 0x79, - KeyF11 = 0x7A, - KeyF12 = 0x7B, - KeyDelete = 0x2E, - KeyNumLock = 0x90, - KeyScrollLock = 0x91, - KeyPrintScreen = 0x9A, - KeyInsert = 0x9B, - KeyHelp = 0x9C, - KeyBackQuote = 0xC0, - KeyQuote = 0xDE, - KeyFinal = 0x18, - KeyConvert = 0x1C, - KeyNonConvert = 0x1D, - KeyAccept = 0x1E, - KeyModeChange = 0x1F, - KeyKana = 0x15, - KeyKanji = 0x19, - KeyUndefined = 0x0 - }; - public: explicit QWasmEventTranslator(QObject *parent = 0); @@ -185,14 +62,54 @@ public: Q_SIGNALS: void getWindowAt(const QPoint &point, QWindow **window); private: - static Qt::Key translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey, bool *outAlphanumretic); + + Qt::Key translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey); template - static QFlags translatKeyModifier(const Event *event); - static QFlags translateKeyboardEventModifier(const EmscriptenKeyboardEvent *keyEvent); - static QFlags translateMouseEventModifier(const EmscriptenMouseEvent *mouseEvent); - static Qt::MouseButton translateMouseButton(unsigned short button); + QFlags translatKeyModifier(const Event *event); + QFlags translateKeyboardEventModifier(const EmscriptenKeyboardEvent *keyEvent); + QFlags translateMouseEventModifier(const EmscriptenMouseEvent *mouseEvent); + Qt::MouseButton translateMouseButton(unsigned short button); void processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent); + bool processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent); + + Qt::Key translateDeadKey(Qt::Key deadKey, Qt::Key accentBaseKey); + + QHash tildeKeyTable { // ~ + { Qt::Key_A, Qt::Key_Atilde}, + { Qt::Key_N, Qt::Key_Ntilde}, + { Qt::Key_O, Qt::Key_Otilde} + }; + QHash graveKeyTable { // ` + { Qt::Key_A, Qt::Key_Agrave}, + { Qt::Key_E, Qt::Key_Egrave}, + { Qt::Key_I, Qt::Key_Igrave}, + { Qt::Key_O, Qt::Key_Ograve}, + { Qt::Key_U, Qt::Key_Ugrave} + }; + QHash acuteKeyTable { // ' + { Qt::Key_A, Qt::Key_Aacute}, + { Qt::Key_E, Qt::Key_Eacute}, + { Qt::Key_I, Qt::Key_Iacute}, + { Qt::Key_O, Qt::Key_Oacute}, + { Qt::Key_U, Qt::Key_Uacute}, + { Qt::Key_Y, Qt::Key_Yacute} + }; + QHash diaeresisKeyTable { // umlaut ¨ + { Qt::Key_A, Qt::Key_Adiaeresis}, + { Qt::Key_E, Qt::Key_Ediaeresis}, + { Qt::Key_I, Qt::Key_Idiaeresis}, + { Qt::Key_O, Qt::Key_Odiaeresis}, + { Qt::Key_U, Qt::Key_Udiaeresis}, + { Qt::Key_Y, Qt::Key_ydiaeresis} + }; + QHash circumflexKeyTable { // ^ + { Qt::Key_A, Qt::Key_Acircumflex}, + { Qt::Key_E, Qt::Key_Ecircumflex}, + { Qt::Key_I, Qt::Key_Icircumflex}, + { Qt::Key_O, Qt::Key_Ocircumflex}, + { Qt::Key_U, Qt::Key_Ucircumflex} + }; private: QWindow *draggedWindow; @@ -205,6 +122,9 @@ private: QRect resizeStartRect; QTouchDevice *touchDevice; quint64 getTimestamp(); + + Qt::Key m_emDeadKey = Qt::Key_unknown; + bool m_emStickyDeadKey = false; }; QT_END_NAMESPACE -- cgit v1.2.3 From 7319c342c34f6bcc8f0322e9613c6296331f1487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 13 Feb 2019 12:52:33 +0100 Subject: macOS: Implement QNSWindow/QNSPanel mixin using preprocessor includes We want to share the implementation between the two classes, but Objective-C doesn't natively have a mixin-feature. Instead of using dynamic super-calls at runtime (which worked fine, but added complexity), we now do the mixin at compile time using the preprocessor. The dynamic-super feature is left in, in case we need it in other areas in the future. Change-Id: I95dfa7f18cba86cc518e963dd018944ef113ac06 Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qnswindow.h | 8 -- src/plugins/platforms/cocoa/qnswindow.mm | 170 ++++++++++++++----------------- 2 files changed, 75 insertions(+), 103 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qnswindow.h b/src/plugins/platforms/cocoa/qnswindow.h index dcbcd58901..2827e41049 100644 --- a/src/plugins/platforms/cocoa/qnswindow.h +++ b/src/plugins/platforms/cocoa/qnswindow.h @@ -60,15 +60,7 @@ QT_FORWARD_DECLARE_CLASS(QCocoaWindow) #define QNSWindowProtocol QT_MANGLE_NAMESPACE(QNSWindowProtocol) @protocol QNSWindowProtocol -@optional -- (BOOL)canBecomeKeyWindow; -- (BOOL)worksWhenModal; -- (void)sendEvent:(NSEvent*)theEvent; - (void)closeAndRelease; -- (void)dealloc; -- (BOOL)isOpaque; -- (NSColor *)backgroundColor; -- (NSString *)description; @property (nonatomic, readonly) QCocoaWindow *platformWindow; @end diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm index 28a9fa8607..3a1a04f887 100644 --- a/src/plugins/platforms/cocoa/qnswindow.mm +++ b/src/plugins/platforms/cocoa/qnswindow.mm @@ -37,6 +37,8 @@ ** ****************************************************************************/ +#if !defined(QNSWINDOW_PROTOCOL_IMPLMENTATION) + #include "qnswindow.h" #include "qcocoawindow.h" #include "qcocoahelpers.h" @@ -89,36 +91,79 @@ static bool isMouseEvent(NSEvent *ev) } @end -#define super USE_qt_objcDynamicSuper_INSTEAD - @implementation QNSWindow +#define QNSWINDOW_PROTOCOL_IMPLMENTATION 1 +#include "qnswindow.mm" +#undef QNSWINDOW_PROTOCOL_IMPLMENTATION -+ (void)load ++ (void)applicationActivationChanged:(NSNotification*)notification { - const Class windowClass = [self class]; - const Class panelClass = [QNSPanel class]; - - unsigned int protocolCount; - Protocol **protocols = class_copyProtocolList(windowClass, &protocolCount); - for (unsigned int i = 0; i < protocolCount; ++i) { - Protocol *protocol = protocols[i]; - - unsigned int methodDescriptionsCount; - objc_method_description *methods = protocol_copyMethodDescriptionList( - protocol, NO, YES, &methodDescriptionsCount); - - for (unsigned int j = 0; j < methodDescriptionsCount; ++j) { - objc_method_description method = methods[j]; - class_addMethod(panelClass, method.name, - class_getMethodImplementation(windowClass, method.name), - method.types); + const id sender = self; + NSEnumerator *windowEnumerator = nullptr; + NSApplication *application = [NSApplication sharedApplication]; + + // Unfortunately there's no NSWindowListOrderedBackToFront, + // so we have to manually reverse the order using an array. + NSMutableArray *windows = [NSMutableArray new]; + [application enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack + usingBlock:^(NSWindow *window, BOOL *) { + // For some reason AppKit will give us nil-windows, skip those + if (!window) + return; + + [windows addObject:window]; + } + ]; + + windowEnumerator = windows.reverseObjectEnumerator; + + for (NSWindow *window in windowEnumerator) { + // We're meddling with normal and floating windows, so leave others alone + if (!(window.level == NSNormalWindowLevel || window.level == NSFloatingWindowLevel)) + continue; + + // Windows that hide automatically will keep their NSFloatingWindowLevel, + // and hence be on top of the window stack. We don't want to affect these + // windows, as otherwise we might end up with key windows being ordered + // behind these auto-hidden windows when activating the application by + // clicking on a new tool window. + if (window.hidesOnDeactivate) + continue; + + if ([window conformsToProtocol:@protocol(QNSWindowProtocol)]) { + QCocoaWindow *cocoaWindow = static_cast(window).platformWindow; + window.level = notification.name == NSApplicationWillResignActiveNotification ? + NSNormalWindowLevel : cocoaWindow->windowLevel(cocoaWindow->window()->flags()); } - free(methods); - } - free(protocols); + // The documentation says that "when a window enters a new level, it’s ordered + // in front of all its peers in that level", but that doesn't seem to be the + // case in practice. To keep the order correct after meddling with the window + // levels, we explicitly order each window to the front. Since we are iterating + // the windows in back-to-front order, this is okey. The call also triggers AppKit + // to re-evaluate the level in relation to windows from other applications, + // working around an issue where our tool windows would stay on top of other + // application windows if activation was transferred to another application by + // clicking on it instead of via the application switcher or Dock. Finally, we + // do this re-ordering for all windows (except auto-hiding ones), otherwise we would + // end up triggering a bug in AppKit where the tool windows would disappear behind + // the application window. + [window orderFront:sender]; + } } +@end + +@implementation QNSPanel +#define QNSWINDOW_PROTOCOL_IMPLMENTATION 1 +#include "qnswindow.mm" +#undef QNSWINDOW_PROTOCOL_IMPLMENTATION +@end + +#else // QNSWINDOW_PROTOCOL_IMPLMENTATION + +// The following methods are mixed in to the QNSWindow and QNSPanel classes via includes + - (QCocoaWindow *)platformWindow { return qnsview_cast(self.contentView).platformWindow; @@ -126,7 +171,7 @@ static bool isMouseEvent(NSEvent *ev) - (NSString *)description { - NSMutableString *description = [NSMutableString stringWithString:qt_objcDynamicSuper()]; + NSMutableString *description = [NSMutableString stringWithString:[super description]]; #ifndef QT_NO_DEBUG_STREAM QString contentViewDescription; @@ -187,13 +232,13 @@ static bool isMouseEvent(NSEvent *ev) } } - return qt_objcDynamicSuper(); + return [super worksWhenModal]; } - (BOOL)isOpaque { return self.platformWindow ? - self.platformWindow->isOpaque() : qt_objcDynamicSuper(); + self.platformWindow->isOpaque() : [super isOpaque]; } /*! @@ -209,7 +254,7 @@ static bool isMouseEvent(NSEvent *ev) - (NSColor *)backgroundColor { return self.styleMask == NSWindowStyleMaskBorderless - ? [NSColor clearColor] : qt_objcDynamicSuper(); + ? [NSColor clearColor] : [super backgroundColor]; } - (void)sendEvent:(NSEvent*)theEvent @@ -234,7 +279,7 @@ static bool isMouseEvent(NSEvent *ev) return; } - qt_objcDynamicSuper(theEvent); + [super sendEvent:theEvent]; if (!self.platformWindow) return; // Platform window went away while processing event @@ -256,77 +301,12 @@ static bool isMouseEvent(NSEvent *ev) [self release]; } -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wobjc-missing-super-calls" - (void)dealloc { qCDebug(lcQpaWindow) << "Deallocating" << self; self.delegate = nil; - qt_objcDynamicSuper(); + [super dealloc]; } -#pragma clang diagnostic pop -+ (void)applicationActivationChanged:(NSNotification*)notification -{ - const id sender = self; - NSEnumerator *windowEnumerator = nullptr; - NSApplication *application = [NSApplication sharedApplication]; - - // Unfortunately there's no NSWindowListOrderedBackToFront, - // so we have to manually reverse the order using an array. - NSMutableArray *windows = [NSMutableArray new]; - [application enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack - usingBlock:^(NSWindow *window, BOOL *) { - // For some reason AppKit will give us nil-windows, skip those - if (!window) - return; - - [windows addObject:window]; - } - ]; - - windowEnumerator = windows.reverseObjectEnumerator; - - for (NSWindow *window in windowEnumerator) { - // We're meddling with normal and floating windows, so leave others alone - if (!(window.level == NSNormalWindowLevel || window.level == NSFloatingWindowLevel)) - continue; - - // Windows that hide automatically will keep their NSFloatingWindowLevel, - // and hence be on top of the window stack. We don't want to affect these - // windows, as otherwise we might end up with key windows being ordered - // behind these auto-hidden windows when activating the application by - // clicking on a new tool window. - if (window.hidesOnDeactivate) - continue; - - if ([window conformsToProtocol:@protocol(QNSWindowProtocol)]) { - QCocoaWindow *cocoaWindow = static_cast(window).platformWindow; - window.level = notification.name == NSApplicationWillResignActiveNotification ? - NSNormalWindowLevel : cocoaWindow->windowLevel(cocoaWindow->window()->flags()); - } - - // The documentation says that "when a window enters a new level, it’s ordered - // in front of all its peers in that level", but that doesn't seem to be the - // case in practice. To keep the order correct after meddling with the window - // levels, we explicitly order each window to the front. Since we are iterating - // the windows in back-to-front order, this is okey. The call also triggers AppKit - // to re-evaluate the level in relation to windows from other applications, - // working around an issue where our tool windows would stay on top of other - // application windows if activation was transferred to another application by - // clicking on it instead of via the application switcher or Dock. Finally, we - // do this re-ordering for all windows (except auto-hiding ones), otherwise we would - // end up triggering a bug in AppKit where the tool windows would disappear behind - // the application window. - [window orderFront:sender]; - } -} - -@end - -@implementation QNSPanel -// Implementation shared with QNSWindow, see +[QNSWindow load] above -@end - -#undef super +#endif -- cgit v1.2.3 From 0a2e91328e6340b6ecfeb4ee202ab1527cefaeca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 13 Feb 2019 13:50:02 +0100 Subject: macOS: Set up platform window reference before initializing QNSWindow/Panel Initializing the window will end up in [NSWindow _commonAwake], which calls many of the getters. We need to set up the platform window reference first, so we can properly reflect the window's state during initialization. Change-Id: I5349273b1930ee8a57dc518db74be90d2426f61c Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qcocoascreen.mm | 3 +- src/plugins/platforms/cocoa/qcocoawindow.mm | 3 +- src/plugins/platforms/cocoa/qnswindow.h | 3 ++ src/plugins/platforms/cocoa/qnswindow.mm | 55 +++++++++++++++++------------ 4 files changed, 39 insertions(+), 25 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm index 830a387fd1..6a5b0e6e3e 100644 --- a/src/plugins/platforms/cocoa/qcocoascreen.mm +++ b/src/plugins/platforms/cocoa/qcocoascreen.mm @@ -410,8 +410,7 @@ QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const if (![nsWindow conformsToProtocol:@protocol(QNSWindowProtocol)]) continue; - id proto = static_cast >(nsWindow); - QCocoaWindow *cocoaWindow = proto.platformWindow; + QCocoaWindow *cocoaWindow = qnsview_cast(nsWindow.contentView).platformWindow; if (!cocoaWindow) continue; window = cocoaWindow->window(); diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 2718dc9600..d1047e1965 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1539,7 +1539,8 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel) // Deferring window creation breaks OpenGL (the GL context is // set up before the window is shown and needs a proper window) backing:NSBackingStoreBuffered defer:NO - screen:cocoaScreen->nativeScreen()]; + screen:cocoaScreen->nativeScreen() + platformWindow:this]; Q_ASSERT_X(nsWindow.screen == cocoaScreen->nativeScreen(), "QCocoaWindow", "Resulting NSScreen should match the requested NSScreen"); diff --git a/src/plugins/platforms/cocoa/qnswindow.h b/src/plugins/platforms/cocoa/qnswindow.h index 2827e41049..5fc48d826f 100644 --- a/src/plugins/platforms/cocoa/qnswindow.h +++ b/src/plugins/platforms/cocoa/qnswindow.h @@ -60,6 +60,9 @@ QT_FORWARD_DECLARE_CLASS(QCocoaWindow) #define QNSWindowProtocol QT_MANGLE_NAMESPACE(QNSWindowProtocol) @protocol QNSWindowProtocol +- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style + backing:(NSBackingStoreType)backingStoreType defer:(BOOL)flag screen:(NSScreen *)screen + platformWindow:(QCocoaWindow*)window; - (void)closeAndRelease; @property (nonatomic, readonly) QCocoaWindow *platformWindow; @end diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm index 3a1a04f887..52f765eb31 100644 --- a/src/plugins/platforms/cocoa/qnswindow.mm +++ b/src/plugins/platforms/cocoa/qnswindow.mm @@ -162,11 +162,28 @@ static bool isMouseEvent(NSEvent *ev) #else // QNSWINDOW_PROTOCOL_IMPLMENTATION -// The following methods are mixed in to the QNSWindow and QNSPanel classes via includes +// The following content is mixed in to the QNSWindow and QNSPanel classes via includes + +{ + // Member variables + QPointer m_platformWindow; +} + +- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style + backing:(NSBackingStoreType)backingStoreType defer:(BOOL)defer screen:(NSScreen *)screen + platformWindow:(QCocoaWindow*)window +{ + // Initializing the window will end up in [NSWindow _commonAwake], which calls many + // of the getters below. We need to set up the platform window reference first, so + // we can properly reflect the window's state during initialization. + m_platformWindow = window; + + return [super initWithContentRect:contentRect styleMask:style backing:backingStoreType defer:defer screen:screen]; +} - (QCocoaWindow *)platformWindow { - return qnsview_cast(self.contentView).platformWindow; + return m_platformWindow; } - (NSString *)description @@ -187,16 +204,15 @@ static bool isMouseEvent(NSEvent *ev) - (BOOL)canBecomeKeyWindow { - QCocoaWindow *pw = self.platformWindow; - if (!pw) + if (!m_platformWindow) return NO; - if (pw->shouldRefuseKeyWindowAndFirstResponder()) + if (m_platformWindow->shouldRefuseKeyWindowAndFirstResponder()) return NO; if ([self isKindOfClass:[QNSPanel class]]) { // Only tool or dialog windows should become key: - Qt::WindowType type = pw->window()->type(); + Qt::WindowType type = m_platformWindow->window()->type(); if (type == Qt::Tool || type == Qt::Dialog) return YES; @@ -215,8 +231,7 @@ static bool isMouseEvent(NSEvent *ev) // Windows with a transient parent (such as combobox popup windows) // cannot become the main window: - QCocoaWindow *pw = self.platformWindow; - if (!pw || pw->window()->transientParent()) + if (!m_platformWindow || m_platformWindow->window()->transientParent()) canBecomeMain = NO; return canBecomeMain; @@ -224,12 +239,10 @@ static bool isMouseEvent(NSEvent *ev) - (BOOL)worksWhenModal { - if ([self isKindOfClass:[QNSPanel class]]) { - if (QCocoaWindow *pw = self.platformWindow) { - Qt::WindowType type = pw->window()->type(); - if (type == Qt::Popup || type == Qt::Dialog || type == Qt::Tool) - return YES; - } + if (m_platformWindow && [self isKindOfClass:[QNSPanel class]]) { + Qt::WindowType type = m_platformWindow->window()->type(); + if (type == Qt::Popup || type == Qt::Dialog || type == Qt::Tool) + return YES; } return [super worksWhenModal]; @@ -237,8 +250,7 @@ static bool isMouseEvent(NSEvent *ev) - (BOOL)isOpaque { - return self.platformWindow ? - self.platformWindow->isOpaque() : [super isOpaque]; + return m_platformWindow ? m_platformWindow->isOpaque() : [super isOpaque]; } /*! @@ -266,7 +278,7 @@ static bool isMouseEvent(NSEvent *ev) // e.g. if being retained by other parts of AppKit, or in an auto-release // pool. We guard against this in QNSView as well, as not all callbacks // come via events, but if they do there's no point in propagating them. - if (!self.platformWindow) + if (!m_platformWindow) return; // Prevent deallocation of this NSWindow during event delivery, as we @@ -274,23 +286,22 @@ static bool isMouseEvent(NSEvent *ev) [[self retain] autorelease]; const char *eventType = object_getClassName(theEvent); - if (QWindowSystemInterface::handleNativeEvent(self.platformWindow->window(), + if (QWindowSystemInterface::handleNativeEvent(m_platformWindow->window(), QByteArray::fromRawData(eventType, qstrlen(eventType)), theEvent, nullptr)) { return; } [super sendEvent:theEvent]; - if (!self.platformWindow) + if (!m_platformWindow) return; // Platform window went away while processing event - QCocoaWindow *pw = self.platformWindow; - if (pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) { + if (m_platformWindow->frameStrutEventsEnabled() && isMouseEvent(theEvent)) { NSPoint loc = [theEvent locationInWindow]; NSRect windowFrame = [self convertRectFromScreen:self.frame]; NSRect contentFrame = self.contentView.frame; if (NSMouseInRect(loc, windowFrame, NO) && !NSMouseInRect(loc, contentFrame, NO)) - [qnsview_cast(pw->view()) handleFrameStrutMouseEvent:theEvent]; + [qnsview_cast(m_platformWindow->view()) handleFrameStrutMouseEvent:theEvent]; } } -- cgit v1.2.3 From 8796e3016fae1672e727e2fa4e48f671a0c667ba Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Mon, 11 Feb 2019 12:50:03 +0100 Subject: Android: Add support for getting the UiLanguages From API 24 it is possible to get the UiLanguages correctly from Android so if API 24 or later is available we should use this. If it is not available, then it will fallback to the original behavior of using the system language. Fixes: QTBUG-68019 Change-Id: I4cfbc2b807b361c08da56a74100ba59abf5f2d0f Reviewed-by: Edward Welbourne --- src/plugins/platforms/android/qandroidsystemlocale.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/android/qandroidsystemlocale.cpp b/src/plugins/platforms/android/qandroidsystemlocale.cpp index 7fe36aa9bc..f9d566ff1a 100644 --- a/src/plugins/platforms/android/qandroidsystemlocale.cpp +++ b/src/plugins/platforms/android/qandroidsystemlocale.cpp @@ -40,6 +40,7 @@ #include "qandroidsystemlocale.h" #include "androidjnimain.h" #include +#include #include "qdatetime.h" #include "qstringlist.h" #include "qvariant.h" @@ -162,6 +163,23 @@ QVariant QAndroidSystemLocale::query(QueryType type, QVariant in) const return m_locale.createSeparatedList(in.value()); case LocaleChanged: Q_ASSERT_X(false, Q_FUNC_INFO, "This can't happen."); + case UILanguages: { + if (QtAndroidPrivate::androidSdkVersion() >= 24) { + QJNIObjectPrivate localeListObject = + QJNIObjectPrivate::callStaticObjectMethod("android/os/LocaleList", "getDefault", + "()Landroid/os/LocaleList;"); + if (localeListObject.isValid()) { + QString lang = localeListObject.callObjectMethod("toLanguageTags", + "()Ljava/lang/String;").toString(); + // Some devices return with it enclosed in []'s so check if both exists before + // removing to ensure it is formatted correctly + if (lang.startsWith(QChar('[')) && lang.endsWith(QChar(']'))) + lang = lang.mid(1, lang.length() - 2); + return lang.split(QChar(',')); + } + } + return QVariant(); + } default: break; } -- cgit v1.2.3 From 2fc4635e9889ade1ae79b787cc18aae654e65e3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 19 Feb 2019 11:14:53 +0100 Subject: macOS: Remove special handling for hiding tool windows on application hide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code was needed when we had QCocoaWindow::hide(), that guarded the ordering out by checking the visible state of the NSWindow. We no longer have that method, and setVisible doesn't have the same guard. Added a comment in setVisible to prevent future travelers from adding logic that introduces the same situation. Change-Id: I0514619a303daceb1cd7d334f0de4bfce6c3e96f Reviewed-by: Andy Shaw Reviewed-by: Timur Pocheptsov Reviewed-by: Tor Arne Vestbø --- .../platforms/cocoa/qcocoaapplicationdelegate.mm | 36 ---------------------- src/plugins/platforms/cocoa/qcocoawindow.mm | 5 +++ 2 files changed, 5 insertions(+), 36 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index 9e3c89b6a4..e255719cc1 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -94,7 +94,6 @@ QT_USE_NAMESPACE bool startedQuit; NSObject *reflectionDelegate; bool inLaunch; - QWindowList hiddenWindows; } + (instancetype)sharedDelegate @@ -311,41 +310,6 @@ QT_USE_NAMESPACE return NO; // Someday qApp->quitOnLastWindowClosed(); when QApp and NSApp work closer together. } -- (void)applicationWillHide:(NSNotification *)notification -{ - if (reflectionDelegate - && [reflectionDelegate respondsToSelector:@selector(applicationWillHide:)]) { - [reflectionDelegate applicationWillHide:notification]; - } - - // When the application is hidden Qt will hide the popup windows associated with - // it when it has lost the activation for the application. However, when it gets - // to this point it believes the popup windows to be hidden already due to the - // fact that the application itself is hidden, which will cause a problem when - // the application is made visible again. - const QWindowList topLevelWindows = QGuiApplication::topLevelWindows(); - for (QWindow *topLevelWindow : topLevelWindows) { - if ((topLevelWindow->type() & Qt::Popup) == Qt::Popup && topLevelWindow->isVisible()) { - topLevelWindow->hide(); - - if ((topLevelWindow->type() & Qt::Tool) == Qt::Tool) - hiddenWindows << topLevelWindow; - } - } -} - -- (void)applicationDidUnhide:(NSNotification *)notification -{ - if (reflectionDelegate - && [reflectionDelegate respondsToSelector:@selector(applicationDidUnhide:)]) - [reflectionDelegate applicationDidUnhide:notification]; - - for (QWindow *window : qAsConst(hiddenWindows)) - window->show(); - - hiddenWindows.clear(); -} - - (void)applicationDidBecomeActive:(NSNotification *)notification { if (reflectionDelegate diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index d1047e1965..50adbad518 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -400,6 +400,11 @@ void QCocoaWindow::setVisible(bool visible) } } + // Note: We do not guard the order out by checking NSWindow.visible, as AppKit will + // in some cases, such as when hiding the application, order out and make a window + // invisible, but keep it in a list of "hidden windows", that it then restores again + // when the application is unhidden. We need to call orderOut explicitly, to bring + // the window out of this "hidden list". [m_view.window orderOut:nil]; if (m_view.window == [NSApp keyWindow] && !eventDispatcher()->hasModalSession()) { -- cgit v1.2.3 From 10565c5ef32457443cc950c26e2d8fab6941dac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 13 Feb 2019 15:49:26 +0100 Subject: macOS: Decouple screen property updates from application delegate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I489c37131bf715d45f147964de4a8cd8c02adbcb Fixes: QTBUG-72966 Reviewed-by: Timur Pocheptsov Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm | 12 ------------ src/plugins/platforms/cocoa/qcocoaintegration.h | 1 + src/plugins/platforms/cocoa/qcocoaintegration.mm | 3 +++ 3 files changed, 4 insertions(+), 12 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index e255719cc1..2cf6672da9 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -115,22 +115,10 @@ QT_USE_NAMESPACE self = [super init]; if (self) { inLaunch = true; - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(updateScreens:) - name:NSApplicationDidChangeScreenParametersNotification - object:NSApp]; } return self; } -- (void)updateScreens:(NSNotification *)notification -{ - Q_UNUSED(notification); - if (QCocoaIntegration *ci = QCocoaIntegration::instance()) - ci->updateScreens(); -} - - (void)dealloc { [_dockMenu release]; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index 7de7e073de..04cb4e1226 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -144,6 +144,7 @@ private: #endif QScopedPointer mPlatformTheme; QList mScreens; + QMacScopedObserver m_screensObserver; #ifndef QT_NO_CLIPBOARD QCocoaClipboard *mCocoaClipboard; #endif diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index f6a49dd74f..affbee35b7 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -206,6 +206,9 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) // by explicitly setting the presentation option to the magic 'default value', // which will resolve to an actual value and result in screen invalidation. cocoaApplication.presentationOptions = NSApplicationPresentationDefault; + + m_screensObserver = QMacScopedObserver([NSApplication sharedApplication], + NSApplicationDidChangeScreenParametersNotification, [&]() { updateScreens(); }); updateScreens(); QMacInternalPasteboardMime::initializeMimeTypes(); -- cgit v1.2.3 From ca32a373b31b087b602ca555151e01ed8ea601c1 Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Wed, 20 Feb 2019 11:46:07 +1000 Subject: wasm: fix crash on window close MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I07d6edfbfbf056240262b833ccb708dc15f830a3 Fixes: QTBUG-73678 Task-number: QTBUG-73678 Reviewed-by: Edward Welbourne Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/wasm/qwasmwindow.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp index 25a0190053..39797cb09d 100644 --- a/src/plugins/platforms/wasm/qwasmwindow.cpp +++ b/src/plugins/platforms/wasm/qwasmwindow.cpp @@ -198,8 +198,10 @@ void QWasmWindow::injectMouseReleased(const QPoint &local, const QPoint &global, if (!hasTitleBar() || button != Qt::LeftButton) return; - if (closeButtonRect().contains(global) && m_activeControl == QWasmCompositor::SC_TitleBarCloseButton) + if (closeButtonRect().contains(global) && m_activeControl == QWasmCompositor::SC_TitleBarCloseButton) { window()->close(); + return; + } if (maxButtonRect().contains(global) && m_activeControl == QWasmCompositor::SC_TitleBarMaxButton) { window()->setWindowState(Qt::WindowMaximized); -- cgit v1.2.3 From 1d3a162bfe38f8a3cd576ca17ea7e0f71a55e074 Mon Sep 17 00:00:00 2001 From: Jan Grulich Date: Mon, 18 Feb 2019 13:15:31 +0100 Subject: Properly convert filename to bytearray when sending over portal We should be using QFile::encodeName() to properly convert filenames from string to bytearray. This takes user's locale into account. Change-Id: I090f73f21feb73af166e88baa0e7f4a595cdb25b Reviewed-by: Thiago Macieira --- .../platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp index 5e94d1558e..dcf52921aa 100644 --- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp +++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp @@ -48,6 +48,7 @@ #include #include +#include #include #include #include @@ -181,10 +182,10 @@ void QXdgDesktopPortalFileDialog::openPortal() if (d->saveFile) { if (!d->directory.isEmpty()) - options.insert(QLatin1String("current_folder"), d->directory.toLatin1().append('\0')); + options.insert(QLatin1String("current_folder"), QFile::encodeName(d->directory).append('\0')); if (!d->selectedFiles.isEmpty()) - options.insert(QLatin1String("current_file"), d->selectedFiles.first().toLatin1().append('\0')); + options.insert(QLatin1String("current_file"), QFile::encodeName(d->selectedFiles.first()).append('\0')); } // Insert filters -- cgit v1.2.3 From 3d7616a3160a5ae8bff5f901e4120ee152b43dc1 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Tue, 19 Feb 2019 12:36:07 +0100 Subject: offscreen: remove false condition This plugin does not use any XCB libs. This patch amends 94a4f06fb88ec6c7fa5e31dfd28af4e9b3cdbdd8 and 744be250bf8dbd3e5065662f55a4655c14aa512c Change-Id: I33e2647ace3d9f32a420551b3b198e33a182a06f Reviewed-by: Michal Klocek Reviewed-by: Allan Sandfeld Jensen --- src/plugins/platforms/offscreen/offscreen.pro | 2 +- src/plugins/platforms/offscreen/qoffscreenintegration.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/offscreen/offscreen.pro b/src/plugins/platforms/offscreen/offscreen.pro index a8f230a7b1..f226132592 100644 --- a/src/plugins/platforms/offscreen/offscreen.pro +++ b/src/plugins/platforms/offscreen/offscreen.pro @@ -17,7 +17,7 @@ HEADERS = qoffscreenintegration.h \ OTHER_FILES += offscreen.json -qtConfig(system-xcb):qtConfig(xlib):qtConfig(opengl):!qtConfig(opengles2) { +qtConfig(xlib):qtConfig(opengl):!qtConfig(opengles2) { SOURCES += qoffscreenintegration_x11.cpp HEADERS += qoffscreenintegration_x11.h QT += glx_support-private diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp index efd8fdf3fa..f2933b7179 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp +++ b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp @@ -66,7 +66,7 @@ #include -#if QT_CONFIG(system_xcb) && QT_CONFIG(xlib) && QT_CONFIG(opengl) && !QT_CONFIG(opengles2) +#if QT_CONFIG(xlib) && QT_CONFIG(opengl) && !QT_CONFIG(opengles2) #include "qoffscreenintegration_x11.h" #endif @@ -225,7 +225,7 @@ QPlatformServices *QOffscreenIntegration::services() const QOffscreenIntegration *QOffscreenIntegration::createOffscreenIntegration() { -#if QT_CONFIG(system_xcb) && QT_CONFIG(xlib) && QT_CONFIG(opengl) && !QT_CONFIG(opengles2) +#if QT_CONFIG(xlib) && QT_CONFIG(opengl) && !QT_CONFIG(opengles2) QByteArray glx = qgetenv("QT_QPA_OFFSCREEN_NO_GLX"); if (glx.isEmpty()) return new QOffscreenX11Integration; -- cgit v1.2.3 From b5c16921cca0d5ae966a36cb451ec0b322b967ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Thu, 21 Feb 2019 15:29:48 +0100 Subject: wasm: make setting the cursor shape work again Commit 960af0d64 ported away from EM_ASM but also changed the logic. Set the canvas.style.cursor property, like it originally did. Change-Id: Ie4b23abeae54173894bff1db000a305c459684bb Reviewed-by: Lorn Potter --- src/plugins/platforms/wasm/qwasmcursor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/wasm/qwasmcursor.cpp b/src/plugins/platforms/wasm/qwasmcursor.cpp index 90431ab6a5..744b160dd1 100644 --- a/src/plugins/platforms/wasm/qwasmcursor.cpp +++ b/src/plugins/platforms/wasm/qwasmcursor.cpp @@ -53,7 +53,8 @@ void QWasmCursor::changeCursor(QCursor *windowCursor, QWindow *window) htmlCursorName = "auto"; // Set cursor on the main canvas - emscripten::val::global("window").set("cursor", emscripten::val(htmlCursorName.constData())); + emscripten::val canvasStyle = emscripten::val::module_property("canvas")["style"]; + canvasStyle.set("cursor", emscripten::val(htmlCursorName.constData())); } QByteArray QWasmCursor::cursorShapeToHtml(Qt::CursorShape shape) -- cgit v1.2.3 From 1be070a2bef8b85caa5722ede60092b6038b13e6 Mon Sep 17 00:00:00 2001 From: Mikhail Svetkin Date: Tue, 22 Jan 2019 14:49:34 +0100 Subject: qtlite: Fix build the source code with -no-feature-shortcut Change-Id: If47149466a5da901e3eb6e6f2dcfb0a7816bc60b Reviewed-by: Gatis Paeglis --- src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp | 2 ++ src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h | 2 ++ 2 files changed, 4 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp index f07ca3f098..fb65f6d909 100644 --- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp +++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp @@ -185,11 +185,13 @@ QIconEngine * QXdgDesktopPortalTheme::createIconEngine(const QString &iconName) return d->baseTheme->createIconEngine(iconName); } +#if QT_CONFIG(shortcut) QList QXdgDesktopPortalTheme::keyBindings(QKeySequence::StandardKey key) const { Q_D(const QXdgDesktopPortalTheme); return d->baseTheme->keyBindings(key); } +#endif QString QXdgDesktopPortalTheme::standardButtonText(int button) const { diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h index b72e676419..4c5f474595 100644 --- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h +++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h @@ -76,7 +76,9 @@ public: QIconEngine *createIconEngine(const QString &iconName) const override; +#if QT_CONFIG(shortcut) QList keyBindings(QKeySequence::StandardKey key) const override; +#endif QString standardButtonText(int button) const override; -- cgit v1.2.3 From 85b0ce8ca36d52db71b519ee8d2a1ce369c53a81 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Mon, 25 Feb 2019 13:54:26 +0100 Subject: Fix can not -> cannot Change-Id: Ie9992f67ca59aff662a4be046ace08640e7c2714 Reviewed-by: Paul Wicking --- src/plugins/platforms/cocoa/qcocoaglcontext.mm | 2 +- src/plugins/platforms/cocoa/qcocoawindow.mm | 2 +- src/plugins/platforms/cocoa/qnsview_drawing.mm | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index 93d95b38ea..fe1fc31553 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -86,7 +86,7 @@ QCocoaGLContext::QCocoaGLContext(QOpenGLContext *context) } m_context = nativeHandle.value().context(); if (!m_context) { - qCWarning(lcQpaOpenGLContext, "QCocoaNativeContext's NSOpenGLContext can not be null"); + qCWarning(lcQpaOpenGLContext, "QCocoaNativeContext's NSOpenGLContext cannot be null"); return; } diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index ff2c4de985..298d11fe08 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -619,7 +619,7 @@ void QCocoaWindow::applyWindowState(Qt::WindowStates requestedState) if (nsWindow.styleMask & NSWindowStyleMaskUtilityWindow && newState & (Qt::WindowMinimized | Qt::WindowFullScreen)) { - qWarning() << window()->type() << "windows can not be made" << newState; + qWarning() << window()->type() << "windows cannot be made" << newState; handleWindowStateChanged(HandleUnconditionally); return; } diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm index e9af90a45c..6db5ed8bad 100644 --- a/src/plugins/platforms/cocoa/qnsview_drawing.mm +++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm @@ -106,7 +106,7 @@ "_q_mac_wantsLayer", "QT_MAC_WANTS_LAYER"); if (wantsLayer != -1 && [self layerEnabledByMacOS]) { - qCWarning(lcQpaDrawing) << "Layer-backing can not be explicitly controlled on 10.14 when built against the 10.14 SDK"; + qCWarning(lcQpaDrawing) << "Layer-backing cannot be explicitly controlled on 10.14 when built against the 10.14 SDK"; return true; } -- cgit v1.2.3 From 00cfb4d7801ec9b5d9b070879ef4a962390628b7 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Mon, 18 Feb 2019 16:16:23 +0100 Subject: Windows QPA: Generate proper event when dragging item outside window When an item was dragged outside the window, the mouse release event was not being properly delivered and the item would stick to mouse cursor after moving it back into the window. Fixes: QTBUG-72994 Change-Id: Ibce990390c866e16d58f7d969673dd05e862d97e Reviewed-by: Oliver Wolff Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowsdrag.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 95d1fc8b7d..322865b0f3 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -49,6 +49,7 @@ #include "qwindowswindow.h" #include "qwindowsmousehandler.h" #include "qwindowscursor.h" +#include "qwindowskeymapper.h" #include #include @@ -205,6 +206,9 @@ static inline Qt::MouseButtons toQtMouseButtons(DWORD keyState) return buttons; } +static Qt::KeyboardModifiers lastModifiers = Qt::NoModifier; +static Qt::MouseButtons lastButtons = Qt::NoButton; + /*! \class QWindowsOleDropSource \brief Implementation of IDropSource @@ -403,7 +407,7 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) case DRAGDROP_S_DROP: case DRAGDROP_S_CANCEL: if (!m_windowUnderMouse.isNull() && m_mode != TouchDrag && fEscapePressed == FALSE - && buttons != QGuiApplicationPrivate::mouse_buttons) { + && buttons != lastButtons) { // QTBUG 66447: Synthesize a mouse release to the window under mouse at // start of the DnD operation as Windows does not send any. const QPoint globalPos = QWindowsCursor::mousePosition(); @@ -503,13 +507,14 @@ void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState, QWindowsDrag *windowsDrag = QWindowsDrag::instance(); const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect); - const Qt::KeyboardModifiers keyboardModifiers = toQtKeyboardModifiers(grfKeyState); - const Qt::MouseButtons mouseButtons = toQtMouseButtons(grfKeyState); + + lastModifiers = toQtKeyboardModifiers(grfKeyState); + lastButtons = toQtMouseButtons(grfKeyState); const QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), m_lastPoint, actions, - mouseButtons, keyboardModifiers); + lastButtons, lastModifiers); m_answerRect = response.answerRect(); const Qt::DropAction action = response.acceptedAction(); @@ -521,7 +526,7 @@ void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState, *pdwEffect = m_chosenEffect; qCDebug(lcQpaMime) << __FUNCTION__ << m_window << windowsDrag->dropData() << " supported actions=" << actions - << " mods=" << keyboardModifiers << " mouse=" << mouseButtons + << " mods=" << lastModifiers << " mouse=" << lastButtons << " accepted: " << response.isAccepted() << action << m_answerRect << " effect" << *pdwEffect; } @@ -572,6 +577,9 @@ QWindowsOleDropTarget::DragLeave() qCDebug(lcQpaMime) << __FUNCTION__ << ' ' << m_window; + lastModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); + lastButtons = QWindowsMouseHandler::queryMouseButtons(); + QWindowSystemInterface::handleDrag(m_window, nullptr, QPoint(), Qt::IgnoreAction, Qt::NoButton, Qt::NoModifier); @@ -598,12 +606,15 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, QWindowsDrag *windowsDrag = QWindowsDrag::instance(); + lastModifiers = toQtKeyboardModifiers(grfKeyState); + lastButtons = toQtMouseButtons(grfKeyState); + const QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(), m_lastPoint, translateToQDragDropActions(*pdwEffect), - toQtMouseButtons(grfKeyState), - toQtKeyboardModifiers(grfKeyState)); + lastButtons, + lastModifiers); m_lastKeyState = grfKeyState; -- cgit v1.2.3 From 2f4c6582363d3fd2ece331913c4baedd6dae1061 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 15 Feb 2019 15:04:29 +0100 Subject: Mark QEglFSKmsEglDeviceIntegration::presentBuffer as override clang complains; this makes it build Change-Id: I874c51ea4500edcf3f0bb9c79f0ef0f36309d579 Reviewed-by: Laszlo Agocs --- .../eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h index 0c64d83b12..a5697ec831 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h @@ -62,7 +62,7 @@ public: bool supportsPBuffers() const override; QEglFSWindow *createWindow(QWindow *window) const override; - void presentBuffer(QPlatformSurface *surface); + void presentBuffer(QPlatformSurface *surface) override; EGLDeviceEXT eglDevice() const { return m_egl_device; } -- cgit v1.2.3 From 58cad5caf2064900ae95ef52b521ec8e4b963ff8 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Thu, 21 Feb 2019 23:56:58 +0100 Subject: build compose input context plugin not only for XCB platform It can be used by any platform that uses xkbcommon for keyboard input: wayland, eglfs. Change-Id: Iba7d8989f922063cdceb94c1c4bcd8d8e4ae294e Reviewed-by: Giulio Camuffo --- src/plugins/platforminputcontexts/platforminputcontexts.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforminputcontexts/platforminputcontexts.pro b/src/plugins/platforminputcontexts/platforminputcontexts.pro index ed6b1b8702..68f6792377 100644 --- a/src/plugins/platforminputcontexts/platforminputcontexts.pro +++ b/src/plugins/platforminputcontexts/platforminputcontexts.pro @@ -5,6 +5,6 @@ qtHaveModule(dbus) { !mac:!win32:SUBDIRS += ibus } -qtConfig(xcb): SUBDIRS += compose +qtConfig(xkbcommon): SUBDIRS += compose -- cgit v1.2.3 From 9694d754b815abdf302aba26bd1eada5768adb97 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 25 Feb 2019 15:01:56 +0100 Subject: Haiku: Fix mis-spelled module in .pro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix warning: Project ERROR: Unknown module(s) in QT: eventdistpatcher_support-private Change-Id: Ic74481621c541fc0a13640c5e5cae2df44ffb091 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/haiku/haiku.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/haiku/haiku.pro b/src/plugins/platforms/haiku/haiku.pro index fd1f47b963..e7702361ee 100644 --- a/src/plugins/platforms/haiku/haiku.pro +++ b/src/plugins/platforms/haiku/haiku.pro @@ -1,6 +1,6 @@ TARGET = qhaiku -QT += core-private gui-private eventdistpatcher_support-private +QT += core-private gui-private eventdispatcher_support-private SOURCES = \ main.cpp \ -- cgit v1.2.3 From 96f6cab22cab252cbe7a98bbeadde95497e0bd75 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 26 Feb 2019 10:38:58 +0100 Subject: Blacklist nouveau and llvmpipe for multithreading After removing Mesa drivers from being blank blacklisted, we still need to blacklist nouveau specifically due to their lack of proper locking: https://bugs.freedesktop.org/show_bug.cgi?id=91632 llvmpipe is similarly blacklisted for now, as we lack enough information to know if the underlying issue behind QTCREATORBUG-10666 has been solved. Fixes: QTBUG-73715 Change-Id: I1a60b562cd9db94fa8462b922d6bfeebf0088dc5 Reviewed-by: Laszlo Agocs --- .../xcb/gl_integrations/xcb_glx/qglxintegration.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp index d42a33c22b..476de6d1e5 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -652,6 +652,12 @@ static const char *qglx_threadedgl_blacklist_renderer[] = { 0 }; +static const char *qglx_threadedgl_blacklist_vendor[] = { + "llvmpipe", // QTCREATORBUG-10666 + "nouveau", // https://bugs.freedesktop.org/show_bug.cgi?id=91632 + nullptr +}; + void QGLXContext::queryDummyContext() { if (m_queriedDummyContext) @@ -710,6 +716,18 @@ void QGLXContext::queryDummyContext() } } } + if (const char *vendor = (const char *) glGetString(GL_VENDOR)) { + for (int i = 0; qglx_threadedgl_blacklist_vendor[i]; ++i) { + if (strstr(vendor, qglx_threadedgl_blacklist_vendor[i]) != 0) { + qCDebug(lcQpaGl).nospace() << "Multithreaded OpenGL disabled: " + "blacklisted vendor \"" + << qglx_threadedgl_blacklist_vendor[i] + << "\""; + m_supportsThreading = false; + break; + } + } + } if (glxvendor && m_supportsThreading) { // Blacklist Mesa drivers due to QTCREATORBUG-10875 (crash in creator), -- cgit v1.2.3 From 2c31516a1eb05597a5c7474448b7b413f5dc34c5 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 25 Feb 2019 15:58:22 +0100 Subject: Windows QPA: Fix override cursor when modal window is present Handle WM_SETCURSOR to apply override cursors to window that do not have mouse capture (as is done in Qt 4). Fixes: QTBUG-58590 Change-Id: I7ff6f799da1b8d4b4396c0a6137778a11a192617 Reviewed-by: Oliver Wolff Reviewed-by: Andre de la Rocha --- src/plugins/platforms/windows/qwindowscontext.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 41655dbd57..80517ffe69 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -1099,6 +1099,12 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, return false; case QtWindows::ClipboardEvent: return false; + case QtWindows::CursorEvent: // Sent to windows that do not have capture (see QTBUG-58590). + if (QWindowsCursor::hasOverrideCursor()) { + QWindowsCursor::enforceOverrideCursor(); + return true; + } + break; case QtWindows::UnknownEvent: return false; case QtWindows::AccessibleObjectFromWindowRequest: -- cgit v1.2.3 From ca991ee22d3509f8f54ee26d4c30d45319428c8f Mon Sep 17 00:00:00 2001 From: Elena Zaretskaya Date: Thu, 14 Feb 2019 09:49:33 -0500 Subject: Segfault when the exiting the application under platform eglfs If you run an application under eglfs, it falls with segfault on the exit. For example, examples/gui/analogclock, examples/widgets/widgets/analogclock, examples/opengl/cube, examples/opengl/qopenglwidget, etc. (I have added the function keyPressEvent to exit by qApp->quit(), if needed). It isn't appear in applications using QQuickView or QGLWindow. This is because QCoreApplication destructor, where the variable self = 0 (therefore, qGuiApp = 0), is called before than QOpenGLVertexArrayObject::destroy(), where qGuiApp is accessed (qGuiApp->thread()). Task-number: QTBUG-73824 Change-Id: I1dc55d5e811bfe8a8ea2178752e8771f8644d356 Reviewed-by: Laszlo Agocs --- src/plugins/platforms/eglfs/api/qeglfsscreen.cpp | 3 --- src/plugins/platforms/eglfs/api/qeglfswindow.cpp | 27 +++++++++++++++--------- src/plugins/platforms/eglfs/api/qeglfswindow_p.h | 1 + 3 files changed, 18 insertions(+), 13 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp index 285dbd93d3..11b68c0589 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp @@ -62,9 +62,6 @@ QEglFSScreen::QEglFSScreen(EGLDisplay dpy) QEglFSScreen::~QEglFSScreen() { delete m_cursor; -#ifndef QT_NO_OPENGL - QOpenGLCompositor::destroy(); -#endif } QRect QEglFSScreen::geometry() const diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp index 29cfd4ea79..98e9ee4728 100644 --- a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp @@ -62,6 +62,7 @@ QEglFSWindow::QEglFSWindow(QWindow *w) : QPlatformWindow(w), #ifndef QT_NO_OPENGL m_backingStore(0), + m_rasterCompositingContext(0), #endif m_raster(false), m_winId(0), @@ -144,18 +145,18 @@ void QEglFSWindow::create() #ifndef QT_NO_OPENGL if (isRaster()) { - QOpenGLContext *context = new QOpenGLContext(QGuiApplication::instance()); - context->setShareContext(qt_gl_global_share_context()); - context->setFormat(m_format); - context->setScreen(window()->screen()); - if (Q_UNLIKELY(!context->create())) + m_rasterCompositingContext = new QOpenGLContext; + m_rasterCompositingContext->setShareContext(qt_gl_global_share_context()); + m_rasterCompositingContext->setFormat(m_format); + m_rasterCompositingContext->setScreen(window()->screen()); + if (Q_UNLIKELY(!m_rasterCompositingContext->create())) qFatal("EGLFS: Failed to create compositing context"); - compositor->setTarget(context, window(), screen->rawGeometry()); + compositor->setTarget(m_rasterCompositingContext, window(), screen->rawGeometry()); compositor->setRotation(qEnvironmentVariableIntValue("QT_QPA_EGLFS_ROTATION")); // If there is a "root" window into which raster and QOpenGLWidget content is // composited, all other contexts must share with its context. if (!qt_gl_global_share_context()) { - qt_gl_set_global_share_context(context); + qt_gl_set_global_share_context(m_rasterCompositingContext); // What we set up here is in effect equivalent to the application setting // AA_ShareOpenGLContexts. Set the attribute to be fully consistent. QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); @@ -166,6 +167,10 @@ void QEglFSWindow::create() void QEglFSWindow::destroy() { +#ifndef QT_NO_OPENGL + QOpenGLCompositor::instance()->removeWindow(this); +#endif + QEglFSScreen *screen = this->screen(); if (m_flags.testFlag(HasNativeWindow)) { #ifndef QT_NO_OPENGL @@ -177,12 +182,14 @@ void QEglFSWindow::destroy() screen->setPrimarySurface(EGL_NO_SURFACE); invalidateSurface(); - } - m_flags = 0; #ifndef QT_NO_OPENGL - QOpenGLCompositor::instance()->removeWindow(this); + QOpenGLCompositor::destroy(); + delete m_rasterCompositingContext; #endif + } + + m_flags = 0; } void QEglFSWindow::invalidateSurface() diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow_p.h b/src/plugins/platforms/eglfs/api/qeglfswindow_p.h index c61f04f569..b0091e2a62 100644 --- a/src/plugins/platforms/eglfs/api/qeglfswindow_p.h +++ b/src/plugins/platforms/eglfs/api/qeglfswindow_p.h @@ -116,6 +116,7 @@ public: protected: #ifndef QT_NO_OPENGL QOpenGLCompositorBackingStore *m_backingStore; + QOpenGLContext *m_rasterCompositingContext; #endif bool m_raster; WId m_winId; -- cgit v1.2.3 From f6ce77f3e4dbc67531db7eeaf271c5416b4a4934 Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Tue, 26 Feb 2019 11:58:12 +1000 Subject: wasm: activateWindow when needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-74066 Change-Id: I6babab888de118c8c881fd8a18a90049563d7a23 Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/wasm/qwasmeventtranslator.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp index ddf0ff61e5..334f183703 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp @@ -550,8 +550,11 @@ void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEven switch (eventType) { case EMSCRIPTEN_EVENT_MOUSEDOWN: { - if (window2) + if (window2) { window2->raise(); + if (!window2->isActive()) + window2->requestActivate(); + } pressedButtons.setFlag(button); -- cgit v1.2.3 From 15adc79bbcaa909f43c2da3c61306cc2138567fa Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Fri, 22 Feb 2019 06:50:58 +1000 Subject: wasm: fix clipboard use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change 5242126a inadvertantly removed clipboard functionality Change-Id: Ie15e08470dd51d1c166063bbd443fd04416b2786 Reviewed-by: Morten Johan Sørvig --- .../platforms/wasm/qwasmeventtranslator.cpp | 28 ++++++++++++++++------ 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp index 334f183703..3fc8f600a1 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp @@ -831,16 +831,30 @@ bool QWasmEventTranslator::processKeyboard(int eventType, const EmscriptenKeyboa if (keyType == QEvent::None) return 0; + QFlags mods = translateKeyboardEventModifier(keyEvent); bool accepted = false; - if (keyText.isEmpty()) - keyText = QString(keyEvent->key); - if (keyText.size() > 1) - keyText.clear(); - accepted = QWindowSystemInterface::handleKeyEvent( - 0, keyType, qtKey, modifiers, keyText); + if (keyType == QEvent::KeyPress && + mods.testFlag(Qt::ControlModifier) + && qtKey == Qt::Key_V) { + QWasmIntegration::get()->getWasmClipboard()->readTextFromClipboard(); + } else { + if (keyText.isEmpty()) + keyText = QString(keyEvent->key); + if (keyText.size() > 1) + keyText.clear(); + accepted = QWindowSystemInterface::handleKeyEvent( + 0, keyType, qtKey, modifiers, keyText); + } + if (keyType == QEvent::KeyPress && + mods.testFlag(Qt::ControlModifier) + && qtKey == Qt::Key_C) { + QWasmIntegration::get()->getWasmClipboard()->writeTextToClipboard(); + } + QWasmEventDispatcher::maintainTimers(); - return accepted ? 1 : 0; + + return accepted; } QT_END_NAMESPACE -- cgit v1.2.3 From 8880ef79311d283a1357ca0c14be6e56281ba5f0 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Mon, 11 Feb 2019 19:41:48 +0200 Subject: Terminate Qt gracefully When the application is closed via the task manager on Android then we need to ensure that that the application can close down any running event loops. So we wake up all the event loops and then call quit() directly on the application object to start a graceful termination of the application. In order to aid the graceful termination of Qt then a check is added to ensure that it does not try to create a new surface when the application is suspended. This prevents it from locking while trying to create a new surface when this is not possible. Fixes: QTBUG-70772 Change-Id: I6795b3d280e178d7f1207004a1b965a31a0cc9e9 Reviewed-by: Paul Olav Tvete Reviewed-by: Andy Shaw --- src/plugins/platforms/android/androidjnimain.cpp | 16 +++++++++------- .../platforms/android/qandroidplatformopenglwindow.cpp | 3 ++- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 13d41bea99..74edfd8356 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -560,10 +560,15 @@ static void quitQtAndroidPlugin(JNIEnv *env, jclass /*clazz*/) static void terminateQt(JNIEnv *env, jclass /*clazz*/) { // QAndroidEventDispatcherStopper is stopped when the user uses the task manager to kill the application - if (!QAndroidEventDispatcherStopper::instance()->stopped()) { - sem_wait(&m_terminateSemaphore); - sem_destroy(&m_terminateSemaphore); + if (QAndroidEventDispatcherStopper::instance()->stopped()) { + QAndroidEventDispatcherStopper::instance()->startAll(); + QCoreApplication::quit(); + QAndroidEventDispatcherStopper::instance()->goingToStop(false); } + + sem_wait(&m_terminateSemaphore); + sem_destroy(&m_terminateSemaphore); + env->DeleteGlobalRef(m_applicationClass); env->DeleteGlobalRef(m_classLoaderObject); if (m_resourcesObj) @@ -583,10 +588,7 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/) m_androidPlatformIntegration = nullptr; delete m_androidAssetsFileEngineHandler; m_androidAssetsFileEngineHandler = nullptr; - - if (!QAndroidEventDispatcherStopper::instance()->stopped()) { - sem_post(&m_exitSemaphore); - } + sem_post(&m_exitSemaphore); } static void setSurface(JNIEnv *env, jobject /*thiz*/, jint id, jobject jSurface, jint w, jint h) diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp index 3e1cfe305d..3de5d30623 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp @@ -47,6 +47,7 @@ #include #include +#include #include #include @@ -121,7 +122,7 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect) EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config) { - if (QAndroidEventDispatcherStopper::stopped()) + if (QAndroidEventDispatcherStopper::stopped() || QGuiApplication::applicationState() == Qt::ApplicationSuspended) return m_eglSurface; QMutexLocker lock(&m_surfaceMutex); -- cgit v1.2.3 From a34e81ab8be6445877e040b1afb85deeaa725f86 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Fri, 30 Nov 2018 12:14:51 +0100 Subject: platformsupport/input: add xkbcommon utilities lib xcb/eglfs/wayland - all use XKB keyboard configs and APIs. There is a lot of duplicated and naturally a diverging code. This patch adds a helper library to avoid all the mentioned problems and unify feature set between these platforms. qlibinputkeyboard: Added a fixup for 2803cdf758dbae1006a0c50300af12dac9f71531. From spec: "keysyms, when bound to modifiers, affect the rules [..]", meaning we can't look at keys in isolation, but have to check if bounding exists in the keymap. This is done by using xkb_state_mod_name_is_active() API, but that API has its limitations - https://github.com/xkbcommon/libxkbcommon/issues/88 I will fix this separately in the LTS (5.12) branch. We need to read the modifier state before the key action. This patch fixes a regression introduced by aforementioned patch, which caused modifiers being reported wrongly in QKeyEvent::modifiers(). qtwayland: Moved toKeysym(QKeyEvent) from qtwayland repository into this library. For this and other key mapping functionality wayland was duplicating the key table. All of that will be removed from qtwayland, and calls will be replaced to use this lib. Adjusted toKeysym() to fix QTBUG-71301. Qt keys don't map to ASCII codes, so first we need search in our key table, instead of mapping from unicode. lookupStringNoKeysymTransformations(): fixed off-by-one error, where we were including terminating NUL in QString. Fixes: QTBUG-71301 Task-number: QTBUG-65503 Change-Id: Idfddea5b34ad620235dc08c0b9e5a0669111821a Reviewed-by: Johan Helsing --- src/plugins/platforms/xcb/qxcbkeyboard.cpp | 723 +---------------------------- src/plugins/platforms/xcb/qxcbkeyboard.h | 35 +- src/plugins/platforms/xcb/qxcbxkbcommon.h | 233 ---------- src/plugins/platforms/xcb/xcb_qpa_lib.pro | 4 +- 4 files changed, 31 insertions(+), 964 deletions(-) delete mode 100644 src/plugins/platforms/xcb/qxcbxkbcommon.h (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index c5dc7b21ad..6eb31d67bd 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -39,7 +39,6 @@ #include "qxcbkeyboard.h" #include "qxcbwindow.h" #include "qxcbscreen.h" -#include "qxcbxkbcommon.h" #include #include @@ -49,404 +48,20 @@ #include #include -#include -#include +#if QT_CONFIG(xkb) +#include +#endif #if QT_CONFIG(xcb_xinput) #include #endif -QT_BEGIN_NAMESPACE - -typedef struct xkb2qt -{ - unsigned int xkb; - unsigned int qt; - - constexpr bool operator <=(const xkb2qt &that) const noexcept - { - return xkb <= that.xkb; - } - - constexpr bool operator <(const xkb2qt &that) const noexcept - { - return xkb < that.xkb; - } -} xkb2qt_t; -template -struct Xkb2Qt -{ - using Type = xkb2qt_t; - static constexpr Type data() noexcept { return Type{Xkb, Qt}; } -}; - -static constexpr const auto KeyTbl = qMakeArray( - QSortedData< - // misc keys - - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt<0x1005FF60, Qt::Key_SysReq>, // hardcoded Sun SysReq - Xkb2Qt<0x1007ff00, Qt::Key_SysReq>, // hardcoded X386 SysReq - - // cursor movement - - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - - // modifiers - - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt<0x1000FF74, Qt::Key_Backtab>, // hardcoded HP backtab - Xkb2Qt<0x1005FF10, Qt::Key_F11>, // hardcoded Sun F36 (labeled F11) - Xkb2Qt<0x1005FF11, Qt::Key_F12>, // hardcoded Sun F37 (labeled F12) - - // numeric and function keypad keys - - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - //Xkb2Qt, - //Xkb2Qt, - //Xkb2Qt, - //Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - - // special non-XF86 function keys - - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - - // International input method support keys - - // International & multi-key character composition - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - - // Misc Functions - Xkb2Qt, - Xkb2Qt, - - // Japanese keyboard support - Xkb2Qt, - Xkb2Qt, - //Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - //Xkb2Qt, - //Xkb2Qt, - //Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - - // Korean keyboard support - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - //Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - //Xkb2Qt, - //Xkb2Qt, - //Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - //Xkb2Qt, - Xkb2Qt, - - // dead keys - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - - // Special keys from X.org - This include multimedia keys, - // wireless/bluetooth/uwb keys, special launcher keys, etc. - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, // ### Qt 6: remap properly - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, // ### Qt 6: remap properly - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt, - Xkb2Qt - >::Data{} -); - -// Possible modifier states. -static const Qt::KeyboardModifiers ModsTbl[] = { - Qt::NoModifier, // 0 - Qt::ShiftModifier, // 1 - Qt::ControlModifier, // 2 - Qt::ControlModifier | Qt::ShiftModifier, // 3 - Qt::AltModifier, // 4 - Qt::AltModifier | Qt::ShiftModifier, // 5 - Qt::AltModifier | Qt::ControlModifier, // 6 - Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier, // 7 - Qt::NoModifier // Fall-back to raw Key_*, for non-latin1 kb layouts -}; +QT_BEGIN_NAMESPACE Qt::KeyboardModifiers QXcbKeyboard::translateModifiers(int s) const { - Qt::KeyboardModifiers ret = 0; + Qt::KeyboardModifiers ret = Qt::NoModifier; if (s & XCB_MOD_MASK_SHIFT) ret |= Qt::ShiftModifier; if (s & XCB_MOD_MASK_CONTROL) @@ -473,7 +88,7 @@ static xcb_keysym_t getUnshiftedXKey(xcb_keysym_t unshifted, xcb_keysym_t shifte xcb_keysym_t xlower; xcb_keysym_t xupper; - xkbcommon_XConvertCase(unshifted, &xlower, &xupper); + QXkbCommon::xkbcommon_XConvertCase(unshifted, &xlower, &xupper); if (xlower != xupper // Check if symbol is cased && unshifted == xupper) { // Unshifted must be upper case @@ -805,7 +420,12 @@ void QXcbKeyboard::updateKeymap() updateXKBMods(); - checkForLatinLayout(); + QXkbCommon::verifyHasLatinLayout(m_xkbKeymap.get()); +} + +QList QXcbKeyboard::possibleKeys(const QKeyEvent *event) const +{ + return QXkbCommon::possibleKeys(m_xkbState.get(), event, m_superAsMeta, m_hyperAsMeta); } #if QT_CONFIG(xkb) @@ -918,272 +538,6 @@ void QXcbKeyboard::updateXKBMods() xkb_mods.mod5 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod5"); } -static bool isLatin(xkb_keysym_t sym) -{ - return ((sym >= 'a' && sym <= 'z') || (sym >= 'A' && sym <= 'Z')); -} - -void QXcbKeyboard::checkForLatinLayout() const -{ - const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts(m_xkbKeymap.get()); - const xcb_keycode_t minKeycode = xkb_keymap_min_keycode(m_xkbKeymap.get()); - const xcb_keycode_t maxKeycode = xkb_keymap_max_keycode(m_xkbKeymap.get()); - - const xkb_keysym_t *keysyms = nullptr; - int nrLatinKeys = 0; - for (xkb_layout_index_t layout = 0; layout < layoutCount; ++layout) { - for (xcb_keycode_t code = minKeycode; code < maxKeycode; ++code) { - xkb_keymap_key_get_syms_by_level(m_xkbKeymap.get(), code, layout, 0, &keysyms); - if (keysyms && isLatin(keysyms[0])) - nrLatinKeys++; - if (nrLatinKeys > 10) // arbitrarily chosen threshold - return; - } - } - // This means that lookupLatinKeysym() will not find anything and latin - // key shortcuts might not work. This is a bug in the affected desktop - // environment. Usually can be solved via system settings by adding e.g. 'us' - // layout to the list of seleced layouts, or by using command line, "setxkbmap - // -layout rus,en". The position of latin key based layout in the list of the - // selected layouts is irrelevant. Properly functioning desktop environments - // handle this behind the scenes, even if no latin key based layout has been - // explicitly listed in the selected layouts. - qCWarning(lcQpaKeyboard, "no keyboard layouts with latin keys present"); -} - -xkb_keysym_t QXcbKeyboard::lookupLatinKeysym(xkb_keycode_t keycode) const -{ - xkb_layout_index_t layout; - xkb_keysym_t sym = XKB_KEY_NoSymbol; - const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts_for_key(m_xkbKeymap.get(), keycode); - const xkb_layout_index_t currentLayout = xkb_state_key_get_layout(m_xkbState.get(), keycode); - // Look at user layouts in the order in which they are defined in system - // settings to find a latin keysym. - for (layout = 0; layout < layoutCount; ++layout) { - if (layout == currentLayout) - continue; - const xkb_keysym_t *syms; - xkb_level_index_t level = xkb_state_key_get_level(m_xkbState.get(), keycode, layout); - if (xkb_keymap_key_get_syms_by_level(m_xkbKeymap.get(), keycode, layout, level, &syms) != 1) - continue; - if (isLatin(syms[0])) { - sym = syms[0]; - break; - } - } - - if (sym == XKB_KEY_NoSymbol) - return sym; - - xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_LATCHED); - xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_LOCKED); - - // Check for uniqueness, consider the following setup: - // setxkbmap -layout us,ru,us -variant dvorak,, -option 'grp:ctrl_alt_toggle' (set 'ru' as active). - // In this setup, the user would expect to trigger a ctrl+q shortcut by pressing ctrl+, - // because "US dvorak" is higher up in the layout settings list. This check verifies that an obtained - // 'sym' can not be acquired by any other layout higher up in the user's layout list. If it can be acquired - // then the obtained key is not unique. This prevents ctrl+ from generating a ctrl+q - // shortcut in the above described setup. We don't want ctrl+ and ctrl+ to - // generate the same shortcut event in this case. - const xcb_keycode_t minKeycode = xkb_keymap_min_keycode(m_xkbKeymap.get()); - const xcb_keycode_t maxKeycode = xkb_keymap_max_keycode(m_xkbKeymap.get()); - ScopedXKBState state(xkb_state_new(m_xkbKeymap.get())); - for (xkb_layout_index_t prevLayout = 0; prevLayout < layout; ++prevLayout) { - xkb_state_update_mask(state.get(), 0, latchedMods, lockedMods, 0, 0, prevLayout); - for (xcb_keycode_t code = minKeycode; code < maxKeycode; ++code) { - xkb_keysym_t prevSym = xkb_state_key_get_one_sym(state.get(), code); - if (prevSym == sym) { - sym = XKB_KEY_NoSymbol; - break; - } - } - } - - return sym; -} - -static const char *qtKeyName(int qtKey) -{ - int keyEnumIndex = qt_getQtMetaObject()->indexOfEnumerator("Key"); - QMetaEnum keyEnum = qt_getQtMetaObject()->enumerator(keyEnumIndex); - return keyEnum.valueToKey(qtKey); -} - -QList QXcbKeyboard::possibleKeys(const QKeyEvent *event) const -{ - // turn off the modifier bits which doesn't participate in shortcuts - Qt::KeyboardModifiers notNeeded = Qt::KeypadModifier | Qt::GroupSwitchModifier; - Qt::KeyboardModifiers modifiers = event->modifiers() &= ~notNeeded; - // create a fresh kb state and test against the relevant modifier combinations - struct xkb_state *kb_state = xkb_state_new(m_xkbKeymap.get()); - if (!kb_state) { - qWarning("QXcbKeyboard: failed to compile xkb keymap!"); - return QList(); - } - // get kb state from the master xkb_state and update the temporary kb_state - xkb_layout_index_t lockedLayout = xkb_state_serialize_layout(m_xkbState.get(), XKB_STATE_LAYOUT_LOCKED); - xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_LATCHED); - xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_LOCKED); - xkb_mod_mask_t depressedMods = xkb_state_serialize_mods(m_xkbState.get(), XKB_STATE_MODS_DEPRESSED); - - xkb_state_update_mask(kb_state, depressedMods, latchedMods, lockedMods, 0, 0, lockedLayout); - quint32 keycode = event->nativeScanCode(); - // handle shortcuts for level three and above - xkb_layout_index_t layoutIndex = xkb_state_key_get_layout(kb_state, keycode); - xkb_level_index_t levelIndex = 0; - if (layoutIndex != XKB_LAYOUT_INVALID) { - levelIndex = xkb_state_key_get_level(kb_state, keycode, layoutIndex); - if (levelIndex == XKB_LEVEL_INVALID) - levelIndex = 0; - } - if (levelIndex <= 1) - xkb_state_update_mask(kb_state, 0, latchedMods, lockedMods, 0, 0, lockedLayout); - - xkb_keysym_t sym = xkb_state_key_get_one_sym(kb_state, keycode); - if (sym == XKB_KEY_NoSymbol) { - xkb_state_unref(kb_state); - return QList(); - } - - QList result; - int baseQtKey = keysymToQtKey(sym, modifiers, kb_state, keycode); - if (baseQtKey) - result += (baseQtKey + modifiers); - - xkb_mod_index_t shiftMod = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Shift"); - xkb_mod_index_t altMod = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Alt"); - xkb_mod_index_t controlMod = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Control"); - xkb_mod_index_t metaMod = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Meta"); - - Q_ASSERT(shiftMod < 32); - Q_ASSERT(altMod < 32); - Q_ASSERT(controlMod < 32); - - xkb_mod_mask_t depressed; - int qtKey = 0; - // obtain a list of possible shortcuts for the given key event - for (uint i = 1; i < sizeof(ModsTbl) / sizeof(*ModsTbl) ; ++i) { - Qt::KeyboardModifiers neededMods = ModsTbl[i]; - if ((modifiers & neededMods) == neededMods) { - if (i == 8) { - if (isLatin(baseQtKey)) - continue; - // add a latin key as a fall back key - sym = lookupLatinKeysym(keycode); - } else { - depressed = 0; - if (neededMods & Qt::AltModifier) - depressed |= (1 << altMod); - if (neededMods & Qt::ShiftModifier) - depressed |= (1 << shiftMod); - if (neededMods & Qt::ControlModifier) - depressed |= (1 << controlMod); - if (metaMod < 32 && neededMods & Qt::MetaModifier) - depressed |= (1 << metaMod); - xkb_state_update_mask(kb_state, depressed, latchedMods, lockedMods, 0, 0, lockedLayout); - sym = xkb_state_key_get_one_sym(kb_state, keycode); - } - if (sym == XKB_KEY_NoSymbol) - continue; - - Qt::KeyboardModifiers mods = modifiers & ~neededMods; - qtKey = keysymToQtKey(sym, mods, kb_state, keycode); - if (!qtKey || qtKey == baseQtKey) - continue; - - // catch only more specific shortcuts, i.e. Ctrl+Shift+= also generates Ctrl++ and +, - // but Ctrl++ is more specific than +, so we should skip the last one - bool ambiguous = false; - for (int shortcut : qAsConst(result)) { - if (int(shortcut & ~Qt::KeyboardModifierMask) == qtKey && (shortcut & mods) == mods) { - ambiguous = true; - break; - } - } - if (ambiguous) - continue; - - result += (qtKey + mods); - } - } - xkb_state_unref(kb_state); - return result; -} - -int QXcbKeyboard::keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers modifiers, - struct xkb_state *state, xcb_keycode_t code) const -{ - int qtKey = 0; - - // lookup from direct mapping - if (keysym >= XKB_KEY_F1 && keysym <= XKB_KEY_F35) { - // function keys - qtKey = Qt::Key_F1 + (keysym - XKB_KEY_F1); - } else if (keysym >= XKB_KEY_KP_0 && keysym <= XKB_KEY_KP_9) { - // numeric keypad keys - qtKey = Qt::Key_0 + (keysym - XKB_KEY_KP_0); - } else if (isLatin(keysym)) { - qtKey = xkbcommon_xkb_keysym_to_upper(keysym); - } else { - // check if we have a direct mapping - xkb2qt_t searchKey{keysym, 0}; - auto it = std::lower_bound(KeyTbl.cbegin(), KeyTbl.cend(), searchKey); - if (it != KeyTbl.end() && !(searchKey < *it)) - qtKey = it->qt; - } - - QString text; - bool fromUnicode = qtKey == 0; - if (fromUnicode) { // lookup from unicode - if (modifiers & Qt::ControlModifier) { - // Control modifier changes the text to ASCII control character, therefore we - // can't use this text to map keysym to a qt key. We can use the same keysym - // (it is not affectd by transformation) to obtain untransformed text. For details - // see "Appendix A. Default Symbol Transformations" in the XKB specification. - text = lookupStringNoKeysymTransformations(keysym); - } else { - text = lookupString(state, code); - } - if (!text.isEmpty()) { - if (text.unicode()->isDigit()) { - // Ensures that also non-latin digits are mapped to corresponding qt keys, - // e.g CTRL + ۲ (arabic two), is mapped to CTRL + Qt::Key_2. - qtKey = Qt::Key_0 + text.unicode()->digitValue(); - } else { - qtKey = text.unicode()->toUpper().unicode(); - } - } - } - - if (rmod_masks.meta) { - // translate Super/Hyper keys to Meta if we're using them as the MetaModifier - if (rmod_masks.meta == rmod_masks.super && (qtKey == Qt::Key_Super_L - || qtKey == Qt::Key_Super_R)) { - qtKey = Qt::Key_Meta; - } else if (rmod_masks.meta == rmod_masks.hyper && (qtKey == Qt::Key_Hyper_L - || qtKey == Qt::Key_Hyper_R)) { - qtKey = Qt::Key_Meta; - } - } - - if (Q_UNLIKELY(lcQpaKeyboard().isDebugEnabled())) { - char keysymName[64]; - xkb_keysym_get_name(keysym, keysymName, sizeof(keysymName)); - QString keysymInHex = QString(QStringLiteral("0x%1")).arg(keysym, 0, 16); - if (qtKeyName(qtKey)) { - qCDebug(lcQpaKeyboard).nospace() << "keysym: " << keysymName << "(" - << keysymInHex << ") mapped to Qt::" << qtKeyName(qtKey) << " | text: " << text - << " | qt key: " << qtKey << " mapped from unicode number: " << fromUnicode; - } else { - qCDebug(lcQpaKeyboard).nospace() << "no Qt::Key for keysym: " << keysymName - << "(" << keysymInHex << ") | text: " << text << " | qt key: " << qtKey; - } - } - - return qtKey; -} - QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection) : QXcbObject(connection) { @@ -1514,6 +868,12 @@ void QXcbKeyboard::resolveMaskConflicts() rmod_masks.meta = rmod_masks.hyper; } } + + // translate Super/Hyper keys to Meta if we're using them as the MetaModifier + if (rmod_masks.meta && rmod_masks.meta == rmod_masks.super) + m_superAsMeta = true; + if (rmod_masks.meta && rmod_masks.meta == rmod_masks.hyper) + m_hyperAsMeta = true; } void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, xcb_keycode_t code, @@ -1529,7 +889,7 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, if (type == QEvent::KeyPress) targetWindow->updateNetWmUserTime(time); - ScopedXKBState sendEventState; + QXkbCommon::ScopedXKBState sendEventState; if (fromSendEvent) { // Have a temporary keyboard state filled in from state // this way we allow for synthetic events to have different state @@ -1546,30 +906,13 @@ 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 text = lookupString(xkbState, code); + QString text = QXkbCommon::lookupString(xkbState, code); Qt::KeyboardModifiers modifiers = translateModifiers(state); - if (sym >= XKB_KEY_KP_Space && sym <= XKB_KEY_KP_9) + if (QXkbCommon::isKeypad(sym)) modifiers |= Qt::KeypadModifier; - // Note 1: All standard key sequences on linux (as defined in platform theme) - // that use a latin character also contain a control modifier, which is why - // checking for Qt::ControlModifier is sufficient here. It is possible to - // override QPlatformTheme::keyBindings() and provide custom sequences for - // QKeySequence::StandardKey. Custom sequences probably should respect this - // convention (alternatively, we could test against other modifiers here). - // Note 2: The possibleKeys() shorcut mechanism is not affected by this value - // adjustment and does its own thing. - xcb_keysym_t latinKeysym = XKB_KEY_NoSymbol; - if (modifiers & Qt::ControlModifier) { - // With standard shortcuts we should prefer a latin character, this is - // in checks like "event == QKeySequence::Copy". - if (!isLatin(sym)) - latinKeysym = lookupLatinKeysym(code); - } - - int qtcode = keysymToQtKey(latinKeysym != XKB_KEY_NoSymbol ? latinKeysym : sym, - modifiers, xkbState, code); + int qtcode = QXkbCommon::keysymToQtKey(sym, modifiers, xkbState, code, m_superAsMeta, m_hyperAsMeta); if (type == QEvent::KeyPress) { if (m_isAutoRepeat && m_autoRepeatCode != code) @@ -1611,28 +954,6 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, } } -QString QXcbKeyboard::lookupString(struct xkb_state *state, xcb_keycode_t code) const -{ - QVarLengthArray chars(32); - const int size = xkb_state_key_get_utf8(state, code, chars.data(), chars.size()); - if (Q_UNLIKELY(size + 1 > chars.size())) { // +1 for NUL - chars.resize(size + 1); - xkb_state_key_get_utf8(state, code, chars.data(), chars.size()); - } - return QString::fromUtf8(chars.constData(), size); -} - -QString QXcbKeyboard::lookupStringNoKeysymTransformations(xkb_keysym_t keysym) const -{ - QVarLengthArray chars(32); - const int size = xkb_keysym_to_utf8(keysym, chars.data(), chars.size()); - if (Q_UNLIKELY(size > chars.size())) { - chars.resize(size); - xkb_keysym_to_utf8(keysym, chars.data(), chars.size()); - } - return QString::fromUtf8(chars.constData(), size); -} - static bool fromSendEvent(const void *event) { // From X11 protocol: Every event contains an 8-bit type code. The most diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h index f8490592b7..75071d045f 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.h +++ b/src/plugins/platforms/xcb/qxcbkeyboard.h @@ -50,16 +50,12 @@ #endif #include -#if QT_CONFIG(xkb) -#include -#endif +#include #include QT_BEGIN_NAMESPACE -class QWindow; - class QXcbKeyboard : public QXcbObject { public: @@ -75,7 +71,7 @@ public: Qt::KeyboardModifiers translateModifiers(int s) const; void updateKeymap(xcb_mapping_notify_event_t *event); void updateKeymap(); - QList possibleKeys(const QKeyEvent *e) const; + QList possibleKeys(const QKeyEvent *event) const; // when XKEYBOARD not present on the X server void updateXKBMods(); @@ -96,10 +92,6 @@ protected: quint16 state, xcb_timestamp_t time, bool fromSendEvent); void resolveMaskConflicts(); - QString lookupString(struct xkb_state *state, xcb_keycode_t code) const; - QString lookupStringNoKeysymTransformations(xkb_keysym_t keysym) const; - int keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers modifiers, - struct xkb_state *state, xcb_keycode_t code) const; typedef QMap KeysymModifierMap; struct xkb_keymap *keymapFromCore(const KeysymModifierMap &keysymMods); @@ -111,9 +103,6 @@ protected: void updateVModMapping(); void updateVModToRModMapping(); - xkb_keysym_t lookupLatinKeysym(xkb_keycode_t keycode) const; - void checkForLatinLayout() const; - private: bool m_config = false; bool m_isAutoRepeat = false; @@ -148,22 +137,12 @@ private: int core_device_id; #endif - struct XKBStateDeleter { - void operator()(struct xkb_state *state) const { return xkb_state_unref(state); } - }; - struct XKBKeymapDeleter { - void operator()(struct xkb_keymap *keymap) const { return xkb_keymap_unref(keymap); } - }; - struct XKBContextDeleter { - void operator()(struct xkb_context *context) const { return xkb_context_unref(context); } - }; - using ScopedXKBState = std::unique_ptr; - using ScopedXKBKeymap = std::unique_ptr; - using ScopedXKBContext = std::unique_ptr; + QXkbCommon::ScopedXKBState m_xkbState; + QXkbCommon::ScopedXKBKeymap m_xkbKeymap; + QXkbCommon::ScopedXKBContext m_xkbContext; - ScopedXKBState m_xkbState; - ScopedXKBKeymap m_xkbKeymap; - ScopedXKBContext m_xkbContext; + bool m_superAsMeta = false; + bool m_hyperAsMeta = false; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbxkbcommon.h b/src/plugins/platforms/xcb/qxcbxkbcommon.h deleted file mode 100644 index 422c0c0f12..0000000000 --- a/src/plugins/platforms/xcb/qxcbxkbcommon.h +++ /dev/null @@ -1,233 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2018 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/* XConvertCase was copied from src/3rdparty/xkbcommon/src/keysym.c, - which contains the following license information: - - Copyright 1985, 1987, 1990, 1998 The Open Group - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the names of the authors or their - institutions shall not be used in advertising or otherwise to promote the - sale, use or other dealings in this Software without prior written - authorization from the authors. - - - - Copyright © 2009 Dan Nicholson - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice (including the next - paragraph) shall be included in all copies or substantial portions of the - Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -/* - The following code modifications were applied: - - XConvertCase() was renamed to xkbcommon_XConvertCase(), to not confuse it - with Xlib's XConvertCase(). - - UCSConvertCase() was renamed to qt_UCSConvertCase() and function's body was - replaced to use Qt APIs for doing case conversion, which should give us better - results instead of using the less complete version from keysym.c -*/ - -#include -#include - -QT_BEGIN_NAMESPACE - -static void qt_UCSConvertCase(uint32_t code, xkb_keysym_t *lower, xkb_keysym_t *upper) -{ - *lower = QChar::toLower(code); - *upper = QChar::toUpper(code); -} - -void xkbcommon_XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t *upper) -{ - /* Latin 1 keysym */ - if (sym < 0x100) { - qt_UCSConvertCase(sym, lower, upper); - return; - } - - /* Unicode keysym */ - if ((sym & 0xff000000) == 0x01000000) { - qt_UCSConvertCase((sym & 0x00ffffff), lower, upper); - *upper |= 0x01000000; - *lower |= 0x01000000; - return; - } - - /* Legacy keysym */ - - *lower = sym; - *upper = sym; - - switch (sym >> 8) { - case 1: /* Latin 2 */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym == XKB_KEY_Aogonek) - *lower = XKB_KEY_aogonek; - else if (sym >= XKB_KEY_Lstroke && sym <= XKB_KEY_Sacute) - *lower += (XKB_KEY_lstroke - XKB_KEY_Lstroke); - else if (sym >= XKB_KEY_Scaron && sym <= XKB_KEY_Zacute) - *lower += (XKB_KEY_scaron - XKB_KEY_Scaron); - else if (sym >= XKB_KEY_Zcaron && sym <= XKB_KEY_Zabovedot) - *lower += (XKB_KEY_zcaron - XKB_KEY_Zcaron); - else if (sym == XKB_KEY_aogonek) - *upper = XKB_KEY_Aogonek; - else if (sym >= XKB_KEY_lstroke && sym <= XKB_KEY_sacute) - *upper -= (XKB_KEY_lstroke - XKB_KEY_Lstroke); - else if (sym >= XKB_KEY_scaron && sym <= XKB_KEY_zacute) - *upper -= (XKB_KEY_scaron - XKB_KEY_Scaron); - else if (sym >= XKB_KEY_zcaron && sym <= XKB_KEY_zabovedot) - *upper -= (XKB_KEY_zcaron - XKB_KEY_Zcaron); - else if (sym >= XKB_KEY_Racute && sym <= XKB_KEY_Tcedilla) - *lower += (XKB_KEY_racute - XKB_KEY_Racute); - else if (sym >= XKB_KEY_racute && sym <= XKB_KEY_tcedilla) - *upper -= (XKB_KEY_racute - XKB_KEY_Racute); - break; - case 2: /* Latin 3 */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XKB_KEY_Hstroke && sym <= XKB_KEY_Hcircumflex) - *lower += (XKB_KEY_hstroke - XKB_KEY_Hstroke); - else if (sym >= XKB_KEY_Gbreve && sym <= XKB_KEY_Jcircumflex) - *lower += (XKB_KEY_gbreve - XKB_KEY_Gbreve); - else if (sym >= XKB_KEY_hstroke && sym <= XKB_KEY_hcircumflex) - *upper -= (XKB_KEY_hstroke - XKB_KEY_Hstroke); - else if (sym >= XKB_KEY_gbreve && sym <= XKB_KEY_jcircumflex) - *upper -= (XKB_KEY_gbreve - XKB_KEY_Gbreve); - else if (sym >= XKB_KEY_Cabovedot && sym <= XKB_KEY_Scircumflex) - *lower += (XKB_KEY_cabovedot - XKB_KEY_Cabovedot); - else if (sym >= XKB_KEY_cabovedot && sym <= XKB_KEY_scircumflex) - *upper -= (XKB_KEY_cabovedot - XKB_KEY_Cabovedot); - break; - case 3: /* Latin 4 */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XKB_KEY_Rcedilla && sym <= XKB_KEY_Tslash) - *lower += (XKB_KEY_rcedilla - XKB_KEY_Rcedilla); - else if (sym >= XKB_KEY_rcedilla && sym <= XKB_KEY_tslash) - *upper -= (XKB_KEY_rcedilla - XKB_KEY_Rcedilla); - else if (sym == XKB_KEY_ENG) - *lower = XKB_KEY_eng; - else if (sym == XKB_KEY_eng) - *upper = XKB_KEY_ENG; - else if (sym >= XKB_KEY_Amacron && sym <= XKB_KEY_Umacron) - *lower += (XKB_KEY_amacron - XKB_KEY_Amacron); - else if (sym >= XKB_KEY_amacron && sym <= XKB_KEY_umacron) - *upper -= (XKB_KEY_amacron - XKB_KEY_Amacron); - break; - case 6: /* Cyrillic */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XKB_KEY_Serbian_DJE && sym <= XKB_KEY_Serbian_DZE) - *lower -= (XKB_KEY_Serbian_DJE - XKB_KEY_Serbian_dje); - else if (sym >= XKB_KEY_Serbian_dje && sym <= XKB_KEY_Serbian_dze) - *upper += (XKB_KEY_Serbian_DJE - XKB_KEY_Serbian_dje); - else if (sym >= XKB_KEY_Cyrillic_YU && sym <= XKB_KEY_Cyrillic_HARDSIGN) - *lower -= (XKB_KEY_Cyrillic_YU - XKB_KEY_Cyrillic_yu); - else if (sym >= XKB_KEY_Cyrillic_yu && sym <= XKB_KEY_Cyrillic_hardsign) - *upper += (XKB_KEY_Cyrillic_YU - XKB_KEY_Cyrillic_yu); - break; - case 7: /* Greek */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XKB_KEY_Greek_ALPHAaccent && sym <= XKB_KEY_Greek_OMEGAaccent) - *lower += (XKB_KEY_Greek_alphaaccent - XKB_KEY_Greek_ALPHAaccent); - else if (sym >= XKB_KEY_Greek_alphaaccent && sym <= XKB_KEY_Greek_omegaaccent && - sym != XKB_KEY_Greek_iotaaccentdieresis && - sym != XKB_KEY_Greek_upsilonaccentdieresis) - *upper -= (XKB_KEY_Greek_alphaaccent - XKB_KEY_Greek_ALPHAaccent); - else if (sym >= XKB_KEY_Greek_ALPHA && sym <= XKB_KEY_Greek_OMEGA) - *lower += (XKB_KEY_Greek_alpha - XKB_KEY_Greek_ALPHA); - else if (sym >= XKB_KEY_Greek_alpha && sym <= XKB_KEY_Greek_omega && - sym != XKB_KEY_Greek_finalsmallsigma) - *upper -= (XKB_KEY_Greek_alpha - XKB_KEY_Greek_ALPHA); - break; - case 0x13: /* Latin 9 */ - if (sym == XKB_KEY_OE) - *lower = XKB_KEY_oe; - else if (sym == XKB_KEY_oe) - *upper = XKB_KEY_OE; - else if (sym == XKB_KEY_Ydiaeresis) - *lower = XKB_KEY_ydiaeresis; - break; - } -} - -xkb_keysym_t xkbcommon_xkb_keysym_to_upper(xkb_keysym_t ks) -{ - xkb_keysym_t lower, upper; - - xkbcommon_XConvertCase(ks, &lower, &upper); - - return upper; -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index db3d6629b3..34c671c8c7 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -6,7 +6,8 @@ QT += \ core-private gui-private \ service_support-private theme_support-private \ fontdatabase_support-private \ - edid_support-private + edid_support-private \ + xkbcommon_support-private qtHaveModule(linuxaccessibility_support-private): \ QT += linuxaccessibility_support-private @@ -52,7 +53,6 @@ HEADERS = \ qxcbimage.h \ qxcbxsettings.h \ qxcbsystemtraytracker.h \ - qxcbxkbcommon.h \ qxcbeventqueue.h \ qxcbeventdispatcher.h \ qxcbconnection_basic.h \ -- cgit v1.2.3 From 2065bc070dcd1f88a1f5ba3dd6ef0139a9a441ec Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Fri, 24 Oct 2014 16:31:48 +0200 Subject: platforminputcontexts: use libxkbcommon compose key API Our implementation of compose table parser was added on Mar, 2013. libxkbcommon added APIs for the same thing in Oct, 2014 (ver: 0.5.0). After removing RHEL 6.6 from the list of supported platforms we were able to move the minimal required libxkbcommon version to 0.5.0. Now we can use the xkbcommon-compose APIs on all supported platforms. With this patch we can drop nearly 1000 lines of maintenance burden. This patch fixes user reported issues with our implementation. Known issues: - Testing revealed that xkbcommon-compose does not support non-utf8 locales, and that is by design - https://github.com/xkbcommon/libxkbcommon/issues/76 Our implementation did work for those locales too, but it is unclear if anyone actually uses non-utf8 locales. It is a corner case (work-arounds existing) and likely a configuration error on the users' system. - Looking at the release notes for versions above 0.6.1, only one issue that stands out. Compose input does not work on system with tr_TR.UTF-8 locale, fixed in 0.7.1. Compose input works fine when using e.g. en_US.UTF-8 locale with Turkish keyboard layout. Note: With Qt 5.13 we have removed Ubuntu 16.04 and openSUSE 42.3 from CI: Ubuntu 16.04 - 0.5.0 openSUSE 42.3 - 0.6.1 CI for Qt 5.13 has: Ubuntu 18.04 - 0.8.0 RHEL-7.4 - 0.7.1 openSUSE 15.0 - 0.8.1 Currently the minimal required libxkbcommon version in src/gui/configure.json is set to 0.5.0, but we could bump it to 0.7.1 to avoid known issues from above, but that is a decision for a separate patch. [ChangeLog][plugins][platforminputcontexts] Now using libxkbcommon-compose APIs for compose key input, instead of Qt's own implementation. Fixes: QTBUG-42181 Fixes: QTBUG-53663 Fixes: QTBUG-48657 Change-Id: I79aafe2bc601293844066e7e5f5eddd3719c6bba Reviewed-by: Giulio Camuffo Reviewed-by: Johan Helsing --- .../platforminputcontexts/compose/compose.pro | 8 +- .../compose/generator/qtablegenerator.cpp | 658 --------------------- .../compose/generator/qtablegenerator.h | 145 ----- .../compose/qcomposeplatforminputcontext.cpp | 289 +++------ .../compose/qcomposeplatforminputcontext.h | 33 +- .../compose/qcomposeplatforminputcontextmain.cpp | 4 +- src/plugins/platforms/xcb/qxcbintegration.cpp | 2 + src/plugins/platforms/xcb/qxcbkeyboard.cpp | 6 + src/plugins/platforms/xcb/qxcbkeyboard.h | 1 + 9 files changed, 99 insertions(+), 1047 deletions(-) delete mode 100644 src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp delete mode 100644 src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h (limited to 'src/plugins') diff --git a/src/plugins/platforminputcontexts/compose/compose.pro b/src/plugins/platforminputcontexts/compose/compose.pro index 68bc2c3466..2e2f8600c3 100644 --- a/src/plugins/platforminputcontexts/compose/compose.pro +++ b/src/plugins/platforminputcontexts/compose/compose.pro @@ -3,18 +3,14 @@ TARGET = composeplatforminputcontextplugin QT += core-private gui-private SOURCES += $$PWD/qcomposeplatforminputcontextmain.cpp \ - $$PWD/qcomposeplatforminputcontext.cpp \ - $$PWD/generator/qtablegenerator.cpp \ + $$PWD/qcomposeplatforminputcontext.cpp -HEADERS += $$PWD/qcomposeplatforminputcontext.h \ - $$PWD/generator/qtablegenerator.h \ +HEADERS += $$PWD/qcomposeplatforminputcontext.h QMAKE_USE_PRIVATE += xkbcommon include($$OUT_PWD/../../../gui/qtgui-config.pri) -DEFINES += X11_PREFIX='\\"$$QMAKE_X11_PREFIX\\"' - OTHER_FILES += $$PWD/compose.json PLUGIN_TYPE = platforminputcontexts diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp deleted file mode 100644 index b5a0a5bbeb..0000000000 --- a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp +++ /dev/null @@ -1,658 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qtablegenerator.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include // LC_CTYPE -#include // strchr, strncmp, etc. -#include // strncasecmp -#include // LC_CTYPE - -static const quint32 SupportedCacheVersion = 1; - -/* - In short on how and why the "Compose" file is cached: - - The "Compose" file is large, for en_US it's likely located at: - /usr/share/X11/locale/en_US.UTF-8/Compose - and it has about 6000 string lines. - Q(Gui)Applications parse this file each time they're created. On modern CPUs - it incurs a 4-10 ms startup penalty of each Qt gui app, on older CPUs - - tens of ms or more. - Since the "Compose" file (almost) never changes using a pre-parsed - cache file instead of the "Compose" file is a good idea to improve Qt5 - application startup time by about 5+ ms (or tens of ms on older CPUs). - - The cache file contains the contents of the QComposeCacheFileHeader struct at the - beginning followed by the pre-parsed contents of the "Compose" file. - - struct QComposeCacheFileHeader stores - (a) The cache version - in the unlikely event that some day one might need - to break compatibility. - (b) The (cache) file size. - (c) The lastModified field tracks if anything changed since the last time - the cache file was saved. - If anything did change then we read the compose file and save (cache) it - in binary/pre-parsed format, which should happen extremely rarely if at all. -*/ - -struct QComposeCacheFileHeader -{ - quint32 cacheVersion; - // The compiler will add 4 padding bytes anyway. - // Reserve them explicitly to possibly use in the future. - quint32 reserved; - quint64 fileSize; - qint64 lastModified; -}; - -// localHostName() copied from qtbase/src/corelib/io/qlockfile_unix.cpp -static QByteArray localHostName() -{ - QByteArray hostName(512, Qt::Uninitialized); - if (gethostname(hostName.data(), hostName.size()) == -1) - return QByteArray(); - hostName.truncate(strlen(hostName.data())); - return hostName; -} - -/* - Reads metadata about the Compose file. Later used to determine if the - compose cache should be updated. The fileSize field will be zero on failure. -*/ -static QComposeCacheFileHeader readFileMetadata(const QString &path) -{ - quint64 fileSize = 0; - qint64 lastModified = 0; - const QByteArray pathBytes = QFile::encodeName(path); - QT_STATBUF st; - if (QT_STAT(pathBytes.data(), &st) == 0) { - lastModified = st.st_mtime; - fileSize = st.st_size; - } - QComposeCacheFileHeader info = { 0, 0, fileSize, lastModified }; - return info; -} - -static const QString getCacheFilePath() -{ - QFile machineIdFile("/var/lib/dbus/machine-id"); - QString machineId; - if (machineIdFile.exists()) { - if (machineIdFile.open(QIODevice::ReadOnly)) - machineId = QString::fromLatin1(machineIdFile.readAll().trimmed()); - } - if (machineId.isEmpty()) - machineId = localHostName(); - const QString dirPath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation); - - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) - return dirPath + QLatin1String("/qt_compose_cache_big_endian_") + machineId; - return dirPath + QLatin1String("/qt_compose_cache_little_endian_") + machineId; -} - -// Returns empty vector on failure -static QVector loadCache(const QComposeCacheFileHeader &composeInfo) -{ - QVector vec; - const QString cacheFilePath = getCacheFilePath(); - QFile inputFile(cacheFilePath); - - if (!inputFile.open(QIODevice::ReadOnly)) - return vec; - QComposeCacheFileHeader cacheInfo; - // use a "buffer" variable to make the line after this one more readable. - char *buffer = reinterpret_cast(&cacheInfo); - - if (inputFile.read(buffer, sizeof cacheInfo) != sizeof cacheInfo) - return vec; - if (cacheInfo.fileSize == 0) - return vec; - // using "!=" just in case someone replaced with a backup that existed before - if (cacheInfo.lastModified != composeInfo.lastModified) - return vec; - if (cacheInfo.cacheVersion != SupportedCacheVersion) - return vec; - const QByteArray pathBytes = QFile::encodeName(cacheFilePath); - QT_STATBUF st; - if (QT_STAT(pathBytes.data(), &st) != 0) - return vec; - const off_t fileSize = st.st_size; - if (fileSize > 1024 * 1024 * 5) { - // The cache file size is usually about 150KB, so if its size is over - // say 5MB then somebody inflated the file, abort. - return vec; - } - const off_t bufferSize = fileSize - (sizeof cacheInfo); - const size_t elemSize = sizeof (struct QComposeTableElement); - const int elemCount = bufferSize / elemSize; - const QByteArray ba = inputFile.read(bufferSize); - const char *data = ba.data(); - // Since we know the number of the (many) elements and their size in - // advance calling vector.reserve(..) seems reasonable. - vec.reserve(elemCount); - - for (int i = 0; i < elemCount; i++) { - const QComposeTableElement *elem = - reinterpret_cast(data + (i * elemSize)); - vec.push_back(*elem); - } - return vec; -} - -// Returns true on success, false otherwise. -static bool saveCache(const QComposeCacheFileHeader &info, const QVector &vec) -{ - const QString filePath = getCacheFilePath(); -#if QT_CONFIG(temporaryfile) - QSaveFile outputFile(filePath); -#else - QFile outputFile(filePath); -#endif - if (!outputFile.open(QIODevice::WriteOnly)) - return false; - const char *data = reinterpret_cast(&info); - - if (outputFile.write(data, sizeof info) != sizeof info) - return false; - data = reinterpret_cast(vec.constData()); - const qint64 size = vec.size() * (sizeof (struct QComposeTableElement)); - - if (outputFile.write(data, size) != size) - return false; -#if QT_CONFIG(temporaryfile) - return outputFile.commit(); -#else - return true; -#endif -} - -TableGenerator::TableGenerator() : m_state(NoErrors), - m_systemComposeDir(QString()) -{ - initPossibleLocations(); - QString composeFilePath = findComposeFile(); -#ifdef DEBUG_GENERATOR -// don't use cache when in debug mode. - if (!composeFilePath.isEmpty()) - qDebug() << "Using Compose file from: " << composeFilePath; -#else - QComposeCacheFileHeader fileInfo = readFileMetadata(composeFilePath); - if (fileInfo.fileSize != 0) - m_composeTable = loadCache(fileInfo); -#endif - if (m_composeTable.isEmpty() && cleanState()) { - if (composeFilePath.isEmpty()) { - m_state = MissingComposeFile; - } else { - QFile composeFile(composeFilePath); - composeFile.open(QIODevice::ReadOnly); - parseComposeFile(&composeFile); - orderComposeTable(); - if (m_composeTable.isEmpty()) { - m_state = EmptyTable; -#ifndef DEBUG_GENERATOR -// don't save cache when in debug mode - } else { - fileInfo.cacheVersion = SupportedCacheVersion; - saveCache(fileInfo, m_composeTable); -#endif - } - } - } -#ifdef DEBUG_GENERATOR - printComposeTable(); -#endif -} - -void TableGenerator::initPossibleLocations() -{ - // Compose files come as a part of Xlib library. Xlib doesn't provide - // a mechanism how to retrieve the location of these files reliably, since it was - // never meant for external software to parse compose tables directly. Best we - // can do is to hardcode search paths. To add an extra system path use - // the QTCOMPOSE environment variable - m_possibleLocations.reserve(7); - if (qEnvironmentVariableIsSet("QTCOMPOSE")) - m_possibleLocations.append(QString::fromLocal8Bit(qgetenv("QTCOMPOSE"))); - m_possibleLocations.append(QStringLiteral("/usr/share/X11/locale")); - m_possibleLocations.append(QStringLiteral("/usr/local/share/X11/locale")); - m_possibleLocations.append(QStringLiteral("/usr/lib/X11/locale")); - m_possibleLocations.append(QStringLiteral("/usr/local/lib/X11/locale")); - m_possibleLocations.append(QStringLiteral(X11_PREFIX "/share/X11/locale")); - m_possibleLocations.append(QStringLiteral(X11_PREFIX "/lib/X11/locale")); -} - -QString TableGenerator::findComposeFile() -{ - // check if XCOMPOSEFILE points to a Compose file - if (qEnvironmentVariableIsSet("XCOMPOSEFILE")) { - const QString path = QFile::decodeName(qgetenv("XCOMPOSEFILE")); - if (QFile::exists(path)) - return path; - else - qWarning("$XCOMPOSEFILE doesn't point to an existing file"); - } - - // check if user’s home directory has a file named .XCompose - if (cleanState()) { - QString path = qgetenv("HOME") + QLatin1String("/.XCompose"); - if (QFile::exists(path)) - return path; - } - - // check for the system provided compose files - if (cleanState()) { - QString table = composeTableForLocale(); - if (cleanState()) { - if (table.isEmpty()) - // no table mappings for the system's locale in the compose.dir - m_state = UnsupportedLocale; - else { - QString path = QDir(systemComposeDir()).filePath(table); - if (QFile::exists(path)) - return path; - } - } - } - return QString(); -} - -QString TableGenerator::composeTableForLocale() -{ - QByteArray loc = locale().toUpper().toUtf8(); - QString table = readLocaleMappings(loc); - if (table.isEmpty()) - table = readLocaleMappings(readLocaleAliases(loc)); - return table; -} - -bool TableGenerator::findSystemComposeDir() -{ - bool found = false; - for (int i = 0; i < m_possibleLocations.size(); ++i) { - QString path = m_possibleLocations.at(i); - if (QFile::exists(path + QLatin1String("/compose.dir"))) { - m_systemComposeDir = path; - found = true; - break; - } - } - - if (!found) { - // should we ask to report this in the qt bug tracker? - m_state = UnknownSystemComposeDir; - qWarning("Qt Warning: Could not find a location of the system's Compose files. " - "Consider setting the QTCOMPOSE environment variable."); - } - - return found; -} - -QString TableGenerator::systemComposeDir() -{ - if (m_systemComposeDir.isNull() - && !findSystemComposeDir()) { - return QLatin1String("$QTCOMPOSE"); - } - - return m_systemComposeDir; -} - -QString TableGenerator::locale() const -{ - char *name = setlocale(LC_CTYPE, (char *)0); - return QLatin1String(name); -} - -QString TableGenerator::readLocaleMappings(const QByteArray &locale) -{ - QString file; - if (locale.isEmpty()) - return file; - - QFile mappings(systemComposeDir() + QLatin1String("/compose.dir")); - if (mappings.open(QIODevice::ReadOnly)) { - const int localeNameLength = locale.size(); - const char * const localeData = locale.constData(); - - char l[1024]; - // formating of compose.dir has some inconsistencies - while (!mappings.atEnd()) { - int read = mappings.readLine(l, sizeof(l)); - if (read <= 0) - break; - - char *line = l; - if (*line >= 'a' && *line <= 'z') { - // file name - while (*line && *line != ':' && *line != ' ' && *line != '\t') - ++line; - if (!*line) - continue; - const char * const composeFileNameEnd = line; - *line = '\0'; - ++line; - - // locale name - while (*line && (*line == ' ' || *line == '\t')) - ++line; - const char * const lc = line; - while (*line && *line != ' ' && *line != '\t' && *line != '\n') - ++line; - *line = '\0'; - if (localeNameLength == (line - lc) && !strncasecmp(lc, localeData, line - lc)) { - file = QString::fromLocal8Bit(l, composeFileNameEnd - l); - break; - } - } - } - mappings.close(); - } - return file; -} - -QByteArray TableGenerator::readLocaleAliases(const QByteArray &locale) -{ - QFile aliases(systemComposeDir() + QLatin1String("/locale.alias")); - QByteArray fullLocaleName; - if (aliases.open(QIODevice::ReadOnly)) { - while (!aliases.atEnd()) { - char l[1024]; - int read = aliases.readLine(l, sizeof(l)); - char *line = l; - if (read && ((*line >= 'a' && *line <= 'z') || - (*line >= 'A' && *line <= 'Z'))) { - const char *alias = line; - while (*line && *line != ':' && *line != ' ' && *line != '\t') - ++line; - if (!*line) - continue; - *line = 0; - if (locale.size() == (line - alias) - && !strncasecmp(alias, locale.constData(), line - alias)) { - // found a match for alias, read the real locale name - ++line; - while (*line && (*line == ' ' || *line == '\t')) - ++line; - const char *fullName = line; - while (*line && *line != ' ' && *line != '\t' && *line != '\n') - ++line; - *line = 0; - fullLocaleName = fullName; -#ifdef DEBUG_GENERATOR - qDebug() << "Alias for: " << alias << "is: " << fullLocaleName; - break; -#endif - } - } - } - aliases.close(); - } - return fullLocaleName; -} - -bool TableGenerator::processFile(const QString &composeFileName) -{ - QFile composeFile(composeFileName); - if (composeFile.open(QIODevice::ReadOnly)) { - parseComposeFile(&composeFile); - return true; - } - qWarning() << QString(QLatin1String("Qt Warning: Compose file: \"%1\" can't be found")) - .arg(composeFile.fileName()); - return false; -} - -TableGenerator::~TableGenerator() -{ -} - -QVector TableGenerator::composeTable() const -{ - return m_composeTable; -} - -void TableGenerator::parseComposeFile(QFile *composeFile) -{ -#ifdef DEBUG_GENERATOR - qDebug() << "TableGenerator::parseComposeFile: " << composeFile->fileName(); -#endif - - char line[1024]; - while (!composeFile->atEnd()) { - composeFile->readLine(line, sizeof(line)); - if (*line == '<') - parseKeySequence(line); - else if (!strncmp(line, "include", 7)) - parseIncludeInstruction(QString::fromLocal8Bit(line)); - } - - composeFile->close(); -} - -void TableGenerator::parseIncludeInstruction(QString line) -{ - // Parse something that looks like: - // include "/usr/share/X11/locale/en_US.UTF-8/Compose" - QString quote = QStringLiteral("\""); - line.remove(0, line.indexOf(quote) + 1); - line.chop(line.length() - line.indexOf(quote)); - - // expand substitutions if present - line.replace(QLatin1String("%H"), QString(qgetenv("HOME"))); - line.replace(QLatin1String("%L"), systemComposeDir() + QLatin1Char('/') + composeTableForLocale()); - line.replace(QLatin1String("%S"), systemComposeDir()); - - processFile(line); -} - -ushort TableGenerator::keysymToUtf8(quint32 sym) -{ - QByteArray chars; - int bytes; - chars.resize(8); - bytes = xkb_keysym_to_utf8(sym, chars.data(), chars.size()); - if (bytes == -1) - qWarning("TableGenerator::keysymToUtf8 - buffer too small"); - - chars.resize(bytes-1); - -#ifdef DEBUG_GENERATOR - QTextCodec *codec = QTextCodec::codecForLocale(); - qDebug() << QString("keysym - 0x%1 : utf8 - %2").arg(QString::number(sym, 16)) - .arg(codec->toUnicode(chars)); -#endif - return QString::fromUtf8(chars).at(0).unicode(); -} - -static inline int fromBase8(const char *s, const char *end) -{ - int result = 0; - while (*s && s != end) { - if (*s < '0' || *s > '7') - return 0; - result *= 8; - result += *s - '0'; - ++s; - } - return result; -} - -static inline int fromBase16(const char *s, const char *end) -{ - int result = 0; - while (*s && s != end) { - result *= 16; - if (*s >= '0' && *s <= '9') - result += *s - '0'; - else if (*s >= 'a' && *s <= 'f') - result += *s - 'a' + 10; - else if (*s >= 'A' && *s <= 'F') - result += *s - 'A' + 10; - else - return 0; - ++s; - } - return result; -} - -void TableGenerator::parseKeySequence(char *line) -{ - // we are interested in the lines with the following format: - // : "♬" U266c # BEAMED SIXTEENTH NOTE - char *keysEnd = strchr(line, ':'); - if (!keysEnd) - return; - - QComposeTableElement elem; - // find the composed value - strings may be direct text encoded in the locale - // for which the compose file is to be used, or an escaped octal or hexadecimal - // character code. Octal codes are specified as "\123" and hexadecimal codes as "\0x123a". - char *composeValue = strchr(keysEnd, '"'); - if (!composeValue) - return; - ++composeValue; - - char *composeValueEnd = strchr(composeValue, '"'); - if (!composeValueEnd) - return; - - // if composed value is a quotation mark adjust the end pointer - if (composeValueEnd[1] == '"') - ++composeValueEnd; - - if (*composeValue == '\\' && composeValue[1] >= '0' && composeValue[1] <= '9') { - // handle octal and hex code values - char detectBase = composeValue[2]; - if (detectBase == 'x') { - // hexadecimal character code - elem.value = keysymToUtf8(fromBase16(composeValue + 3, composeValueEnd)); - } else { - // octal character code - elem.value = keysymToUtf8(fromBase8(composeValue + 1, composeValueEnd)); - } - } else { - // handle direct text encoded in the locale - if (*composeValue == '\\') - ++composeValue; - elem.value = QString::fromLocal8Bit(composeValue, composeValueEnd - composeValue).at(0).unicode(); - ++composeValue; - } - -#ifdef DEBUG_GENERATOR - // find the comment - elem.comment = QString::fromLocal8Bit(composeValueEnd + 1).trimmed(); -#endif - - // find the key sequence and convert to X11 keysym - char *k = line; - const char *kend = keysEnd; - - for (int i = 0; i < QT_KEYSEQUENCE_MAX_LEN; i++) { - // find the next pair of angle brackets and get the contents within - while (k < kend && *k != '<') - ++k; - char *sym = ++k; - while (k < kend && *k != '>') - ++k; - *k = '\0'; - if (k < kend) { - elem.keys[i] = xkb_keysym_from_name(sym, (xkb_keysym_flags)0); - if (elem.keys[i] == XKB_KEY_NoSymbol) { - if (!strcmp(sym, "dead_inverted_breve")) - elem.keys[i] = XKB_KEY_dead_invertedbreve; - else if (!strcmp(sym, "dead_double_grave")) - elem.keys[i] = XKB_KEY_dead_doublegrave; -#ifdef DEBUG_GENERATOR - else - qWarning() << QString("Qt Warning - invalid keysym: %1").arg(sym); -#endif - } - } else { - elem.keys[i] = 0; - } - } - m_composeTable.append(elem); -} - -void TableGenerator::printComposeTable() const -{ -#ifdef DEBUG_GENERATOR -# ifndef QT_NO_DEBUG_STREAM - if (m_composeTable.isEmpty()) - return; - - QDebug ds = qDebug() << "output:\n"; - ds.nospace(); - const int tableSize = m_composeTable.size(); - for (int i = 0; i < tableSize; ++i) { - const QComposeTableElement &elem = m_composeTable.at(i); - ds << "{ {"; - for (int j = 0; j < QT_KEYSEQUENCE_MAX_LEN; j++) { - ds << hex << showbase << elem.keys[j] << ", "; - } - ds << "}, " << hex << showbase << elem.value << ", \"\" }, // " << elem.comment << " \n"; - } -# endif -#endif -} - -void TableGenerator::orderComposeTable() -{ - // Stable-sorting to ensure that the item that appeared before the other in the - // original container will still appear first after the sort. This property is - // needed to handle the cases when user re-defines already defined key sequence - std::stable_sort(m_composeTable.begin(), m_composeTable.end(), ByKeys()); -} - diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h deleted file mode 100644 index 4f58358f4e..0000000000 --- a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h +++ /dev/null @@ -1,145 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTABLEGENERATOR_H -#define QTABLEGENERATOR_H - -#include -#include -#include -#include - -#include - -static Q_CONSTEXPR int QT_KEYSEQUENCE_MAX_LEN = 6; - -//#define DEBUG_GENERATOR - -/* Whenever QComposeTableElement gets modified supportedCacheVersion - from qtablegenerator.cpp must be bumped. */ -struct QComposeTableElement { - uint keys[QT_KEYSEQUENCE_MAX_LEN]; - uint value; -#ifdef DEBUG_GENERATOR - QString comment; -#endif -}; - -#ifndef DEBUG_GENERATOR -QT_BEGIN_NAMESPACE -Q_DECLARE_TYPEINFO(QComposeTableElement, Q_PRIMITIVE_TYPE); -QT_END_NAMESPACE -#endif - -struct ByKeys -{ - using uint_array = uint[QT_KEYSEQUENCE_MAX_LEN]; - using result_type = bool; - - bool operator()(const uint_array &lhs, const uint_array &rhs) const Q_DECL_NOTHROW - { - return std::lexicographical_compare(lhs, lhs + QT_KEYSEQUENCE_MAX_LEN, - rhs, rhs + QT_KEYSEQUENCE_MAX_LEN); - } - - bool operator()(const uint_array &lhs, const QComposeTableElement &rhs) const Q_DECL_NOTHROW - { - return operator()(lhs, rhs.keys); - } - - bool operator()(const QComposeTableElement &lhs, const uint_array &rhs) const Q_DECL_NOTHROW - { - return operator()(lhs.keys, rhs); - } - - bool operator()(const QComposeTableElement &lhs, const QComposeTableElement &rhs) const Q_DECL_NOTHROW - { - return operator()(lhs.keys, rhs.keys); - } -}; - -class TableGenerator -{ - -public: - enum TableState - { - UnsupportedLocale, - EmptyTable, - UnknownSystemComposeDir, - MissingComposeFile, - NoErrors - }; - - TableGenerator(); - ~TableGenerator(); - - void parseComposeFile(QFile *composeFile); - void printComposeTable() const; - void orderComposeTable(); - - QVector composeTable() const; - TableState tableState() const { return m_state; } - -protected: - bool processFile(const QString &composeFileName); - void parseKeySequence(char *line); - void parseIncludeInstruction(QString line); - - QString findComposeFile(); - bool findSystemComposeDir(); - QString systemComposeDir(); - QString composeTableForLocale(); - - ushort keysymToUtf8(quint32 sym); - - QString readLocaleMappings(const QByteArray &locale); - QByteArray readLocaleAliases(const QByteArray &locale); - void initPossibleLocations(); - bool cleanState() const { return m_state == NoErrors; } - QString locale() const; - -private: - QVector m_composeTable; - TableState m_state; - QString m_systemComposeDir; - QList m_possibleLocations; -}; - -#endif // QTABLEGENERATOR_H diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp index 81a730232c..6b9687c22d 100644 --- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -36,131 +36,100 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ - #include "qcomposeplatforminputcontext.h" #include #include -#include -#include +#include QT_BEGIN_NAMESPACE -//#define DEBUG_COMPOSING +Q_LOGGING_CATEGORY(lcXkbCompose, "qt.xkb.compose") -static const int ignoreKeys[] = { - Qt::Key_Shift, - Qt::Key_Control, - Qt::Key_Meta, - Qt::Key_Alt, - Qt::Key_CapsLock, - Qt::Key_Super_L, - Qt::Key_Super_R, - Qt::Key_Hyper_L, - Qt::Key_Hyper_R, - Qt::Key_Mode_switch -}; +QComposeInputContext::QComposeInputContext() +{ + setObjectName(QStringLiteral("QComposeInputContext")); + qCDebug(lcXkbCompose, "using xkb compose input context"); +} -static const int composingKeys[] = { - Qt::Key_Multi_key, - Qt::Key_Dead_Grave, - Qt::Key_Dead_Acute, - Qt::Key_Dead_Circumflex, - Qt::Key_Dead_Tilde, - Qt::Key_Dead_Macron, - Qt::Key_Dead_Breve, - Qt::Key_Dead_Abovedot, - Qt::Key_Dead_Diaeresis, - Qt::Key_Dead_Abovering, - Qt::Key_Dead_Doubleacute, - Qt::Key_Dead_Caron, - Qt::Key_Dead_Cedilla, - Qt::Key_Dead_Ogonek, - Qt::Key_Dead_Iota, - Qt::Key_Dead_Voiced_Sound, - Qt::Key_Dead_Semivoiced_Sound, - Qt::Key_Dead_Belowdot, - Qt::Key_Dead_Hook, - Qt::Key_Dead_Horn, - Qt::Key_Dead_Stroke, - Qt::Key_Dead_Abovecomma, - Qt::Key_Dead_Abovereversedcomma, - Qt::Key_Dead_Doublegrave, - Qt::Key_Dead_Belowring, - Qt::Key_Dead_Belowmacron, - Qt::Key_Dead_Belowcircumflex, - Qt::Key_Dead_Belowtilde, - Qt::Key_Dead_Belowbreve, - Qt::Key_Dead_Belowdiaeresis, - Qt::Key_Dead_Invertedbreve, - Qt::Key_Dead_Belowcomma, - Qt::Key_Dead_Currency, - Qt::Key_Dead_a, - Qt::Key_Dead_A, - Qt::Key_Dead_e, - Qt::Key_Dead_E, - Qt::Key_Dead_i, - Qt::Key_Dead_I, - Qt::Key_Dead_o, - Qt::Key_Dead_O, - Qt::Key_Dead_u, - Qt::Key_Dead_U, - Qt::Key_Dead_Small_Schwa, - Qt::Key_Dead_Capital_Schwa, - Qt::Key_Dead_Greek, - Qt::Key_Dead_Lowline, - Qt::Key_Dead_Aboveverticalline, - Qt::Key_Dead_Belowverticalline, - Qt::Key_Dead_Longsolidusoverlay -}; +QComposeInputContext::~QComposeInputContext() +{ + xkb_compose_state_unref(m_composeState); + xkb_compose_table_unref(m_composeTable); +} -QComposeInputContext::QComposeInputContext() - : m_tableState(TableGenerator::EmptyTable) - , m_compositionTableInitialized(false) +void QComposeInputContext::ensureInitialized() { - clearComposeBuffer(); + if (m_initialized) + return; + + if (!m_XkbContext) { + qCWarning(lcXkbCompose) << "error: xkb context has not been set on" << metaObject()->className(); + return; + } + + m_initialized = true; + const char *const locale = setlocale(LC_CTYPE, ""); + qCDebug(lcXkbCompose) << "detected locale (LC_CTYPE):" << locale; + + m_composeTable = xkb_compose_table_new_from_locale(m_XkbContext, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); + if (m_composeTable) + m_composeState = xkb_compose_state_new(m_composeTable, XKB_COMPOSE_STATE_NO_FLAGS); + + if (!m_composeTable) { + qCWarning(lcXkbCompose, "failed to create compose table"); + return; + } + if (!m_composeState) { + qCWarning(lcXkbCompose, "failed to create compose state"); + return; + } } bool QComposeInputContext::filterEvent(const QEvent *event) { - const QKeyEvent *keyEvent = (const QKeyEvent *)event; - // should pass only the key presses - if (keyEvent->type() != QEvent::KeyPress) { + auto keyEvent = static_cast(event); + if (keyEvent->type() != QEvent::KeyPress) return false; - } - // if there were errors when generating the compose table input - // context should not try to filter anything, simply return false - if (m_compositionTableInitialized && (m_tableState & TableGenerator::NoErrors) != TableGenerator::NoErrors) + if (!inputMethodAccepted()) return false; - int keyval = keyEvent->key(); - int keysym = 0; + // lazy initialization - we don't want to do this on an app startup + ensureInitialized(); - if (ignoreKey(keyval)) + if (!m_composeTable || !m_composeState) return false; - if (!composeKey(keyval) && keyEvent->text().isEmpty()) - return false; + xkb_compose_state_feed(m_composeState, keyEvent->nativeVirtualKey()); - keysym = keyEvent->nativeVirtualKey(); + switch (xkb_compose_state_get_status(m_composeState)) { + case XKB_COMPOSE_COMPOSING: + return true; + case XKB_COMPOSE_CANCELLED: + reset(); + return false; + case XKB_COMPOSE_COMPOSED: + { + const int size = xkb_compose_state_get_utf8(m_composeState, nullptr, 0); + QVarLengthArray buffer(size + 1); + xkb_compose_state_get_utf8(m_composeState, buffer.data(), buffer.size()); + QString composedText = QString::fromUtf8(buffer.constData()); - int nCompose = 0; - while (nCompose < QT_KEYSEQUENCE_MAX_LEN && m_composeBuffer[nCompose] != 0) - nCompose++; + QInputMethodEvent event; + event.setCommitString(composedText); + QCoreApplication::sendEvent(m_focusObject, &event); - if (nCompose == QT_KEYSEQUENCE_MAX_LEN) { reset(); - nCompose = 0; - } - - m_composeBuffer[nCompose] = keysym; - // check sequence - if (checkComposeTable()) return true; - - return false; + } + case XKB_COMPOSE_NOTHING: + return false; + default: + Q_UNREACHABLE(); + return false; + } } bool QComposeInputContext::isValid() const @@ -175,7 +144,8 @@ void QComposeInputContext::setFocusObject(QObject *object) void QComposeInputContext::reset() { - clearComposeBuffer(); + if (m_composeState) + xkb_compose_state_reset(m_composeState); } void QComposeInputContext::update(Qt::InputMethodQueries q) @@ -183,125 +153,4 @@ void QComposeInputContext::update(Qt::InputMethodQueries q) QPlatformInputContext::update(q); } -static bool isDuplicate(const QComposeTableElement &lhs, const QComposeTableElement &rhs) -{ - return std::equal(lhs.keys, lhs.keys + QT_KEYSEQUENCE_MAX_LEN, - QT_MAKE_CHECKED_ARRAY_ITERATOR(rhs.keys, QT_KEYSEQUENCE_MAX_LEN)); -} - -bool QComposeInputContext::checkComposeTable() -{ - if (!m_compositionTableInitialized) { - TableGenerator reader; - m_tableState = reader.tableState(); - - m_compositionTableInitialized = true; - if ((m_tableState & TableGenerator::NoErrors) == TableGenerator::NoErrors) { - m_composeTable = reader.composeTable(); - } else { -#ifdef DEBUG_COMPOSING - qDebug( "### FAILED_PARSING ###" ); -#endif - // if we have errors, don' try to look things up anyways. - reset(); - return false; - } - } - Q_ASSERT(!m_composeTable.isEmpty()); - QVector::const_iterator it = - std::lower_bound(m_composeTable.constBegin(), m_composeTable.constEnd(), m_composeBuffer, ByKeys()); - - // prevent dereferencing an 'end' iterator, which would result in a crash - if (it == m_composeTable.constEnd()) - it -= 1; - - QComposeTableElement elem = *it; - // would be nicer if qLowerBound had API that tells if the item was actually found - if (m_composeBuffer[0] != elem.keys[0]) { -#ifdef DEBUG_COMPOSING - qDebug( "### no match ###" ); -#endif - reset(); - return false; - } - // check if compose buffer is matched - for (int i=0; i < QT_KEYSEQUENCE_MAX_LEN; i++) { - - // check if partial match - if (m_composeBuffer[i] == 0 && elem.keys[i]) { -#ifdef DEBUG_COMPOSING - qDebug("### partial match ###"); -#endif - return true; - } - - if (m_composeBuffer[i] != elem.keys[i]) { -#ifdef DEBUG_COMPOSING - qDebug("### different entry ###"); -#endif - reset(); - return i != 0; - } - } -#ifdef DEBUG_COMPOSING - qDebug("### match exactly ###"); -#endif - - // check if the key sequence is overwriten - see the comment in - // TableGenerator::orderComposeTable() - int next = 1; - do { - // if we are at the end of the table, then we have nothing to do here - if (it + next != m_composeTable.constEnd()) { - QComposeTableElement nextElem = *(it + next); - if (isDuplicate(elem, nextElem)) { - elem = nextElem; - next++; - continue; - } else { - break; - } - } - break; - } while (true); - - commitText(elem.value); - reset(); - - return true; -} - -void QComposeInputContext::commitText(uint character) const -{ - QInputMethodEvent event; - event.setCommitString(QChar(character)); - QCoreApplication::sendEvent(m_focusObject, &event); -} - -bool QComposeInputContext::ignoreKey(int keyval) const -{ - for (uint i = 0; i < (sizeof(ignoreKeys) / sizeof(ignoreKeys[0])); i++) - if (keyval == ignoreKeys[i]) - return true; - - return false; -} - -bool QComposeInputContext::composeKey(int keyval) const -{ - for (uint i = 0; i < (sizeof(composingKeys) / sizeof(composingKeys[0])); i++) - if (keyval == composingKeys[i]) - return true; - - return false; -} - -void QComposeInputContext::clearComposeBuffer() -{ - for (uint i=0; i < (sizeof(m_composeBuffer) / sizeof(int)); i++) - m_composeBuffer[i] = 0; -} - -QComposeInputContext::~QComposeInputContext() {} - QT_END_NAMESPACE diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h index 4830959665..b1de1b1094 100644 --- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h +++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -36,24 +36,24 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ - #ifndef QCOMPOSEPLATFORMINPUTCONTEXT_H #define QCOMPOSEPLATFORMINPUTCONTEXT_H -#include +#include -#include +#include -#include "generator/qtablegenerator.h" +#include QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(lcXkbCompose) + class QEvent; class QComposeInputContext : public QPlatformInputContext { Q_OBJECT - public: QComposeInputContext(); ~QComposeInputContext(); @@ -62,21 +62,22 @@ public: void setFocusObject(QObject *object) override; void reset() override; void update(Qt::InputMethodQueries) override; + bool filterEvent(const QEvent *event) override; + // This invokable is called from QXkbCommon::setXkbContext(). + Q_INVOKABLE void setXkbContext(struct xkb_context *context) { m_XkbContext = context; } + protected: - void clearComposeBuffer(); - bool ignoreKey(int keyval) const; - bool composeKey(int keyval) const; - bool checkComposeTable(); - void commitText(uint character) const; + void ensureInitialized(); private: - QObject *m_focusObject; - QVector m_composeTable; - uint m_composeBuffer[QT_KEYSEQUENCE_MAX_LEN]; - TableGenerator::TableState m_tableState; - bool m_compositionTableInitialized; + bool m_initialized = false; + xkb_context *m_context = nullptr; + xkb_compose_table *m_composeTable = nullptr; + xkb_compose_state *m_composeState = nullptr; + QObject *m_focusObject = nullptr; + struct xkb_context *m_XkbContext = nullptr; }; QT_END_NAMESPACE diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp index 6b33df65b9..d062d4fd6a 100644 --- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp +++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -61,7 +61,7 @@ QComposeInputContext *QComposePlatformInputContextPlugin::create(const QString & if (system.compare(system, QLatin1String("compose"), Qt::CaseInsensitive) == 0 || system.compare(system, QLatin1String("xim"), Qt::CaseInsensitive) == 0) return new QComposeInputContext; - return 0; + return nullptr; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index ed9e87a036..a70c7db923 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -357,6 +357,8 @@ void QXcbIntegration::initialize() m_inputContext.reset(QPlatformInputContextFactory::create(icStr)); if (!m_inputContext && icStr != defaultInputContext && icStr != QLatin1String("none")) m_inputContext.reset(QPlatformInputContextFactory::create(defaultInputContext)); + + defaultConnection()->keyboard()->initialize(); } void QXcbIntegration::moveToScreen(QWindow *window, int screen) diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 6eb31d67bd..d0e02ecdd1 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -565,6 +565,12 @@ QXcbKeyboard::~QXcbKeyboard() xcb_key_symbols_free(m_key_symbols); } +void QXcbKeyboard::initialize() +{ + auto inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext(); + QXkbCommon::setXkbContext(inputContext, m_xkbContext.get()); +} + void QXcbKeyboard::selectEvents() { #if QT_CONFIG(xkb) diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h index 75071d045f..e35c82ad24 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.h +++ b/src/plugins/platforms/xcb/qxcbkeyboard.h @@ -63,6 +63,7 @@ public: ~QXcbKeyboard(); + void initialize(); void selectEvents(); void handleKeyPressEvent(const xcb_key_press_event_t *event); -- cgit v1.2.3 From a74b2b5f152ae81da6c0906afc63b8647c3a048a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 27 Feb 2019 11:30:31 +0100 Subject: macOS: Initialize QNSView mouse related members with other mouse logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I4ff67028823d62ed67bf4303a58bee127bd76501 Reviewed-by: Timur Pocheptsov Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qnsview.mm | 9 --------- src/plugins/platforms/cocoa/qnsview_mouse.mm | 13 +++++++++++++ 2 files changed, 13 insertions(+), 9 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 17063f6e92..5309449dce 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -137,22 +137,13 @@ { if ((self = [super initWithFrame:NSZeroRect])) { m_platformWindow = platformWindow; - m_buttons = Qt::NoButton; - m_acceptedMouseDowns = Qt::NoButton; - m_frameStrutButtons = Qt::NoButton; m_sendKeyEvent = false; - m_sendUpAsRightButton = false; m_inputSource = nil; - m_mouseMoveHelper = [[QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) alloc] initWithView:self]; m_resendKeyEvent = false; - m_scrolling = false; m_updatingDrag = false; m_currentlyInterpretedKeyEvent = nil; - m_dontOverrideCtrlLMB = qt_mac_resolveOption(false, platformWindow->window(), - "_q_platform_MacDontOverrideCtrlLMB", "QT_MAC_DONT_OVERRIDE_CTRL_LMB"); self.focusRingType = NSFocusRingTypeNone; - self.cursor = nil; self.previousSuperview = nil; self.previousWindow = nil; diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm index 49c94f18db..c9c87d9323 100644 --- a/src/plugins/platforms/cocoa/qnsview_mouse.mm +++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm @@ -153,6 +153,19 @@ - (void)initMouse { + m_buttons = Qt::NoButton; + m_acceptedMouseDowns = Qt::NoButton; + m_frameStrutButtons = Qt::NoButton; + + m_scrolling = false; + self.cursor = nil; + + m_sendUpAsRightButton = false; + m_dontOverrideCtrlLMB = qt_mac_resolveOption(false, m_platformWindow->window(), + "_q_platform_MacDontOverrideCtrlLMB", "QT_MAC_DONT_OVERRIDE_CTRL_LMB"); + + m_mouseMoveHelper = [[QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) alloc] initWithView:self]; + NSUInteger trackingOptions = NSTrackingActiveInActiveApp | NSTrackingMouseEnteredAndExited | NSTrackingCursorUpdate; -- cgit v1.2.3 From 070f75d3b0f5313a0f486fe5c811a8e40dd97967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Sat, 23 Feb 2019 09:40:30 +0100 Subject: wasm: improve clipboard fallback path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This improves handling of cut/copy/paste clipboard events, ands allows clipboard access via the common keyboard shortcuts. Make the canvas be eligible for clipboard events by setting the contenteditable attribute. Install clipboard event handlers directly on the canvas. Suppress Ctrl+X/C/V key event handling in the keyboard event handler in order to make the browser generate clipboard events. Send synthetic key events from the clipboard event handlers to make the app copy/paste to Qt’s clipboard at the correct time. Access the system clipboard data using event.clipboardData. Task-number: QTBUG-64638 Change-Id: I584b78ffa2b755b1b76e477b970255c6e5522f6a Reviewed-by: Lorn Potter --- src/plugins/platforms/wasm/qtloader.js | 9 +++- src/plugins/platforms/wasm/qwasmclipboard.cpp | 48 +++++++++++++++------- .../platforms/wasm/qwasmeventtranslator.cpp | 8 ++++ src/plugins/platforms/wasm/wasm_shell.html | 8 +++- 4 files changed, 56 insertions(+), 17 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/wasm/qtloader.js b/src/plugins/platforms/wasm/qtloader.js index 84694c7b9f..203213db56 100644 --- a/src/plugins/platforms/wasm/qtloader.js +++ b/src/plugins/platforms/wasm/qtloader.js @@ -168,7 +168,14 @@ function QtLoader(config) removeChildren(container); var canvas = document.createElement("canvas"); canvas.className = "QtCanvas" - canvas.style = "height: 100%; width: 100%;" + canvas.style.height = "100%" + canvas.style.width = "100%" + + // Set contentEditable in order to enable clipboard events; hide the resulting focus frame. + canvas.contentEditable = true; + canvas.style.outline = "0px solid transparent"; + canvas.style.cursor = "default"; + return canvas; } diff --git a/src/plugins/platforms/wasm/qwasmclipboard.cpp b/src/plugins/platforms/wasm/qwasmclipboard.cpp index ec058f05dd..63fea7738d 100644 --- a/src/plugins/platforms/wasm/qwasmclipboard.cpp +++ b/src/plugins/platforms/wasm/qwasmclipboard.cpp @@ -67,23 +67,42 @@ static void qClipboardPromiseResolve(emscripten::val something) pasteClipboardData(emscripten::val("text/plain"), something); } -static void qClipboardCopyTo(val event) +static void qClipboardCutTo(val event) { - val target = event["target"]; - val clipboard = event["clipboardData"]; + if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) { + // Send synthetic Ctrl+X to make the app cut data to Qt's clipboard + QWindowSystemInterface::handleKeyEvent( + 0, QEvent::KeyPress, Qt::Key_X, Qt::ControlModifier, "X"); + } val module = val::global("Module"); val clipdata = module.call("getClipboardData"); val clipFormat = module.call("getClipboardFormat"); - clipboard.call("setData", clipFormat, clipdata); - target.call("preventDefault"); + event["clipboardData"].call("setData", clipFormat, clipdata); + event.call("preventDefault"); } -static void qClipboardPasteTo(val event) +static void qClipboardCopyTo(val event) { - val target = event["clipboardData"]; + if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) { + // Send synthetic Ctrl+C to make the app copy data to Qt's clipboard + QWindowSystemInterface::handleKeyEvent( + 0, QEvent::KeyPress, Qt::Key_C, Qt::ControlModifier, "C"); + } + val module = val::global("Module"); val clipdata = module.call("getClipboardData"); + val clipFormat = module.call("getClipboardFormat"); + event["clipboardData"].call("setData", clipFormat, clipdata); + event.call("preventDefault"); +} + +static void qClipboardPasteTo(val event) +{ + bool hasClipboardApi = QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi; + val clipdata = hasClipboardApi ? + val::global("Module").call("getClipboardData") : + event["clipboardData"].call("getData", std::string("text")); const std::string data = clipdata.as(); if (data.length() > 0) { @@ -99,6 +118,7 @@ EMSCRIPTEN_BINDINGS(clipboard_module) { function("getClipboardFormat", &getClipboardFormat); function("pasteClipboardData", &pasteClipboardData); function("qClipboardPromiseResolve", &qClipboardPromiseResolve); + function("qClipboardCutTo", &qClipboardCutTo); function("qClipboardCopyTo", &qClipboardCopyTo); function("qClipboardPasteTo", &qClipboardPasteTo); } @@ -161,7 +181,7 @@ void QWasmClipboard::initClipboardEvents() val permissions = navigator["permissions"]; val clipboard = navigator["clipboard"]; - hasClipboardApi = (!clipboard.isUndefined()); + hasClipboardApi = (!clipboard.isUndefined() && !clipboard["readText"].isUndefined()); if (hasClipboardApi) { val readPermissionsMap = val::object(); readPermissionsMap.set("name", val("clipboard-read")); @@ -172,13 +192,13 @@ void QWasmClipboard::initClipboardEvents() permissions.call("query", writePermissionsMap); } else { - - val window = val::global("window"); - window.call("addEventListener", std::string("paste"), - val::module_property("qClipboardPasteTo")); - - window.call("addEventListener", std::string("copy"), + val canvas = val::module_property("canvas"); + canvas.call("addEventListener", std::string("cut"), + val::module_property("qClipboardCutTo")); + canvas.call("addEventListener", std::string("copy"), val::module_property("qClipboardCopyTo")); + canvas.call("addEventListener", std::string("paste"), + val::module_property("qClipboardPasteTo")); } } diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp index 3fc8f600a1..05c09ec9a0 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp @@ -832,6 +832,14 @@ bool QWasmEventTranslator::processKeyboard(int eventType, const EmscriptenKeyboa return 0; QFlags mods = translateKeyboardEventModifier(keyEvent); + + // Clipboard fallback path: cut/copy/paste are handled by clipboard event + // handlers if direct clipboard access is not available. + if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi && modifiers & Qt::ControlModifier && + (qtKey == Qt::Key_X || qtKey == Qt::Key_C || qtKey == Qt::Key_V)) { + return 0; + } + bool accepted = false; if (keyType == QEvent::KeyPress && diff --git a/src/plugins/platforms/wasm/wasm_shell.html b/src/plugins/platforms/wasm/wasm_shell.html index 67bfcdfbdc..110d45e036 100644 --- a/src/plugins/platforms/wasm/wasm_shell.html +++ b/src/plugins/platforms/wasm/wasm_shell.html @@ -7,7 +7,11 @@ @@ -19,7 +23,7 @@ - +