diff options
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbintegration.cpp')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbintegration.cpp | 260 |
1 files changed, 146 insertions, 114 deletions
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index efda6b67ce..4dafae31e3 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qxcbintegration.h" #include "qxcbconnection.h" @@ -56,11 +20,12 @@ #ifndef QT_NO_SESSIONMANAGER #include "qxcbsessionmanager.h" #endif +#include "qxcbxsettings.h" #include <xcb/xcb.h> -#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h> -#include <QtServiceSupport/private/qgenericunixservices_p.h> +#include <QtGui/private/qgenericunixfontdatabase_p.h> +#include <QtGui/private/qgenericunixservices_p.h> #include <stdio.h> @@ -84,10 +49,10 @@ #include <QtGui/QOpenGLContext> #include <QtGui/QScreen> #include <QtGui/QOffscreenSurface> -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) #include <qpa/qplatformaccessibility.h> -#ifndef QT_NO_ACCESSIBILITY_ATSPI_BRIDGE -#include <QtLinuxAccessibilitySupport/private/bridge_p.h> +#if QT_CONFIG(accessibility_atspi_bridge) +#include <QtGui/private/qspiaccessiblebridge_p.h> #endif #endif @@ -100,16 +65,18 @@ QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + // Find out if our parent process is gdb by looking at the 'exe' symlink under /proc,. // or, for older Linuxes, read out 'cmdline'. static bool runningUnderDebugger() { #if defined(QT_DEBUG) && defined(Q_OS_LINUX) - const QString parentProc = QLatin1String("/proc/") + QString::number(getppid()); - const QFileInfo parentProcExe(parentProc + QLatin1String("/exe")); + const QString parentProc = "/proc/"_L1 + QString::number(getppid()); + const QFileInfo parentProcExe(parentProc + "/exe"_L1); if (parentProcExe.isSymLink()) - return parentProcExe.symLinkTarget().endsWith(QLatin1String("/gdb")); - QFile f(parentProc + QLatin1String("/cmdline")); + return parentProcExe.symLinkTarget().endsWith("/gdb"_L1); + QFile f(parentProc + "/cmdline"_L1); if (!f.open(QIODevice::ReadOnly)) return false; QByteArray s; @@ -126,19 +93,26 @@ static bool runningUnderDebugger() #endif } +class QXcbUnixServices : public QGenericUnixServices +{ +public: + QString portalWindowIdentifier(QWindow *window) override; +}; + + QXcbIntegration *QXcbIntegration::m_instance = nullptr; QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char **argv) - : m_services(new QGenericUnixServices) - , m_instanceName(0) + : m_services(new QXcbUnixServices) + , m_instanceName(nullptr) , m_canGrab(true) , m_defaultVisualId(UINT_MAX) { + Q_UNUSED(parameters); + m_instance = this; qApp->setAttribute(Qt::AA_CompressHighFrequencyEvents, true); - QWindowSystemInterface::setPlatformFiltersEvents(true); - qRegisterMetaType<QXcbWindow*>(); #if QT_CONFIG(xcb_xlib) XInitThreads(); @@ -146,7 +120,7 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char m_nativeInterface.reset(new QXcbNativeInterface); // Parse arguments - const char *displayName = 0; + const char *displayName = nullptr; bool noGrabArg = false; bool doGrabArg = false; if (argc) { @@ -177,7 +151,7 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char bool underDebugger = runningUnderDebugger(); if (noGrabArg && doGrabArg && underDebugger) { - qWarning("Both -nograb and -dograb command line arguments specified. Please pick one. -nograb takes prcedence"); + qWarning("Both -nograb and -dograb command line arguments specified. Please pick one. -nograb takes precedence"); doGrabArg = false; } @@ -193,40 +167,27 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char if (canNotGrabEnv) m_canGrab = false; - 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()) { - delete conn; + m_connection = new QXcbConnection(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, displayName); + if (!m_connection->isConnected()) { + delete m_connection; + m_connection = nullptr; return; } - m_connections << conn; - - // ### Qt 6 (QTBUG-52408) remove this multi-connection code path - for (int i = 0; i < numParameters - 1; i += 2) { - 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()) - m_connections << conn; - else - delete conn; - } m_fontDatabase.reset(new QGenericUnixFontDatabase()); #if QT_CONFIG(xcb_native_painting) if (nativePaintingEnabled()) { qCDebug(lcQpaXcb, "QXCB USING NATIVE PAINTING"); - qt_xcb_native_x11_info_init(defaultConnection()); + qt_xcb_native_x11_info_init(connection()); } #endif } QXcbIntegration::~QXcbIntegration() { - qDeleteAll(m_connections); + delete m_connection; + m_connection = nullptr; m_instance = nullptr; } @@ -243,10 +204,10 @@ QPlatformPixmap *QXcbIntegration::createPlatformPixmap(QPlatformPixmap::PixelTyp QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const { QXcbGlIntegration *glIntegration = nullptr; - const bool isTrayIconWindow = QXcbWindow::isTrayIconWindow(window);; + const bool isTrayIconWindow = QXcbWindow::isTrayIconWindow(window); if (window->type() != Qt::Desktop && !isTrayIconWindow) { if (window->supportsOpenGL()) { - glIntegration = defaultConnection()->glIntegration(); + glIntegration = connection()->glIntegration(); if (glIntegration) { QXcbWindow *xcbWindow = glIntegration->createWindow(window); xcbWindow->create(); @@ -276,28 +237,54 @@ QPlatformWindow *QXcbIntegration::createForeignWindow(QWindow *window, WId nativ #ifndef QT_NO_OPENGL QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { - QXcbScreen *screen = static_cast<QXcbScreen *>(context->screen()->handle()); - QXcbGlIntegration *glIntegration = screen->connection()->glIntegration(); + QXcbGlIntegration *glIntegration = m_connection->glIntegration(); if (!glIntegration) { qWarning("QXcbIntegration: Cannot create platform OpenGL context, neither GLX nor EGL are enabled"); return nullptr; } return glIntegration->createPlatformOpenGLContext(context); } + +# if QT_CONFIG(xcb_glx_plugin) +QOpenGLContext *QXcbIntegration::createOpenGLContext(GLXContext context, void *visualInfo, QOpenGLContext *shareContext) const +{ + using namespace QNativeInterface::Private; + if (auto *glxIntegration = dynamic_cast<QGLXIntegration*>(m_connection->glIntegration())) + return glxIntegration->createOpenGLContext(context, visualInfo, shareContext); + else + return nullptr; +} +# endif + +#if QT_CONFIG(egl) +QOpenGLContext *QXcbIntegration::createOpenGLContext(EGLContext context, EGLDisplay display, QOpenGLContext *shareContext) const +{ + using namespace QNativeInterface::Private; + if (auto *eglIntegration = dynamic_cast<QEGLIntegration*>(m_connection->glIntegration())) + return eglIntegration->createOpenGLContext(context, display, shareContext); + else + return nullptr; +} #endif +#endif // QT_NO_OPENGL + QPlatformBackingStore *QXcbIntegration::createPlatformBackingStore(QWindow *window) const { - const bool isTrayIconWindow = QXcbWindow::isTrayIconWindow(window); - if (isTrayIconWindow) - return new QXcbSystemTrayBackingStore(window); + QPlatformBackingStore *backingStore = nullptr; + const bool isTrayIconWindow = QXcbWindow::isTrayIconWindow(window); + if (isTrayIconWindow) { + backingStore = new QXcbSystemTrayBackingStore(window); #if QT_CONFIG(xcb_native_painting) - if (nativePaintingEnabled()) - return new QXcbNativeBackingStore(window); + } else if (nativePaintingEnabled()) { + backingStore = new QXcbNativeBackingStore(window); #endif - - return new QXcbBackingStore(window); + } else { + backingStore = new QXcbBackingStore(window); + } + Q_ASSERT(backingStore); + return backingStore; } QPlatformOffscreenSurface *QXcbIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const @@ -317,7 +304,7 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const case OpenGL: case ThreadedOpenGL: { - if (const auto *integration = defaultConnection()->glIntegration()) + if (const auto *integration = connection()->glIntegration()) return cap != ThreadedOpenGL || integration->supportsThreadedOpenGL(); return false; } @@ -332,8 +319,8 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const case SwitchableWidgetComposition: { - return m_connections.at(0)->glIntegration() - && m_connections.at(0)->glIntegration()->supportsSwitchableWidgetComposition(); + return m_connection->glIntegration() + && m_connection->glIntegration()->supportsSwitchableWidgetComposition(); } default: return QPlatformIntegration::hasCapability(cap); @@ -342,22 +329,41 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const QAbstractEventDispatcher *QXcbIntegration::createEventDispatcher() const { - return QXcbEventDispatcher::createEventDispatcher(defaultConnection()); + return QXcbEventDispatcher::createEventDispatcher(connection()); } +using namespace Qt::Literals::StringLiterals; +static const auto xsNetCursorBlink = "Net/CursorBlink"_ba; +static const auto xsNetCursorBlinkTime = "Net/CursorBlinkTime"_ba; +static const auto xsNetDoubleClickTime = "Net/DoubleClickTime"_ba; +static const auto xsNetDoubleClickDistance = "Net/DoubleClickDistance"_ba; +static const auto xsNetDndDragThreshold = "Net/DndDragThreshold"_ba; + void QXcbIntegration::initialize() { - const QLatin1String defaultInputContext("compose"); + const auto defaultInputContext = "compose"_L1; // Perform everything that may potentially need the event dispatcher (timers, socket // notifiers) here instead of the constructor. - QString icStr = QPlatformInputContextFactory::requested(); - if (icStr.isNull()) - icStr = defaultInputContext; - m_inputContext.reset(QPlatformInputContextFactory::create(icStr)); - if (!m_inputContext && icStr != defaultInputContext && icStr != QLatin1String("none")) + auto icStrs = QPlatformInputContextFactory::requested(); + if (icStrs.isEmpty()) + icStrs = { defaultInputContext }; + m_inputContext.reset(QPlatformInputContextFactory::create(icStrs)); + if (!m_inputContext && !icStrs.contains(defaultInputContext) + && icStrs != QStringList{"none"_L1}) m_inputContext.reset(QPlatformInputContextFactory::create(defaultInputContext)); - defaultConnection()->keyboard()->initialize(); + connection()->keyboard()->initialize(); + + auto notifyThemeChanged = [](QXcbVirtualDesktop *, const QByteArray &, const QVariant &, void *) { + QWindowSystemInterface::handleThemeChange(); + }; + + auto *xsettings = connection()->primaryScreen()->xSettings(); + xsettings->registerCallbackForProperty(xsNetCursorBlink, notifyThemeChanged, this); + xsettings->registerCallbackForProperty(xsNetCursorBlinkTime, notifyThemeChanged, this); + xsettings->registerCallbackForProperty(xsNetDoubleClickTime, notifyThemeChanged, this); + xsettings->registerCallbackForProperty(xsNetDoubleClickDistance, notifyThemeChanged, this); + xsettings->registerCallbackForProperty(xsNetDndDragThreshold, notifyThemeChanged, this); } void QXcbIntegration::moveToScreen(QWindow *window, int screen) @@ -379,7 +385,7 @@ QPlatformNativeInterface * QXcbIntegration::nativeInterface() const #ifndef QT_NO_CLIPBOARD QPlatformClipboard *QXcbIntegration::clipboard() const { - return m_connections.at(0)->clipboard(); + return m_connection->clipboard(); } #endif @@ -395,7 +401,7 @@ QPlatformDrag *QXcbIntegration::drag() const return simpleDrag; } - return m_connections.at(0)->drag(); + return m_connection->drag(); } #endif @@ -404,7 +410,7 @@ QPlatformInputContext *QXcbIntegration::inputContext() const return m_inputContext.data(); } -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) QPlatformAccessibility *QXcbIntegration::accessibility() const { #if !defined(QT_NO_ACCESSIBILITY_ATSPI_BRIDGE) @@ -424,14 +430,9 @@ QPlatformServices *QXcbIntegration::services() const return m_services.data(); } -Qt::KeyboardModifiers QXcbIntegration::queryKeyboardModifiers() const -{ - return m_connections.at(0)->queryKeyboardModifiers(); -} - -QList<int> QXcbIntegration::possibleKeys(const QKeyEvent *e) const +QPlatformKeyMapper *QXcbIntegration::keyMapper() const { - return m_connections.at(0)->keyboard()->possibleKeys(e); + return m_connection->keyboard(); } QStringList QXcbIntegration::themeNames() const @@ -444,31 +445,53 @@ QPlatformTheme *QXcbIntegration::createPlatformTheme(const QString &name) const return QGenericUnixTheme::createUnixTheme(name); } +#define RETURN_VALID_XSETTINGS(key) { \ + auto value = connection()->primaryScreen()->xSettings()->setting(key); \ + if (value.isValid()) return value; \ +} + QVariant QXcbIntegration::styleHint(QPlatformIntegration::StyleHint hint) const { switch (hint) { - case QPlatformIntegration::CursorFlashTime: - case QPlatformIntegration::KeyboardInputInterval: + case QPlatformIntegration::CursorFlashTime: { + bool ok = false; + // If cursor blinking is off, returns 0 to keep the cursor awlays display. + if (connection()->primaryScreen()->xSettings()->setting(xsNetCursorBlink).toInt(&ok) == 0 && ok) + return 0; + + RETURN_VALID_XSETTINGS(xsNetCursorBlinkTime); + break; + } case QPlatformIntegration::MouseDoubleClickInterval: + RETURN_VALID_XSETTINGS(xsNetDoubleClickTime); + break; + case QPlatformIntegration::MouseDoubleClickDistance: + RETURN_VALID_XSETTINGS(xsNetDoubleClickDistance); + break; + case QPlatformIntegration::KeyboardInputInterval: case QPlatformIntegration::StartDragTime: case QPlatformIntegration::KeyboardAutoRepeatRate: case QPlatformIntegration::PasswordMaskDelay: case QPlatformIntegration::StartDragVelocity: case QPlatformIntegration::UseRtlExtensions: case QPlatformIntegration::PasswordMaskCharacter: + case QPlatformIntegration::FlickMaximumVelocity: + case QPlatformIntegration::FlickDeceleration: // TODO using various xcb, gnome or KDE settings break; // Not implemented, use defaults + case QPlatformIntegration::FlickStartDistance: case QPlatformIntegration::StartDragDistance: { + RETURN_VALID_XSETTINGS(xsNetDndDragThreshold); // The default (in QPlatformTheme::defaultThemeHint) is 10 pixels, but // on a high-resolution screen it makes sense to increase it. - qreal dpi = 100.0; - if (const QXcbScreen *screen = defaultConnection()->primaryScreen()) { + qreal dpi = 100; + if (const QXcbScreen *screen = connection()->primaryScreen()) { if (screen->logicalDpi().first > dpi) dpi = screen->logicalDpi().first; if (screen->logicalDpi().second > dpi) dpi = screen->logicalDpi().second; } - return 10.0 * dpi / 100.0; + return (hint == QPlatformIntegration::FlickStartDistance ? qreal(15) : qreal(10)) * dpi / qreal(100); } case QPlatformIntegration::ShowIsFullScreen: // X11 always has support for windows, but the @@ -488,7 +511,7 @@ static QString argv0BaseName() const QStringList arguments = QCoreApplication::arguments(); if (!arguments.isEmpty() && !arguments.front().isEmpty()) { result = arguments.front(); - const int lastSlashPos = result.lastIndexOf(QLatin1Char('/')); + const int lastSlashPos = result.lastIndexOf(u'/'); if (lastSlashPos != -1) result.remove(0, lastSlashPos + 1); } @@ -533,9 +556,7 @@ QPlatformSessionManager *QXcbIntegration::createPlatformSessionManager(const QSt void QXcbIntegration::sync() { - for (int i = 0; i < m_connections.size(); i++) { - m_connections.at(i)->sync(); - } + m_connection->sync(); } // For QApplication::beep() @@ -569,4 +590,15 @@ QPlatformVulkanInstance *QXcbIntegration::createPlatformVulkanInstance(QVulkanIn } #endif +void QXcbIntegration::setApplicationBadge(qint64 number) +{ + auto unixServices = dynamic_cast<QGenericUnixServices *>(services()); + unixServices->setApplicationBadge(number); +} + +QString QXcbUnixServices::portalWindowIdentifier(QWindow *window) +{ + return "x11:"_L1 + QString::number(window->winId(), 16); +} + QT_END_NAMESPACE |