diff options
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbwindow.cpp')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 688 |
1 files changed, 391 insertions, 297 deletions
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 147bac01dd..09d4cd9833 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -1,47 +1,12 @@ -/**************************************************************************** -** -** 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 "qxcbwindow.h" #include <QtDebug> #include <QMetaEnum> #include <QScreen> +#include <QtCore/QFileInfo> #include <QtGui/QIcon> #include <QtGui/QRegion> #include <QtGui/private/qhighdpiscaling_p.h> @@ -92,6 +57,11 @@ enum { QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + +Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window"); +Q_LOGGING_CATEGORY(lcQpaXcbWindow, "qt.qpa.xcb.window"); + Q_DECLARE_TYPEINFO(xcb_rectangle_t, Q_PRIMITIVE_TYPE); #undef FocusIn @@ -126,12 +96,14 @@ const quint32 XEMBED_VERSION = 0; QXcbScreen *QXcbWindow::parentScreen() { - return parent() ? static_cast<QXcbWindow*>(parent())->parentScreen() : xcbScreen(); + return QPlatformWindow::parent() ? static_cast<QXcbWindow*>(QPlatformWindow::parent())->parentScreen() : xcbScreen(); } -//QPlatformWindow::screenForGeometry version that uses deviceIndependentGeometry QXcbScreen *QXcbWindow::initialScreen() const { + // Resolve initial screen via QWindowPrivate::screenForGeometry(), + // which works in platform independent coordinates, as opposed to + // QPlatformWindow::screenForGeometry() that uses native coordinates. QWindowPrivate *windowPrivate = qt_window_private(window()); QScreen *screen = windowPrivate->screenForGeometry(window()->geometry()); return static_cast<QXcbScreen*>(screen->handle()); @@ -163,6 +135,7 @@ void QXcbWindow::setImageFormatForVisual(const xcb_visualtype_t *visual) case 16: qWarning("Using RGB16 fallback, if this works your X11 server is reporting a bad screen format."); m_imageFormat = QImage::Format_RGB16; + break; default: break; } @@ -198,7 +171,7 @@ static inline XTextProperty* qstringToXTP(Display *dpy, const QString& s) tp.value = (uchar*)qcs.data(); tp.encoding = XA_STRING; tp.format = 8; - tp.nitems = qcs.length(); + tp.nitems = qcs.size(); free_prop = false; } return &tp; @@ -246,13 +219,14 @@ enum : quint32 { | XCB_EVENT_MASK_POINTER_MOTION, transparentForInputEventMask = baseEventMask - | XCB_EVENT_MASK_VISIBILITY_CHANGE | XCB_EVENT_MASK_RESIZE_REDIRECT + | XCB_EVENT_MASK_VISIBILITY_CHANGE | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_COLOR_MAP_CHANGE | XCB_EVENT_MASK_OWNER_GRAB_BUTTON }; void QXcbWindow::create() { + xcb_window_t old_m_window = m_window; destroy(); m_windowState = Qt::WindowNoState; @@ -261,8 +235,8 @@ void QXcbWindow::create() Qt::WindowType type = window()->type(); QXcbScreen *currentScreen = xcbScreen(); - QXcbScreen *platformScreen = parent() ? parentScreen() : initialScreen(); - QRect rect = parent() + QXcbScreen *platformScreen = QPlatformWindow::parent() ? parentScreen() : initialScreen(); + QRect rect = QPlatformWindow::parent() ? QHighDpi::toNativeLocalPosition(window()->geometry(), platformScreen) : QHighDpi::toNativePixels(window()->geometry(), platformScreen); @@ -285,11 +259,6 @@ void QXcbWindow::create() return; } - QPlatformWindow::setGeometry(rect); - - if (platformScreen != currentScreen) - QWindowSystemInterface::handleWindowScreenChanged(window(), platformScreen->QPlatformScreen::screen()); - const QSize minimumSize = windowMinimumSize(); if (rect.width() > 0 || rect.height() > 0) { rect.setWidth(qBound(1, rect.width(), XCOORD_MAX)); @@ -301,12 +270,17 @@ void QXcbWindow::create() rect.setHeight(QHighDpi::toNativePixels(int(defaultWindowHeight), platformScreen->QPlatformScreen::screen())); } + QPlatformWindow::setGeometry(rect); + + if (platformScreen != currentScreen) + QWindowSystemInterface::handleWindowScreenChanged(window(), platformScreen->QPlatformScreen::screen()); + xcb_window_t xcb_parent_id = platformScreen->root(); - if (parent()) { - xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window(); - m_embedded = parent()->isForeignWindow(); + if (QPlatformWindow::parent()) { + xcb_parent_id = static_cast<QXcbWindow *>(QPlatformWindow::parent())->xcb_window(); + m_embedded = QPlatformWindow::parent()->isForeignWindow(); - QSurfaceFormat parentFormat = parent()->window()->requestedFormat(); + QSurfaceFormat parentFormat = QPlatformWindow::parent()->window()->requestedFormat(); if (window()->surfaceType() != QSurface::OpenGLSurface && parentFormat.hasAlpha()) { window()->setFormat(parentFormat); } @@ -324,16 +298,16 @@ void QXcbWindow::create() qWarning() << "Failed to use requested visual id."; } - if (parent()) { + if (QPlatformWindow::parent()) { // When using a Vulkan QWindow via QWidget::createWindowContainer() we // must make sure the visuals are compatible. Now, the parent will be // of RasterGLSurface which typically chooses a GLX/EGL compatible // visual which may not be what the Vulkan window would choose. // Therefore, take the parent's visual. if (window()->surfaceType() == QSurface::VulkanSurface - && parent()->window()->surfaceType() != QSurface::VulkanSurface) + && QPlatformWindow::parent()->window()->surfaceType() != QSurface::VulkanSurface) { - visual = platformScreen->visualForId(static_cast<QXcbWindow *>(parent())->visualId()); + visual = platformScreen->visualForId(static_cast<QXcbWindow *>(QPlatformWindow::parent())->visualId()); } } @@ -356,18 +330,8 @@ void QXcbWindow::create() | XCB_CW_BIT_GRAVITY | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER - | XCB_CW_EVENT_MASK; - - static auto haveOpenGL = []() { - static const bool result = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL); - return result; - }; - - xcb_colormap_t cmap = XCB_COLORMAP_NONE; - if ((window()->supportsOpenGL() && haveOpenGL()) || m_format.hasAlpha()) { - cmap = platformScreen->colormapForVisual(m_visualId); - mask |= XCB_CW_COLORMAP; - } + | XCB_CW_EVENT_MASK + | XCB_CW_COLORMAP; quint32 values[] = { XCB_BACK_PIXMAP_NONE, @@ -376,7 +340,7 @@ void QXcbWindow::create() type == Qt::Popup || type == Qt::ToolTip || (window()->flags() & Qt::BypassWindowManagerHint), type == Qt::Popup || type == Qt::Tool || type == Qt::SplashScreen || type == Qt::ToolTip || type == Qt::Drawer, defaultEventMask, - cmap + platformScreen->colormapForVisual(m_visualId) }; m_window = xcb_generate_id(xcb_connection()); @@ -400,20 +364,20 @@ void QXcbWindow::create() xcb_atom_t properties[5]; int propertyCount = 0; - properties[propertyCount++] = atom(QXcbAtom::WM_DELETE_WINDOW); - properties[propertyCount++] = atom(QXcbAtom::WM_TAKE_FOCUS); - properties[propertyCount++] = atom(QXcbAtom::_NET_WM_PING); + properties[propertyCount++] = atom(QXcbAtom::AtomWM_DELETE_WINDOW); + properties[propertyCount++] = atom(QXcbAtom::AtomWM_TAKE_FOCUS); + properties[propertyCount++] = atom(QXcbAtom::Atom_NET_WM_PING); if (connection()->hasXSync()) - properties[propertyCount++] = atom(QXcbAtom::_NET_WM_SYNC_REQUEST); + properties[propertyCount++] = atom(QXcbAtom::Atom_NET_WM_SYNC_REQUEST); if (window()->flags() & Qt::WindowContextHelpButtonHint) - properties[propertyCount++] = atom(QXcbAtom::_NET_WM_CONTEXT_HELP); + properties[propertyCount++] = atom(QXcbAtom::Atom_NET_WM_CONTEXT_HELP); xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, - atom(QXcbAtom::WM_PROTOCOLS), + atom(QXcbAtom::AtomWM_PROTOCOLS), XCB_ATOM_ATOM, 32, propertyCount, @@ -424,10 +388,35 @@ void QXcbWindow::create() const QByteArray wmClass = QXcbIntegration::instance()->wmClass(); if (!wmClass.isEmpty()) { xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, - m_window, atom(QXcbAtom::WM_CLASS), + m_window, atom(QXcbAtom::AtomWM_CLASS), XCB_ATOM_STRING, 8, wmClass.size(), wmClass.constData()); } + QString desktopFileName = QGuiApplication::desktopFileName(); + if (QGuiApplication::desktopFileName().isEmpty()) { + QFileInfo fi = QFileInfo(QCoreApplication::instance()->applicationFilePath()); + QStringList domainName = + QCoreApplication::instance()->organizationDomain().split(QLatin1Char('.'), + Qt::SkipEmptyParts); + + if (domainName.isEmpty()) { + desktopFileName = fi.baseName(); + } else { + for (int i = 0; i < domainName.size(); ++i) + desktopFileName.prepend(QLatin1Char('.')).prepend(domainName.at(i)); + desktopFileName.append(fi.baseName()); + } + } + if (!desktopFileName.isEmpty()) { + const QByteArray dfName = desktopFileName.toUtf8(); + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, + m_window, atom(QXcbAtom::Atom_KDE_NET_WM_DESKTOP_FILE), + atom(QXcbAtom::AtomUTF8_STRING), 8, dfName.size(), dfName.constData()); + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, + m_window, atom(QXcbAtom::Atom_GTK_APPLICATION_ID), + atom(QXcbAtom::AtomUTF8_STRING), 8, dfName.size(), dfName.constData()); + } + if (connection()->hasXSync()) { m_syncCounter = xcb_generate_id(xcb_connection()); xcb_sync_create_counter(xcb_connection(), m_syncCounter, m_syncValue); @@ -435,7 +424,7 @@ void QXcbWindow::create() xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, - atom(QXcbAtom::_NET_WM_SYNC_REQUEST_COUNTER), + atom(QXcbAtom::Atom_NET_WM_SYNC_REQUEST_COUNTER), XCB_ATOM_CARDINAL, 32, 1, @@ -445,13 +434,13 @@ void QXcbWindow::create() // set the PID to let the WM kill the application if unresponsive quint32 pid = getpid(); xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, - atom(QXcbAtom::_NET_WM_PID), XCB_ATOM_CARDINAL, 32, + atom(QXcbAtom::Atom_NET_WM_PID), XCB_ATOM_CARDINAL, 32, 1, &pid); const QByteArray clientMachine = QSysInfo::machineHostName().toLocal8Bit(); if (!clientMachine.isEmpty()) { xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, - atom(QXcbAtom::WM_CLIENT_MACHINE), XCB_ATOM_STRING, 8, + atom(QXcbAtom::AtomWM_CLIENT_MACHINE), XCB_ATOM_STRING, 8, clientMachine.size(), clientMachine.constData()); } @@ -465,14 +454,14 @@ void QXcbWindow::create() xcb_window_t leader = connection()->clientLeader(); xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, - atom(QXcbAtom::WM_CLIENT_LEADER), XCB_ATOM_WINDOW, 32, + atom(QXcbAtom::AtomWM_CLIENT_LEADER), XCB_ATOM_WINDOW, 32, 1, &leader); /* Add XEMBED info; this operation doesn't initiate the embedding. */ quint32 data[] = { XEMBED_VERSION, XEMBED_MAPPED }; xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, - atom(QXcbAtom::_XEMBED_INFO), - atom(QXcbAtom::_XEMBED_INFO), + atom(QXcbAtom::Atom_XEMBED_INFO), + atom(QXcbAtom::Atom_XEMBED_INFO), 32, 2, (void *)data); if (connection()->hasXInput2()) @@ -482,10 +471,8 @@ void QXcbWindow::create() setWindowFlags(window()->flags()); setWindowTitle(window()->title()); -#if QT_CONFIG(xcb_xlib) // force sync to read outstanding requests - see QTBUG-29106 - XSync(static_cast<Display*>(platformScreen->connection()->xlib_display()), false); -#endif + connection()->sync(); #if QT_CONFIG(draganddrop) connection()->drag()->dndEnable(this, true); @@ -507,6 +494,17 @@ void QXcbWindow::create() if (m_trayIconWindow) m_embedded = requestSystemTrayWindowDock(); + + if (m_window != old_m_window) { + if (!m_wmTransientForChildren.isEmpty()) { + QList<QPointer<QXcbWindow>> transientChildren = m_wmTransientForChildren; + m_wmTransientForChildren.clear(); + for (auto transientChild : transientChildren) { + if (transientChild) + transientChild->updateWmTransientFor(); + } + } + } } QXcbWindow::~QXcbWindow() @@ -514,6 +512,18 @@ QXcbWindow::~QXcbWindow() destroy(); } +QXcbForeignWindow::QXcbForeignWindow(QWindow *window, WId nativeHandle) + : QXcbWindow(window) +{ + m_window = nativeHandle; + + // Reflect the foreign window's geometry as our own + if (auto geometry = Q_XCB_REPLY(xcb_get_geometry, xcb_connection(), m_window)) { + QRect nativeGeometry(geometry->x, geometry->y, geometry->width, geometry->height); + QPlatformWindow::setGeometry(nativeGeometry); + } +} + QXcbForeignWindow::~QXcbForeignWindow() { // Clear window so that destroy() does not affect it @@ -531,12 +541,14 @@ void QXcbWindow::destroy() doFocusOut(); if (connection()->mouseGrabber() == this) connection()->setMouseGrabber(nullptr); + if (connection()->mousePressWindow() == this) + connection()->setMousePressWindow(nullptr); if (m_syncCounter && connection()->hasXSync()) xcb_sync_destroy_counter(xcb_connection(), m_syncCounter); if (m_window) { if (m_netWmUserTimeWindow) { - xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW)); + xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_USER_TIME_WINDOW)); // Some window managers, like metacity, do XSelectInput on the _NET_WM_USER_TIME_WINDOW window, // without trapping BadWindow (which crashes when the user time window is destroyed). connection()->sync(); @@ -549,6 +561,7 @@ void QXcbWindow::destroy() } m_mapped = false; + m_recreationReasons = RecreationNotNeeded; if (m_pendingSyncRequest) m_pendingSyncRequest->invalidate(); @@ -556,12 +569,14 @@ void QXcbWindow::destroy() void QXcbWindow::setGeometry(const QRect &rect) { + setWindowState(Qt::WindowNoState); + QPlatformWindow::setGeometry(rect); propagateSizeHints(); QXcbScreen *currentScreen = xcbScreen(); - QXcbScreen *newScreen = parent() ? parentScreen() : static_cast<QXcbScreen*>(screenForGeometry(rect)); + QXcbScreen *newScreen = QPlatformWindow::parent() ? parentScreen() : static_cast<QXcbScreen*>(screenForGeometry(rect)); if (!newScreen) newScreen = xcbScreen(); @@ -602,9 +617,9 @@ void QXcbWindow::setGeometry(const QRect &rect) QMargins QXcbWindow::frameMargins() const { if (m_dirtyFrameMargins) { - if (connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::_NET_FRAME_EXTENTS))) { + if (connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::Atom_NET_FRAME_EXTENTS))) { auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(), false, m_window, - atom(QXcbAtom::_NET_FRAME_EXTENTS), XCB_ATOM_CARDINAL, 0, 4); + atom(QXcbAtom::Atom_NET_FRAME_EXTENTS), XCB_ATOM_CARDINAL, 0, 4); if (reply && reply->type == XCB_ATOM_CARDINAL && reply->format == 32 && reply->value_len == 4) { quint32 *data = (quint32 *)xcb_get_property_value(reply.get()); // _NET_FRAME_EXTENTS format is left, right, top, bottom @@ -680,31 +695,58 @@ void QXcbWindow::setVisible(bool visible) hide(); } +void QXcbWindow::updateWmTransientFor() +{ + xcb_window_t transientXcbParent = XCB_NONE; + if (isTransient(window())) { + QWindow *tp = window()->transientParent(); + if (tp && tp->handle()) { + QXcbWindow *handle = static_cast<QXcbWindow *>(tp->handle()); + transientXcbParent = tp->handle()->winId(); + if (transientXcbParent) { + handle->registerWmTransientForChild(this); + qCDebug(lcQpaXcbWindow) << Q_FUNC_INFO << static_cast<QPlatformWindow *>(handle) + << " registerWmTransientForChild " << static_cast<QPlatformWindow *>(this); + } + } + // Default to client leader if there is no transient parent, else modal dialogs can + // be hidden by their parents. + if (!transientXcbParent) + transientXcbParent = connection()->clientLeader(); + if (transientXcbParent) { // ICCCM 4.1.2.6 + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32, + 1, &transientXcbParent); + qCDebug(lcQpaXcbWindow, "0x%x added XCB_ATOM_WM_TRANSIENT_FOR 0x%x", m_window, transientXcbParent); + } + } + if (!transientXcbParent) + xcb_delete_property(xcb_connection(), m_window, XCB_ATOM_WM_TRANSIENT_FOR); +} + +void QXcbWindow::registerWmTransientForChild(QXcbWindow *child) +{ + if (!child) + return; + + if (!m_wmTransientForChildren.contains(child)) + m_wmTransientForChildren.append(child); +} + void QXcbWindow::show() { if (window()->isTopLevel()) { + if (m_recreationReasons != RecreationNotNeeded) { + qCDebug(lcQpaWindow) << "QXcbWindow: need to recreate window" << window() << m_recreationReasons; + create(); + m_recreationReasons = RecreationNotNeeded; + } // update WM_NORMAL_HINTS propagateSizeHints(); // update WM_TRANSIENT_FOR - xcb_window_t transientXcbParent = 0; - if (isTransient(window())) { - const QWindow *tp = window()->transientParent(); - if (tp && tp->handle()) - transientXcbParent = static_cast<const QXcbWindow *>(tp->handle())->winId(); - // Default to client leader if there is no transient parent, else modal dialogs can - // be hidden by their parents. - if (!transientXcbParent) - transientXcbParent = connection()->clientLeader(); - if (transientXcbParent) { // ICCCM 4.1.2.6 - xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, - XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32, - 1, &transientXcbParent); - } - } - if (!transientXcbParent) - xcb_delete_property(xcb_connection(), m_window, XCB_ATOM_WM_TRANSIENT_FOR); + updateWmTransientFor(); // update _NET_WM_STATE setNetWmStateOnUnmappedWindow(); @@ -815,7 +857,7 @@ void QXcbWindow::doFocusIn() return; QWindow *w = static_cast<QWindowPrivate *>(QObjectPrivate::get(window()))->eventReceiver(); connection()->setFocusWindow(w); - QWindowSystemInterface::handleWindowActivated(w, Qt::ActiveWindowFocusReason); + QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason); } void QXcbWindow::doFocusOut() @@ -858,29 +900,29 @@ QXcbWindow::NetWmStates QXcbWindow::netWmStates() NetWmStates result; auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(), - 0, m_window, atom(QXcbAtom::_NET_WM_STATE), + 0, m_window, atom(QXcbAtom::Atom_NET_WM_STATE), XCB_ATOM_ATOM, 0, 1024); if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) { const xcb_atom_t *states = static_cast<const xcb_atom_t *>(xcb_get_property_value(reply.get())); const xcb_atom_t *statesEnd = states + reply->length; - if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_ABOVE))) + if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_ABOVE))) result |= NetWmStateAbove; - if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_BELOW))) + if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_BELOW))) result |= NetWmStateBelow; - if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN))) + if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN))) result |= NetWmStateFullScreen; - if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ))) + if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ))) result |= NetWmStateMaximizedHorz; - if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT))) + if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT))) result |= NetWmStateMaximizedVert; - if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MODAL))) + if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_MODAL))) result |= NetWmStateModal; - if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP))) + if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_STAYS_ON_TOP))) result |= NetWmStateStaysOnTop; - if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION))) + if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_DEMANDS_ATTENTION))) result |= NetWmStateDemandsAttention; - if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_HIDDEN))) + if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_HIDDEN))) result |= NetWmStateHidden; } else { qCDebug(lcQpaXcb, "getting net wm state (%x), empty\n", m_window); @@ -898,6 +940,12 @@ void QXcbWindow::setWindowFlags(Qt::WindowFlags flags) if (type == Qt::Popup) flags |= Qt::X11BypassWindowManagerHint; + Qt::WindowFlags oldflags = window()->flags(); + if ((oldflags & Qt::WindowStaysOnTopHint) != (flags & Qt::WindowStaysOnTopHint)) + m_recreationReasons |= WindowStaysOnTopHintChanged; + if ((oldflags & Qt::WindowStaysOnBottomHint) != (flags & Qt::WindowStaysOnBottomHint)) + m_recreationReasons |= WindowStaysOnBottomHintChanged; + const quint32 mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; const quint32 values[] = { // XCB_CW_OVERRIDE_REDIRECT @@ -989,13 +1037,13 @@ void QXcbWindow::setMotifWmHints(Qt::WindowFlags flags) xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, - atom(QXcbAtom::_MOTIF_WM_HINTS), - atom(QXcbAtom::_MOTIF_WM_HINTS), + atom(QXcbAtom::Atom_MOTIF_WM_HINTS), + atom(QXcbAtom::Atom_MOTIF_WM_HINTS), 32, 5, &mwmhints); } else { - xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_MOTIF_WM_HINTS)); + xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_MOTIF_WM_HINTS)); } } @@ -1007,7 +1055,7 @@ void QXcbWindow::setNetWmState(bool set, xcb_atom_t one, xcb_atom_t two) event.format = 32; event.sequence = 0; event.window = m_window; - event.type = atom(QXcbAtom::_NET_WM_STATE); + event.type = atom(QXcbAtom::Atom_NET_WM_STATE); event.data.data32[0] = set ? 1 : 0; event.data.data32[1] = one; event.data.data32[2] = two; @@ -1023,26 +1071,26 @@ 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)); + atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ), + atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT)); } if ((m_windowState ^ state) & Qt::WindowFullScreen) - setNetWmState(state & Qt::WindowFullScreen, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); + setNetWmState(state & Qt::WindowFullScreen, atom(QXcbAtom::Atom_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)); + atom(QXcbAtom::Atom_NET_WM_STATE_ABOVE), + atom(QXcbAtom::Atom_NET_WM_STATE_STAYS_ON_TOP)); + setNetWmState(flags & Qt::WindowStaysOnBottomHint, atom(QXcbAtom::Atom_NET_WM_STATE_BELOW)); } void QXcbWindow::setNetWmStateOnUnmappedWindow() { if (Q_UNLIKELY(m_mapped)) - qCWarning(lcQpaXcb()) << "internal error: " << Q_FUNC_INFO << "called on mapped window"; + qCDebug(lcQpaXcb()) << "internal info: " << Q_FUNC_INFO << "called on mapped window"; NetWmStates states; const Qt::WindowFlags flags = window()->flags(); @@ -1077,7 +1125,7 @@ void QXcbWindow::setNetWmStateOnUnmappedWindow() QList<xcb_atom_t> atoms; auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(), - 0, m_window, atom(QXcbAtom::_NET_WM_STATE), + 0, m_window, atom(QXcbAtom::Atom_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<const xcb_atom_t *>(xcb_get_property_value(reply.get())); @@ -1085,31 +1133,31 @@ void QXcbWindow::setNetWmStateOnUnmappedWindow() 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 & NetWmStateHidden && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_HIDDEN))) - atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_HIDDEN)); - 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 (states & NetWmStateAbove && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_ABOVE))) + atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_ABOVE)); + if (states & NetWmStateBelow && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_BELOW))) + atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_BELOW)); + if (states & NetWmStateHidden && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_HIDDEN))) + atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_HIDDEN)); + if (states & NetWmStateFullScreen && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN))) + atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN)); + if (states & NetWmStateMaximizedHorz && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ))) + atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ)); + if (states & NetWmStateMaximizedVert && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT))) + atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT)); + if (states & NetWmStateModal && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_MODAL))) + atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_MODAL)); + if (states & NetWmStateStaysOnTop && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_STAYS_ON_TOP))) + atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_STAYS_ON_TOP)); + if (states & NetWmStateDemandsAttention && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_DEMANDS_ATTENTION))) + atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_DEMANDS_ATTENTION)); if (atoms.isEmpty()) { - xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_STATE)); + xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_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()); + atom(QXcbAtom::Atom_NET_WM_STATE), XCB_ATOM_ATOM, 32, + atoms.size(), atoms.constData()); } xcb_flush(xcb_connection()); } @@ -1119,28 +1167,43 @@ void QXcbWindow::setWindowState(Qt::WindowStates state) if (state == m_windowState) return; - if ((m_windowState & Qt::WindowMinimized) && !(state & Qt::WindowMinimized)) { - xcb_map_window(xcb_connection(), m_window); - } else if (!(m_windowState & Qt::WindowMinimized) && (state & Qt::WindowMinimized)) { - xcb_client_message_event_t event; + Qt::WindowStates unsetState = m_windowState & ~state; + Qt::WindowStates newState = state & ~m_windowState; - event.response_type = XCB_CLIENT_MESSAGE; - event.format = 32; - event.sequence = 0; - event.window = m_window; - event.type = atom(QXcbAtom::WM_CHANGE_STATE); - event.data.data32[0] = XCB_ICCCM_WM_STATE_ICONIC; - event.data.data32[1] = 0; - event.data.data32[2] = 0; - event.data.data32[3] = 0; - event.data.data32[4] = 0; + // unset old state + if (unsetState & Qt::WindowMinimized) + xcb_map_window(xcb_connection(), m_window); + if (unsetState & Qt::WindowMaximized) + setNetWmState(false, + atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ), + atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT)); + if (unsetState & Qt::WindowFullScreen) + setNetWmState(false, atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN)); + + // set new state + if (newState & Qt::WindowMinimized) { + { + xcb_client_message_event_t event; + + event.response_type = XCB_CLIENT_MESSAGE; + event.format = 32; + event.sequence = 0; + event.window = m_window; + event.type = atom(QXcbAtom::AtomWM_CHANGE_STATE); + event.data.data32[0] = XCB_ICCCM_WM_STATE_ICONIC; + event.data.data32[1] = 0; + event.data.data32[2] = 0; + event.data.data32[3] = 0; + event.data.data32[4] = 0; - xcb_send_event(xcb_connection(), 0, xcbScreen()->root(), - XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, - (const char *)&event); + xcb_send_event(xcb_connection(), 0, xcbScreen()->root(), + XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, + (const char *)&event); + } m_minimized = true; } + // set Maximized && FullScreen state if need setNetWmState(state); xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_hints_unchecked(xcb_connection(), m_window); @@ -1166,7 +1229,7 @@ void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp) if (timestamp != 0) connection()->setNetWmUserTime(timestamp); - const bool isSupportedByWM = connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW)); + const bool isSupportedByWM = connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::Atom_NET_WM_USER_TIME_WINDOW)); if (m_netWmUserTimeWindow || isSupportedByWM) { if (!m_netWmUserTimeWindow) { m_netWmUserTimeWindow = xcb_generate_id(xcb_connection()); @@ -1181,9 +1244,9 @@ void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp) 0, // value mask nullptr); // value list wid = m_netWmUserTimeWindow; - xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW), + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, atom(QXcbAtom::Atom_NET_WM_USER_TIME_WINDOW), XCB_ATOM_WINDOW, 32, 1, &m_netWmUserTimeWindow); - xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_USER_TIME)); + xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_USER_TIME)); QXcbWindow::setWindowTitle(connection(), m_netWmUserTimeWindow, QStringLiteral("Qt NET_WM User Time Window")); @@ -1191,14 +1254,14 @@ void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp) } else if (!isSupportedByWM) { // WM no longer supports it, then we should remove the // _NET_WM_USER_TIME_WINDOW atom. - xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW)); + xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_USER_TIME_WINDOW)); xcb_destroy_window(xcb_connection(), m_netWmUserTimeWindow); m_netWmUserTimeWindow = XCB_NONE; } else { wid = m_netWmUserTimeWindow; } } - xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, wid, atom(QXcbAtom::_NET_WM_USER_TIME), + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, wid, atom(QXcbAtom::Atom_NET_WM_USER_TIME), XCB_ATOM_CARDINAL, 32, 1, ×tamp); } @@ -1273,10 +1336,10 @@ void QXcbWindow::setWindowIconText(const QString &title) xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, - atom(QXcbAtom::_NET_WM_ICON_NAME), - atom(QXcbAtom::UTF8_STRING), + atom(QXcbAtom::Atom_NET_WM_ICON_NAME), + atom(QXcbAtom::AtomUTF8_STRING), 8, - ba.length(), + ba.size(), ba.constData()); } @@ -1307,18 +1370,25 @@ void QXcbWindow::setWindowIcon(const QIcon &icon) } if (!icon_data.isEmpty()) { + // Ignore icon exceeding maximum xcb request length + if (quint64(icon_data.size()) > quint64(xcb_get_maximum_request_length(xcb_connection()))) { + qWarning() << "Ignoring window icon" << icon_data.size() + << "exceeds maximum xcb request length" + << xcb_get_maximum_request_length(xcb_connection()); + return; + } xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, - atom(QXcbAtom::_NET_WM_ICON), - atom(QXcbAtom::CARDINAL), + atom(QXcbAtom::Atom_NET_WM_ICON), + atom(QXcbAtom::AtomCARDINAL), 32, icon_data.size(), (unsigned char *) icon_data.data()); } else { xcb_delete_property(xcb_connection(), m_window, - atom(QXcbAtom::_NET_WM_ICON)); + atom(QXcbAtom::Atom_NET_WM_ICON)); } } @@ -1375,7 +1445,8 @@ void QXcbWindow::propagateSizeHints() qMin(XCOORD_MAX, maximumSize.height())); if (sizeIncrement.width() > 0 || sizeIncrement.height() > 0) { - xcb_icccm_size_hints_set_base_size(&hints, baseSize.width(), baseSize.height()); + if (!baseSize.isNull() && baseSize.isValid()) + xcb_icccm_size_hints_set_base_size(&hints, baseSize.width(), baseSize.height()); xcb_icccm_size_hints_set_resize_inc(&hints, sizeIncrement.width(), sizeIncrement.height()); } @@ -1393,29 +1464,37 @@ void QXcbWindow::requestActivateWindow() return; } - if (!m_mapped) { - m_deferredActivation = true; - return; + { + QMutexLocker locker(&m_mappedMutex); + if (!m_mapped) { + m_deferredActivation = true; + return; + } + m_deferredActivation = false; } - m_deferredActivation = false; updateNetWmUserTime(connection()->time()); QWindow *focusWindow = QGuiApplication::focusWindow(); + xcb_window_t current = XCB_NONE; + if (focusWindow) { + if (QPlatformWindow *pw = focusWindow->handle()) + current = pw->winId(); + } if (window()->isTopLevel() && !(window()->flags() & Qt::X11BypassWindowManagerHint) && (!focusWindow || !window()->isAncestorOf(focusWindow)) - && connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::_NET_ACTIVE_WINDOW))) { + && connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::Atom_NET_ACTIVE_WINDOW))) { xcb_client_message_event_t event; event.response_type = XCB_CLIENT_MESSAGE; event.format = 32; event.sequence = 0; event.window = m_window; - event.type = atom(QXcbAtom::_NET_ACTIVE_WINDOW); + event.type = atom(QXcbAtom::Atom_NET_ACTIVE_WINDOW); event.data.data32[0] = 1; event.data.data32[1] = connection()->time(); - event.data.data32[2] = focusWindow ? focusWindow->winId() : XCB_NONE; + event.data.data32[2] = current; event.data.data32[3] = 0; event.data.data32[4] = 0; @@ -1439,7 +1518,7 @@ QXcbWindow::WindowTypes QXcbWindow::wmWindowTypes() const WindowTypes result; auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(), - 0, m_window, atom(QXcbAtom::_NET_WM_WINDOW_TYPE), + 0, m_window, atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE), XCB_ATOM_ATOM, 0, 1024); if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) { const xcb_atom_t *types = static_cast<const xcb_atom_t *>(xcb_get_property_value(reply.get())); @@ -1447,49 +1526,49 @@ QXcbWindow::WindowTypes QXcbWindow::wmWindowTypes() const for (; types != types_end; types++) { QXcbAtom::Atom type = connection()->qatom(*types); switch (type) { - case QXcbAtom::_NET_WM_WINDOW_TYPE_NORMAL: + case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL: result |= WindowType::Normal; break; - case QXcbAtom::_NET_WM_WINDOW_TYPE_DESKTOP: + case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DESKTOP: result |= WindowType::Desktop; break; - case QXcbAtom::_NET_WM_WINDOW_TYPE_DOCK: + case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DOCK: result |= WindowType::Dock; break; - case QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLBAR: + case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLBAR: result |= WindowType::Toolbar; break; - case QXcbAtom::_NET_WM_WINDOW_TYPE_MENU: + case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_MENU: result |= WindowType::Menu; break; - case QXcbAtom::_NET_WM_WINDOW_TYPE_UTILITY: + case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_UTILITY: result |= WindowType::Utility; break; - case QXcbAtom::_NET_WM_WINDOW_TYPE_SPLASH: + case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_SPLASH: result |= WindowType::Splash; break; - case QXcbAtom::_NET_WM_WINDOW_TYPE_DIALOG: + case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DIALOG: result |= WindowType::Dialog; break; - case QXcbAtom::_NET_WM_WINDOW_TYPE_DROPDOWN_MENU: + case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DROPDOWN_MENU: result |= WindowType::DropDownMenu; break; - case QXcbAtom::_NET_WM_WINDOW_TYPE_POPUP_MENU: + case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_POPUP_MENU: result |= WindowType::PopupMenu; break; - case QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLTIP: + case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLTIP: result |= WindowType::Tooltip; break; - case QXcbAtom::_NET_WM_WINDOW_TYPE_NOTIFICATION: + case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NOTIFICATION: result |= WindowType::Notification; break; - case QXcbAtom::_NET_WM_WINDOW_TYPE_COMBO: + case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_COMBO: result |= WindowType::Combo; break; - case QXcbAtom::_NET_WM_WINDOW_TYPE_DND: + case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DND: result |= WindowType::Dnd; break; - case QXcbAtom::_KDE_NET_WM_WINDOW_TYPE_OVERRIDE: + case QXcbAtom::Atom_KDE_NET_WM_WINDOW_TYPE_OVERRIDE: result |= WindowType::KdeOverride; break; default: @@ -1506,41 +1585,41 @@ void QXcbWindow::setWmWindowType(WindowTypes types, Qt::WindowFlags flags) // manual selection 1 (these are never set by Qt and take precedence) if (types & WindowType::Normal) - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_NORMAL)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL)); if (types & WindowType::Desktop) - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DESKTOP)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DESKTOP)); if (types & WindowType::Dock) - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DOCK)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DOCK)); if (types & WindowType::Notification) - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_NOTIFICATION)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NOTIFICATION)); // manual selection 2 (Qt uses these during auto selection); if (types & WindowType::Utility) - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_UTILITY)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_UTILITY)); if (types & WindowType::Splash) - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_SPLASH)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_SPLASH)); if (types & WindowType::Dialog) - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DIALOG)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DIALOG)); if (types & WindowType::Tooltip) - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLTIP)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLTIP)); if (types & WindowType::KdeOverride) - atoms.append(atom(QXcbAtom::_KDE_NET_WM_WINDOW_TYPE_OVERRIDE)); + atoms.append(atom(QXcbAtom::Atom_KDE_NET_WM_WINDOW_TYPE_OVERRIDE)); // manual selection 3 (these can be set by Qt, but don't have a // corresponding Qt::WindowType). note that order of the *MENU // atoms is important if (types & WindowType::Menu) - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_MENU)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_MENU)); if (types & WindowType::DropDownMenu) - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DROPDOWN_MENU)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DROPDOWN_MENU)); if (types & WindowType::PopupMenu) - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_POPUP_MENU)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_POPUP_MENU)); if (types & WindowType::Toolbar) - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLBAR)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLBAR)); if (types & WindowType::Combo) - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_COMBO)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_COMBO)); if (types & WindowType::Dnd) - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DND)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DND)); // automatic selection Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask)); @@ -1548,41 +1627,41 @@ void QXcbWindow::setWmWindowType(WindowTypes types, Qt::WindowFlags flags) case Qt::Dialog: case Qt::Sheet: if (!(types & WindowType::Dialog)) - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DIALOG)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DIALOG)); break; case Qt::Tool: case Qt::Drawer: if (!(types & WindowType::Utility)) - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_UTILITY)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_UTILITY)); break; case Qt::ToolTip: if (!(types & WindowType::Tooltip)) - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLTIP)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLTIP)); break; case Qt::SplashScreen: if (!(types & WindowType::Splash)) - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_SPLASH)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_SPLASH)); break; default: break; } - if ((flags & Qt::FramelessWindowHint) && !(type & WindowType::KdeOverride)) { + if ((flags & Qt::FramelessWindowHint) && !(types & WindowType::KdeOverride)) { // override netwm type - quick and easy for KDE noborder - atoms.append(atom(QXcbAtom::_KDE_NET_WM_WINDOW_TYPE_OVERRIDE)); + atoms.append(atom(QXcbAtom::Atom_KDE_NET_WM_WINDOW_TYPE_OVERRIDE)); } - if (atoms.size() == 1 && atoms.first() == atom(QXcbAtom::_NET_WM_WINDOW_TYPE_NORMAL)) + if (atoms.size() == 1 && atoms.first() == atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL)) atoms.clear(); else - atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_NORMAL)); + atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL)); if (atoms.isEmpty()) { - xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_WINDOW_TYPE)); + xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE)); } else { xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, - atom(QXcbAtom::_NET_WM_WINDOW_TYPE), XCB_ATOM_ATOM, 32, - atoms.count(), atoms.constData()); + atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE), XCB_ATOM_ATOM, 32, + atoms.size(), atoms.constData()); } xcb_flush(xcb_connection()); } @@ -1591,7 +1670,7 @@ void QXcbWindow::setWindowRole(const QString &role) { QByteArray roleData = role.toLatin1(); xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, - atom(QXcbAtom::WM_WINDOW_ROLE), XCB_ATOM_STRING, 8, + atom(QXcbAtom::AtomWM_WINDOW_ROLE), XCB_ATOM_STRING, 8, roleData.size(), roleData.constData()); } @@ -1613,11 +1692,7 @@ bool QXcbWindow::requestSystemTrayWindowDock() bool QXcbWindow::handleNativeEvent(xcb_generic_event_t *event) { auto eventType = connection()->nativeInterface()->nativeEventType(); -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) qintptr result = 0; // Used only by MS Windows -#else - long result = 0; // Used only by MS Windows -#endif return QWindowSystemInterface::handleNativeEvent(window(), eventType, event, &result); } @@ -1628,7 +1703,7 @@ void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event) bool pending = true; - connection()->eventQueue()->peek(QXcbEventQueue::PeekRemoveMatchContinue, + connection()->eventQueue()->peek(QXcbEventQueue::PeekConsumeMatchAndContinue, [this, &pending](xcb_generic_event_t *event, int type) { if (type != XCB_EXPOSE) return false; @@ -1654,15 +1729,15 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even if (event->format != 32) return; - if (event->type == atom(QXcbAtom::WM_PROTOCOLS)) { + if (event->type == atom(QXcbAtom::AtomWM_PROTOCOLS)) { xcb_atom_t protocolAtom = event->data.data32[0]; - if (protocolAtom == atom(QXcbAtom::WM_DELETE_WINDOW)) { + if (protocolAtom == atom(QXcbAtom::AtomWM_DELETE_WINDOW)) { QWindowSystemInterface::handleCloseEvent(window()); - } else if (protocolAtom == atom(QXcbAtom::WM_TAKE_FOCUS)) { + } else if (protocolAtom == atom(QXcbAtom::AtomWM_TAKE_FOCUS)) { connection()->setTime(event->data.data32[1]); relayFocusToModalWindow(); return; - } else if (protocolAtom == atom(QXcbAtom::_NET_WM_PING)) { + } else if (protocolAtom == atom(QXcbAtom::Atom_NET_WM_PING)) { if (event->window == xcbScreen()->root()) return; @@ -1675,14 +1750,14 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&reply); xcb_flush(xcb_connection()); - } else if (protocolAtom == atom(QXcbAtom::_NET_WM_SYNC_REQUEST)) { + } else if (protocolAtom == atom(QXcbAtom::Atom_NET_WM_SYNC_REQUEST)) { connection()->setTime(event->data.data32[1]); m_syncValue.lo = event->data.data32[2]; m_syncValue.hi = event->data.data32[3]; if (connection()->hasXSync()) m_syncState = SyncReceived; #ifndef QT_NO_WHATSTHIS - } else if (protocolAtom == atom(QXcbAtom::_NET_WM_CONTEXT_HELP)) { + } else if (protocolAtom == atom(QXcbAtom::Atom_NET_WM_CONTEXT_HELP)) { QWindowSystemInterface::handleEnterWhatsThisEvent(); #endif } else { @@ -1690,29 +1765,29 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even connection()->atomName(protocolAtom).constData()); } #if QT_CONFIG(draganddrop) - } else if (event->type == atom(QXcbAtom::XdndEnter)) { + } else if (event->type == atom(QXcbAtom::AtomXdndEnter)) { connection()->drag()->handleEnter(this, event); - } else if (event->type == atom(QXcbAtom::XdndPosition)) { + } else if (event->type == atom(QXcbAtom::AtomXdndPosition)) { connection()->drag()->handlePosition(this, event); - } else if (event->type == atom(QXcbAtom::XdndLeave)) { + } else if (event->type == atom(QXcbAtom::AtomXdndLeave)) { connection()->drag()->handleLeave(this, event); - } else if (event->type == atom(QXcbAtom::XdndDrop)) { + } else if (event->type == atom(QXcbAtom::AtomXdndDrop)) { connection()->drag()->handleDrop(this, event); #endif - } else if (event->type == atom(QXcbAtom::_XEMBED)) { + } else if (event->type == atom(QXcbAtom::Atom_XEMBED)) { handleXEmbedMessage(event); - } else if (event->type == atom(QXcbAtom::_NET_ACTIVE_WINDOW)) { + } else if (event->type == atom(QXcbAtom::Atom_NET_ACTIVE_WINDOW)) { doFocusIn(); - } else if (event->type == atom(QXcbAtom::MANAGER) - || event->type == atom(QXcbAtom::_NET_WM_STATE) - || event->type == atom(QXcbAtom::WM_CHANGE_STATE)) { + } else if (event->type == atom(QXcbAtom::AtomMANAGER) + || event->type == atom(QXcbAtom::Atom_NET_WM_STATE) + || event->type == atom(QXcbAtom::AtomWM_CHANGE_STATE)) { // Ignore _NET_WM_STATE, MANAGER which are relate to tray icons // and other messages. - } else if (event->type == atom(QXcbAtom::_COMPIZ_DECOR_PENDING) - || event->type == atom(QXcbAtom::_COMPIZ_DECOR_REQUEST) - || event->type == atom(QXcbAtom::_COMPIZ_DECOR_DELETE_PIXMAP) - || event->type == atom(QXcbAtom::_COMPIZ_TOOLKIT_ACTION) - || event->type == atom(QXcbAtom::_GTK_LOAD_ICONTHEMES)) { + } else if (event->type == atom(QXcbAtom::Atom_COMPIZ_DECOR_PENDING) + || event->type == atom(QXcbAtom::Atom_COMPIZ_DECOR_REQUEST) + || event->type == atom(QXcbAtom::Atom_COMPIZ_DECOR_DELETE_PIXMAP) + || event->type == atom(QXcbAtom::Atom_COMPIZ_TOOLKIT_ACTION) + || event->type == atom(QXcbAtom::Atom_GTK_LOAD_ICONTHEMES)) { //silence the _COMPIZ and _GTK messages for now } else { qCWarning(lcQpaXcb) << "Unhandled client message: " << connection()->atomName(event->type); @@ -1723,7 +1798,7 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * { bool fromSendEvent = (event->response_type & 0x80); QPoint pos(event->x, event->y); - if (!parent() && !fromSendEvent) { + if (!QPlatformWindow::parent() && !fromSendEvent) { // Do not trust the position, query it instead. auto reply = Q_XCB_REPLY(xcb_translate_coordinates, xcb_connection(), xcb_window(), xcbScreen()->root(), 0, 0); @@ -1734,7 +1809,7 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * } const QRect actualGeometry = QRect(pos, QSize(event->width, event->height)); - QPlatformScreen *newScreen = parent() ? parent()->screen() : screenForGeometry(actualGeometry); + QPlatformScreen *newScreen = QPlatformWindow::parent() ? QPlatformWindow::parent()->screen() : screenForGeometry(actualGeometry); if (!newScreen) return; @@ -1748,7 +1823,7 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * if (!qFuzzyCompare(QHighDpiScaling::factor(newScreen), m_sizeHintsScaleFactor)) propagateSizeHints(); - // Send the synthetic expose event on resize only when the window is shrinked, + // Send the synthetic expose event on resize only when the window is shrunk, // because the "XCB_GRAVITY_NORTH_WEST" flag doesn't send it automatically. if (!m_oldWindowSize.isEmpty() && (actualGeometry.width() < m_oldWindowSize.width() @@ -1810,8 +1885,11 @@ QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event) { if (event->window == m_window) { + m_mappedMutex.lock(); m_mapped = true; - if (m_deferredActivation) + const bool deferredActivation = m_deferredActivation; + m_mappedMutex.unlock(); + if (deferredActivation) requestActivateWindow(); QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); @@ -1821,7 +1899,9 @@ void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event) void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event) { if (event->window == m_window) { + m_mappedMutex.lock(); m_mapped = false; + m_mappedMutex.unlock(); QWindowSystemInterface::handleExposeEvent(window(), QRegion()); } } @@ -1844,7 +1924,7 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in if (m_embedded && !m_trayIconWindow) { if (window() != QGuiApplication::focusWindow()) { - const QXcbWindow *container = static_cast<const QXcbWindow *>(parent()); + const QXcbWindow *container = static_cast<const QXcbWindow *>(QPlatformWindow::parent()); Q_ASSERT(container != nullptr); sendXEmbedMessage(container->xcb_window(), XEMBED_REQUEST_FOCUS); @@ -1888,8 +1968,10 @@ void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x, return; } - if (connection()->buttonState() == Qt::NoButton) + if (connection()->buttonState() == Qt::NoButton) { connection()->setMousePressWindow(nullptr); + m_ignorePressedWindowOnMouseLeave = false; + } handleMouseEvent(timestamp, local, global, modifiers, type, source); } @@ -1909,10 +1991,10 @@ static inline bool doCheckUnGrabAncestor(QXcbConnection *conn) return true; } -static bool ignoreLeaveEvent(quint8 mode, quint8 detail, QXcbConnection *conn = nullptr) +static bool ignoreLeaveEvent(quint8 mode, quint8 detail, QXcbConnection *conn) { return ((doCheckUnGrabAncestor(conn) - && mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) + && mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) || (mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_INFERIOR) || detail == XCB_NOTIFY_DETAIL_VIRTUAL || detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL); @@ -1932,14 +2014,18 @@ void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, in { connection()->setTime(timestamp); - const QPoint global = QPoint(root_x, root_y); - - if (ignoreEnterEvent(mode, detail, connection()) || connection()->mousePressWindow()) + if (ignoreEnterEvent(mode, detail, connection()) + || (connection()->mousePressWindow() && !m_ignorePressedWindowOnMouseLeave)) { return; + } // Updates scroll valuators, as user might have done some scrolling outside our X client. connection()->xi2UpdateScrollingDevices(); + if (mode == XCB_NOTIFY_MODE_UNGRAB && connection()->queryMouseButtons() != Qt::NoButton) + m_ignorePressedWindowOnMouseLeave = true; + + const QPoint global = QPoint(root_x, root_y); const QPoint local(event_x, event_y); QWindowSystemInterface::handleEnterEvent(window(), local, global); } @@ -1949,8 +2035,11 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y, { connection()->setTime(timestamp); - if (ignoreLeaveEvent(mode, detail, connection()) || connection()->mousePressWindow()) + QXcbWindow *mousePressWindow = connection()->mousePressWindow(); + if (ignoreLeaveEvent(mode, detail, connection()) + || (mousePressWindow && !m_ignorePressedWindowOnMouseLeave)) { return; + } // check if enter event is buffered auto event = connection()->eventQueue()->peek([](xcb_generic_event_t *event, int type) { @@ -1968,6 +2057,8 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y, QWindowSystemInterface::handleEnterLeaveEvent(enterWindow->window(), window(), local, global); } else { QWindowSystemInterface::handleLeaveEvent(window()); + if (m_ignorePressedWindowOnMouseLeave) + connection()->setMousePressWindow(nullptr); } free(enter); @@ -2120,6 +2211,7 @@ void QXcbWindow::handleMouseEvent(xcb_timestamp_t time, const QPoint &local, con Qt::KeyboardModifiers modifiers, QEvent::Type type, Qt::MouseEventSource source) { m_lastPointerPosition = local; + m_lastPointerGlobalPosition = global; connection()->setTime(time); Qt::MouseButton button = type == QEvent::MouseMove ? Qt::NoButton : connection()->button(); QWindowSystemInterface::handleMouseEvent(window(), time, local, global, @@ -2143,17 +2235,17 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev const bool propertyDeleted = event->state == XCB_PROPERTY_DELETE; - if (event->atom == atom(QXcbAtom::_NET_WM_STATE) || event->atom == atom(QXcbAtom::WM_STATE)) { + if (event->atom == atom(QXcbAtom::Atom_NET_WM_STATE) || event->atom == atom(QXcbAtom::AtomWM_STATE)) { if (propertyDeleted) return; Qt::WindowStates newState = Qt::WindowNoState; - if (event->atom == atom(QXcbAtom::WM_STATE)) { // WM_STATE: Quick check for 'Minimize'. + if (event->atom == atom(QXcbAtom::AtomWM_STATE)) { // WM_STATE: Quick check for 'Minimize'. auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(), - 0, m_window, atom(QXcbAtom::WM_STATE), + 0, m_window, atom(QXcbAtom::AtomWM_STATE), XCB_ATOM_ANY, 0, 1024); - if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::WM_STATE)) { + if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::AtomWM_STATE)) { const quint32 *data = (const quint32 *)xcb_get_property_value(reply.get()); if (reply->length != 0) m_minimized = (data[0] == XCB_ICCCM_WM_STATE_ICONIC @@ -2183,7 +2275,7 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev connection()->setMouseGrabber(nullptr); } return; - } else if (event->atom == atom(QXcbAtom::_NET_FRAME_EXTENTS)) { + } else if (event->atom == atom(QXcbAtom::Atom_NET_FRAME_EXTENTS)) { m_dirtyFrameMargins = true; } } @@ -2292,7 +2384,7 @@ bool QXcbWindow::windowEvent(QEvent *event) case Qt::BacktabFocusReason: { const QXcbWindow *container = - static_cast<const QXcbWindow *>(parent()); + static_cast<const QXcbWindow *>(QPlatformWindow::parent()); sendXEmbedMessage(container->xcb_window(), focusEvent->reason() == Qt::TabFocusReason ? XEMBED_FOCUS_NEXT : XEMBED_FOCUS_PREV); @@ -2322,23 +2414,22 @@ bool QXcbWindow::startSystemMove() bool QXcbWindow::startSystemMoveResize(const QPoint &pos, int edges) { - const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE); + const xcb_atom_t moveResize = connection()->atom(QXcbAtom::Atom_NET_WM_MOVERESIZE); if (!connection()->wmSupport()->isSupportedByWM(moveResize)) return false; // ### FIXME QTBUG-53389 bool startedByTouch = connection()->startSystemMoveResizeForTouch(m_window, edges); if (startedByTouch) { - if (connection()->isUnity()) { - // Unity fails to move/resize via _NET_WM_MOVERESIZE (WM bug?). - connection()->abortSystemMoveResizeForTouch(); + const QString wmname = connection()->windowManagerName(); + if (wmname != "kwin"_L1 && wmname != "openbox"_L1) { + qCDebug(lcQpaXInputDevices) << "only KDE and OpenBox support startSystemMove/Resize which is triggered from touch events: XDG_CURRENT_DESKTOP=" + << qgetenv("XDG_CURRENT_DESKTOP"); + connection()->abortSystemMoveResize(m_window); return false; } // KWin, Openbox, AwesomeWM and Gnome have been tested to work with _NET_WM_MOVERESIZE. } else { // Started by mouse press. - if (connection()->isUnity()) - return false; // _NET_WM_MOVERESIZE on this WM is bouncy (WM bug?). - doStartSystemMoveResize(mapToGlobal(pos), edges); } @@ -2370,7 +2461,8 @@ static uint qtEdgesToXcbMoveResizeDirection(Qt::Edges edges) void QXcbWindow::doStartSystemMoveResize(const QPoint &globalPos, int edges) { - const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE); + qCDebug(lcQpaXInputDevices) << "triggered system move or resize via sending _NET_WM_MOVERESIZE client message"; + const xcb_atom_t moveResize = connection()->atom(QXcbAtom::Atom_NET_WM_MOVERESIZE); xcb_client_message_event_t xev; xev.response_type = XCB_CLIENT_MESSAGE; xev.type = moveResize; @@ -2389,6 +2481,8 @@ void QXcbWindow::doStartSystemMoveResize(const QPoint &globalPos, int edges) xcb_send_event(connection()->xcb_connection(), false, xcbScreen()->root(), XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, (const char *)&xev); + + connection()->setDuringSystemMoveResize(true); } // Sends an XEmbed message. @@ -2401,7 +2495,7 @@ void QXcbWindow::sendXEmbedMessage(xcb_window_t window, quint32 message, event.format = 32; event.sequence = 0; event.window = window; - event.type = atom(QXcbAtom::_XEMBED); + event.type = atom(QXcbAtom::Atom_XEMBED); event.data.data32[0] = connection()->time(); event.data.data32[1] = message; event.data.data32[2] = detail; @@ -2410,15 +2504,15 @@ void QXcbWindow::sendXEmbedMessage(xcb_window_t window, quint32 message, xcb_send_event(xcb_connection(), false, window, XCB_EVENT_MASK_NO_EVENT, (const char *)&event); } -static bool activeWindowChangeQueued(const QWindow *window) +static bool focusWindowChangeQueued(const QWindow *window) { /* Check from window system event queue if the next queued activation * targets a window other than @window. */ - QWindowSystemInterfacePrivate::ActivatedWindowEvent *systemEvent = - static_cast<QWindowSystemInterfacePrivate::ActivatedWindowEvent *> - (QWindowSystemInterfacePrivate::peekWindowSystemEvent(QWindowSystemInterfacePrivate::ActivatedWindow)); - return systemEvent && systemEvent->activated != window; + QWindowSystemInterfacePrivate::FocusWindowEvent *systemEvent = + static_cast<QWindowSystemInterfacePrivate::FocusWindowEvent *> + (QWindowSystemInterfacePrivate::peekWindowSystemEvent(QWindowSystemInterfacePrivate::FocusWindow)); + return systemEvent && systemEvent->focused != window; } void QXcbWindow::handleXEmbedMessage(const xcb_client_message_event_t *event) @@ -2448,13 +2542,13 @@ void QXcbWindow::handleXEmbedMessage(const xcb_client_message_event_t *event) break; } connection()->setFocusWindow(window()); - QWindowSystemInterface::handleWindowActivated(window(), reason); + QWindowSystemInterface::handleFocusWindowChanged(window(), reason); break; case XEMBED_FOCUS_OUT: if (window() == QGuiApplication::focusWindow() - && !activeWindowChangeQueued(window())) { + && !focusWindowChangeQueued(window())) { connection()->setFocusWindow(nullptr); - QWindowSystemInterface::handleWindowActivated(nullptr); + QWindowSystemInterface::handleFocusWindowChanged(nullptr); } break; } @@ -2480,7 +2574,7 @@ void QXcbWindow::setOpacity(qreal level) xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, - atom(QXcbAtom::_NET_WM_WINDOW_OPACITY), + atom(QXcbAtom::Atom_NET_WM_WINDOW_OPACITY), XCB_ATOM_CARDINAL, 32, 1, @@ -2518,7 +2612,7 @@ void QXcbWindow::setAlertState(bool enabled) m_alertState = enabled; - setNetWmState(enabled, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)); + setNetWmState(enabled, atom(QXcbAtom::Atom_NET_WM_STATE_DEMANDS_ATTENTION)); } uint QXcbWindow::visualId() const @@ -2552,10 +2646,10 @@ void QXcbWindow::setWindowTitle(const QXcbConnection *conn, xcb_window_t window, xcb_change_property(conn->xcb_connection(), XCB_PROP_MODE_REPLACE, window, - conn->atom(QXcbAtom::_NET_WM_NAME), - conn->atom(QXcbAtom::UTF8_STRING), + conn->atom(QXcbAtom::Atom_NET_WM_NAME), + conn->atom(QXcbAtom::AtomUTF8_STRING), 8, - ba.length(), + ba.size(), ba.constData()); #if QT_CONFIG(xcb_xlib) @@ -2569,9 +2663,9 @@ void QXcbWindow::setWindowTitle(const QXcbConnection *conn, xcb_window_t window, QString QXcbWindow::windowTitle(const QXcbConnection *conn, xcb_window_t window) { - const xcb_atom_t utf8Atom = conn->atom(QXcbAtom::UTF8_STRING); + const xcb_atom_t utf8Atom = conn->atom(QXcbAtom::AtomUTF8_STRING); auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, conn->xcb_connection(), - false, window, conn->atom(QXcbAtom::_NET_WM_NAME), + false, window, conn->atom(QXcbAtom::Atom_NET_WM_NAME), utf8Atom, 0, 1024); if (reply && reply->format == 8 && reply->type == utf8Atom) { const char *name = reinterpret_cast<const char *>(xcb_get_property_value(reply.get())); @@ -2579,7 +2673,7 @@ QString QXcbWindow::windowTitle(const QXcbConnection *conn, xcb_window_t window) } reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, conn->xcb_connection(), - false, window, conn->atom(QXcbAtom::WM_NAME), + false, window, conn->atom(QXcbAtom::AtomWM_NAME), XCB_ATOM_STRING, 0, 1024); if (reply && reply->format == 8 && reply->type == XCB_ATOM_STRING) { const char *name = reinterpret_cast<const char *>(xcb_get_property_value(reply.get())); |