From ea7277690d9f4a7c4e10f3d3b7a2bef46d6878c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Thu, 19 May 2011 10:51:34 +0200 Subject: [PATCH] Better setWindowFlags() support in XCB window. We need to re-create the native window in setParent, as used to be done in QWidgetPrivate::setParent_sys in qwidget_x11.cpp. --- src/gui/kernel/qwindow.cpp | 3 - src/plugins/platforms/xcb/qxcbscreen.cpp | 20 +++++ src/plugins/platforms/xcb/qxcbscreen.h | 3 + src/plugins/platforms/xcb/qxcbwindow.cpp | 100 ++++++++++++++--------- src/plugins/platforms/xcb/qxcbwindow.h | 7 +- src/widgets/kernel/qwidget_qpa.cpp | 16 ++-- 6 files changed, 100 insertions(+), 49 deletions(-) diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 121791d2f3..3ff7d6c998 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -127,9 +127,6 @@ void QWindow::setParent(QWindow *parent) { Q_D(QWindow); - if (d->parentWindow == parent) - return; - QObject::setParent(parent); if (d->platformWindow) { diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 1c12ee3059..851a781d6c 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -102,6 +102,26 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int num free(reply); m_syncRequestSupported = m_windowManagerName != QLatin1String("KWin"); + + m_clientLeader = xcb_generate_id(xcb_connection()); + Q_XCB_CALL2(xcb_create_window(xcb_connection(), + XCB_COPY_FROM_PARENT, + m_clientLeader, + m_screen->root, + 0, 0, 1, 1, + 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + m_screen->root_visual, + 0, 0), connection); + + Q_XCB_CALL2(xcb_change_property(xcb_connection(), + XCB_PROP_MODE_REPLACE, + m_clientLeader, + atom(QXcbAtom::WM_CLIENT_LEADER), + XCB_ATOM_WINDOW, + 32, + 1, + &m_clientLeader), connection); } QXcbScreen::~QXcbScreen() diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index 9547d016b7..8efafb35bc 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -67,6 +67,8 @@ public: xcb_screen_t *screen() const { return m_screen; } xcb_window_t root() const { return m_screen->root; } + xcb_window_t clientLeader() const { return m_clientLeader; } + QString windowManagerName() const { return m_windowManagerName; } bool syncRequestSupported() const { return m_syncRequestSupported; } @@ -75,6 +77,7 @@ private: int m_number; QString m_windowManagerName; bool m_syncRequestSupported; + xcb_window_t m_clientLeader; }; #endif diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 35c9efc1d9..074fdafe87 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -89,17 +89,35 @@ static inline bool isTransient(const QWindow *w) QXcbWindow::QXcbWindow(QWindow *window) : QPlatformWindow(window) + , m_window(0) , m_context(0) - , m_windowState(Qt::WindowNoState) + , m_syncCounter(0) { m_screen = static_cast(QGuiApplicationPrivate::platformIntegration()->screens().at(0)); setConnection(m_screen->connection()); - const quint32 mask = XCB_CW_BACK_PIXMAP | XCB_CW_EVENT_MASK; + create(); +} + +void QXcbWindow::create() +{ + bool wasCreated = (m_window != 0); + destroy(); + + m_windowState = Qt::WindowNoState; + m_hasReceivedSyncRequest = false; + + Qt::WindowType type = window()->windowType(); + + const quint32 mask = XCB_CW_BACK_PIXMAP | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER | XCB_CW_EVENT_MASK; const quint32 values[] = { // XCB_CW_BACK_PIXMAP XCB_NONE, + // XCB_CW_OVERRIDE_REDIRECT + type == Qt::Popup, + // XCB_CW_SAVE_UNDER + type == Qt::Popup || type == Qt::Tool || type == Qt::SplashScreen || type == Qt::ToolTip || type == Qt::Drawer, // XCB_CW_EVENT_MASK XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY @@ -115,21 +133,21 @@ QXcbWindow::QXcbWindow(QWindow *window) | XCB_EVENT_MASK_FOCUS_CHANGE }; - QRect rect = window->geometry(); + QRect rect = window()->geometry(); xcb_window_t xcb_parent_id = m_screen->root(); - if (parent() && !window->isTopLevel()) + if (parent() && !window()->isTopLevel()) xcb_parent_id = static_cast(parent())->xcb_window(); #if defined(XCB_USE_GLX) || defined(XCB_USE_EGL) - if (window->surfaceType() == QWindow::OpenGLSurface + if (window()->surfaceType() == QWindow::OpenGLSurface && QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) { #if defined(XCB_USE_GLX) - XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen),m_screen->screenNumber(), window->requestedWindowFormat()); + XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen),m_screen->screenNumber(), window()->requestedWindowFormat()); #elif defined(XCB_USE_EGL) EGLDisplay eglDisplay = connection()->egl_display(); - EGLConfig eglConfig = q_configFromQPlatformWindowFormat(eglDisplay,window->requestedWindowFormat(),true); + EGLConfig eglConfig = q_configFromQPlatformWindowFormat(eglDisplay,window()->requestedWindowFormat(),true); VisualID id = QXlibEglIntegration::getCompatibleVisualId(DISPLAY_FROM_XCB(this), eglDisplay, eglConfig); XVisualInfo visualInfoTemplate; @@ -149,7 +167,7 @@ QXcbWindow::QXcbWindow(QWindow *window) 0, visualInfo->depth, InputOutput, visualInfo->visual, CWColormap, &a); - printf("created GL window: %d\n", m_window); + printf("created GL window: %x\n", m_window); } else { qFatal("no window!"); } @@ -172,7 +190,7 @@ QXcbWindow::QXcbWindow(QWindow *window) 0, // value mask 0)); // value list - printf("created regular window: %d\n", m_window); + printf("created regular window: %x\n", m_window); } connection()->addWindow(m_window, this); @@ -188,7 +206,7 @@ QXcbWindow::QXcbWindow(QWindow *window) if (m_screen->syncRequestSupported()) properties[propertyCount++] = atom(QXcbAtom::_NET_WM_SYNC_REQUEST); - if (window->windowFlags() & Qt::WindowContextHelpButtonHint) + if (window()->windowFlags() & Qt::WindowContextHelpButtonHint) properties[propertyCount++] = atom(QXcbAtom::_NET_WM_CONTEXT_HELP); Q_XCB_CALL(xcb_change_property(xcb_connection(), @@ -221,15 +239,36 @@ QXcbWindow::QXcbWindow(QWindow *window) Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, atom(QXcbAtom::_NET_WM_PID), XCB_ATOM_CARDINAL, 32, 1, &pid)); + + xcb_wm_hints_t hints; + memset(&hints, 0, sizeof(hints)); + xcb_wm_hints_set_normal(&hints); + + xcb_set_wm_hints(xcb_connection(), m_window, &hints); + + xcb_window_t leader = m_screen->clientLeader(); + Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + atom(QXcbAtom::WM_CLIENT_LEADER), XCB_ATOM_WINDOW, 32, + 1, &leader)); + + if (wasCreated) + setWindowFlags(window()->windowFlags()); } QXcbWindow::~QXcbWindow() +{ + destroy(); +} + +void QXcbWindow::destroy() { delete m_context; - if (m_screen->syncRequestSupported()) + if (m_syncCounter && m_screen->syncRequestSupported()) Q_XCB_CALL(xcb_sync_destroy_counter(xcb_connection(), m_syncCounter)); - connection()->removeWindow(m_window); - Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window)); + if (m_window) { + connection()->removeWindow(m_window); + Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window)); + } } void QXcbWindow::setGeometry(const QRect &rect) @@ -468,27 +507,20 @@ Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags) { Qt::WindowType type = static_cast(int(flags & Qt::WindowType_Mask)); - setNetWmWindowTypes(flags); - if (type == Qt::ToolTip) flags |= Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint; if (type == Qt::Popup) flags |= Qt::X11BypassWindowManagerHint; - bool topLevel = (flags & Qt::Window); - bool popup = (type == Qt::Popup); - bool dialog = (type == Qt::Dialog - || type == Qt::Sheet); - bool desktop = (type == Qt::Desktop); - bool tool = (type == Qt::Tool || type == Qt::SplashScreen - || type == Qt::ToolTip || type == Qt::Drawer); + setNetWmWindowFlags(flags); + setMotifWindowFlags(flags); - Q_UNUSED(topLevel); - Q_UNUSED(dialog); - Q_UNUSED(desktop); - Q_UNUSED(tool); + return flags; +} - bool tooltip = (type == Qt::ToolTip); +void QXcbWindow::setMotifWindowFlags(Qt::WindowFlags flags) +{ + Qt::WindowType type = static_cast(int(flags & Qt::WindowType_Mask)); QtMotifWmHints mwmhints; mwmhints.flags = 0L; @@ -551,15 +583,6 @@ Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags) } setMotifWmHints(connection(), m_window, mwmhints); - - if (popup || tooltip) { - const quint32 mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER; - const quint32 values[] = { true, true }; - - Q_XCB_CALL(xcb_change_window_attributes(xcb_connection(), m_window, mask, values)); - } - - return flags; } void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two) @@ -640,7 +663,7 @@ Qt::WindowState QXcbWindow::setWindowState(Qt::WindowState state) return m_windowState; } -void QXcbWindow::setNetWmWindowTypes(Qt::WindowFlags flags) +void QXcbWindow::setNetWmWindowFlags(Qt::WindowFlags flags) { // in order of decreasing priority QVector windowTypes; @@ -767,6 +790,9 @@ WId QXcbWindow::winId() const void QXcbWindow::setParent(const QPlatformWindow *parent) { + // re-create for compatibility + create(); + QPoint topLeft = geometry().topLeft(); xcb_window_t xcb_parent_id = parent ? static_cast(parent)->xcb_window() : m_screen->root(); diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 9996188714..a6ca3de565 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -94,15 +94,20 @@ public: void updateSyncRequestCounter(); private: - void setNetWmWindowTypes(Qt::WindowFlags flags); void changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two = 0); QVector getNetWmState(); void setNetWmState(const QVector &atoms); void printNetWmState(const QVector &state); + void setNetWmWindowFlags(Qt::WindowFlags flags); + void setMotifWindowFlags(Qt::WindowFlags flags); + void updateMotifWmHintsBeforeMap(); void updateNetWmStateBeforeMap(); + void create(); + void destroy(); + void show(); void hide(); diff --git a/src/widgets/kernel/qwidget_qpa.cpp b/src/widgets/kernel/qwidget_qpa.cpp index a4c68c16a5..6721fdbb6a 100644 --- a/src/widgets/kernel/qwidget_qpa.cpp +++ b/src/widgets/kernel/qwidget_qpa.cpp @@ -93,13 +93,14 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO QWindow *win = topData()->window; + win->setWindowFlags(data.window_flags); + win->setGeometry(q->geometry()); + if (QWidget *nativeParent = q->nativeParentWidget()) { if (nativeParent->windowHandle()) win->setParent(nativeParent->windowHandle()); } - win->setWindowFlags(data.window_flags); - win->setGeometry(q->geometry()); win->create(); data.window_flags = win->windowFlags(); @@ -174,13 +175,12 @@ void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f) if (parent != newparent) { QObjectPrivate::setParent_helper(newparent); //### why does this have to be done in the _sys function??? - if (q->windowHandle() && newparent) { - QWidget * parentWithWindow = newparent->windowHandle()? newparent : newparent->nativeParentWidget(); - if (parentWithWindow && parentWithWindow->windowHandle()) { - q->windowHandle()->setParent(parentWithWindow->windowHandle()); - } + if (q->windowHandle()) { + q->windowHandle()->setWindowFlags(f); + QWidget *parentWithWindow = + newparent ? (newparent->windowHandle() ? newparent : newparent->nativeParentWidget()) : 0; + q->windowHandle()->setParent(parentWithWindow ? parentWithWindow->windowHandle() : 0); } - } if (!newparent) {