From 516f4e283ba4626d7239630397ef867ab0366071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Wed, 18 May 2011 09:32:17 +0200 Subject: Add QWindow::setWindowModality(). Also set corresponding window manager hints in xcb plugin. --- src/gui/kernel/qwindow.cpp | 18 ++++ src/gui/kernel/qwindow.h | 4 +- src/gui/kernel/qwindow_p.h | 2 + src/plugins/platforms/xcb/qxcbwindow.cpp | 136 ++++++++++++++++++++++++++---- src/plugins/platforms/xcb/qxcbwindow.h | 2 + src/widgets/kernel/qwidget_qpa.cpp | 6 +- src/widgets/platforms/x11/qwidget_x11.cpp | 2 +- 7 files changed, 151 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 3b01a0d352..121791d2f3 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -152,6 +152,24 @@ bool QWindow::isTopLevel() const return d->windowFlags & Qt::Window; } +bool QWindow::isModal() const +{ + Q_D(const QWindow); + return d->modality != Qt::NonModal; +} + +Qt::WindowModality QWindow::windowModality() const +{ + Q_D(const QWindow); + return d->modality; +} + +void QWindow::setWindowModality(Qt::WindowModality windowModality) +{ + Q_D(QWindow); + d->modality = windowModality; +} + void QWindow::setWindowFormat(const QWindowFormat &format) { Q_D(QWindow); diff --git a/src/gui/kernel/qwindow.h b/src/gui/kernel/qwindow.h index 22dbf48538..de4e414703 100644 --- a/src/gui/kernel/qwindow.h +++ b/src/gui/kernel/qwindow.h @@ -96,7 +96,9 @@ public: bool isTopLevel() const; - QWindow *topLevelWindow() const; + bool isModal() const; + Qt::WindowModality windowModality() const; + void setWindowModality(Qt::WindowModality windowModality); void setWindowFormat(const QWindowFormat &format); QWindowFormat requestedWindowFormat() const; diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index 215a18d27e..f52dd559f1 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -92,6 +92,8 @@ public: QSize maximumSize; QSize baseSize; QSize sizeIncrement; + + Qt::WindowModality modality; }; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 7942e46c1d..eeec59c868 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -253,8 +253,15 @@ void QXcbWindow::show() if (window()->isTopLevel()) { xcb_get_property_cookie_t cookie = xcb_get_wm_hints(xcb_connection(), m_window); + xcb_generic_error_t *error; + xcb_wm_hints_t hints; - xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, 0); + xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, &error); + + if (error) { + connection()->handleXcbError(error); + free(error); + } if (window()->windowState() & Qt::WindowMinimized) xcb_wm_hints_set_iconic(&hints); @@ -276,6 +283,9 @@ void QXcbWindow::show() XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32, 1, &parentWindow)); } + + // update _MOTIF_WM_HINTS + updateMotifWmHintsBeforeShow(); } Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window)); @@ -299,7 +309,7 @@ void QXcbWindow::hide() xcb_flush(xcb_connection()); } -struct QtMWMHints { +struct QtMotifWmHints { quint32 flags, functions, decorations; qint32 input_mode; quint32 status; @@ -332,6 +342,53 @@ enum { MWM_INPUT_FULL_APPLICATION_MODAL = 3L }; +static QtMotifWmHints getMotifWmHints(QXcbConnection *c, xcb_window_t window) +{ + QtMotifWmHints hints; + + xcb_get_property_cookie_t get_cookie = + xcb_get_property(c->xcb_connection(), 0, window, c->atom(QXcbAtom::_MOTIF_WM_HINTS), + c->atom(QXcbAtom::_MOTIF_WM_HINTS), 0, 20); + + xcb_generic_error_t *error; + + xcb_get_property_reply_t *reply = + xcb_get_property_reply(c->xcb_connection(), get_cookie, &error); + + if (reply && reply->format == 32 && reply->type == c->atom(QXcbAtom::_MOTIF_WM_HINTS)) { + hints = *((QtMotifWmHints *)xcb_get_property_value(reply)); + } else if (error) { + c->handleXcbError(error); + free(error); + + hints.flags = 0L; + hints.functions = MWM_FUNC_ALL; + hints.decorations = MWM_DECOR_ALL; + hints.input_mode = 0L; + hints.status = 0L; + } + + free(reply); + + return hints; +} + +static void setMotifWmHints(QXcbConnection *c, xcb_window_t window, const QtMotifWmHints &hints) +{ + if (hints.flags != 0l) { + Q_XCB_CALL2(xcb_change_property(c->xcb_connection(), + XCB_PROP_MODE_REPLACE, + window, + c->atom(QXcbAtom::_MOTIF_WM_HINTS), + c->atom(QXcbAtom::_MOTIF_WM_HINTS), + 32, + 5, + &hints), c); + } else { + Q_XCB_CALL2(xcb_delete_property(c->xcb_connection(), window, c->atom(QXcbAtom::_MOTIF_WM_HINTS)), c); + } +} + Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags) { Qt::WindowType type = static_cast(int(flags & Qt::WindowType_Mask)); @@ -358,7 +415,7 @@ Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags) bool tooltip = (type == Qt::ToolTip); - QtMWMHints mwmhints; + QtMotifWmHints mwmhints; mwmhints.flags = 0L; mwmhints.functions = 0L; mwmhints.decorations = 0; @@ -418,18 +475,7 @@ Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags) mwmhints.decorations = 0; } - if (mwmhints.flags != 0l) { - Q_XCB_CALL(xcb_change_property(xcb_connection(), - XCB_PROP_MODE_REPLACE, - m_window, - atom(QXcbAtom::_MOTIF_WM_HINTS), - atom(QXcbAtom::_MOTIF_WM_HINTS), - 32, - 5, - &mwmhints)); - } else { - Q_XCB_CALL(xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_MOTIF_WM_HINTS))); - } + setMotifWmHints(connection(), m_window, mwmhints); if (popup || tooltip) { const quint32 mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER; @@ -555,6 +601,62 @@ void QXcbWindow::setNetWmWindowTypes(Qt::WindowFlags flags) windowTypes.count(), windowTypes.constData())); } +void QXcbWindow::updateMotifWmHintsBeforeShow() +{ + QtMotifWmHints mwmhints = getMotifWmHints(connection(), m_window); + + if (window()->windowModality() != Qt::NonModal) { + switch (window()->windowModality()) { + case Qt::WindowModal: + mwmhints.input_mode = MWM_INPUT_PRIMARY_APPLICATION_MODAL; + break; + case Qt::ApplicationModal: + default: + mwmhints.input_mode = MWM_INPUT_FULL_APPLICATION_MODAL; + break; + } + mwmhints.flags |= MWM_HINTS_INPUT_MODE; + } else { + mwmhints.input_mode = MWM_INPUT_MODELESS; + mwmhints.flags &= ~MWM_HINTS_INPUT_MODE; + } + + if (window()->minimumSize() == window()->maximumSize()) { + // fixed size, remove the resize handle (since mwm/dtwm + // isn't smart enough to do it itself) + mwmhints.flags |= MWM_HINTS_FUNCTIONS; + if (mwmhints.functions == MWM_FUNC_ALL) { + mwmhints.functions = MWM_FUNC_MOVE; + } else { + mwmhints.functions &= ~MWM_FUNC_RESIZE; + } + + if (mwmhints.decorations == MWM_DECOR_ALL) { + mwmhints.flags |= MWM_HINTS_DECORATIONS; + mwmhints.decorations = (MWM_DECOR_BORDER + | MWM_DECOR_TITLE + | MWM_DECOR_MENU); + } else { + mwmhints.decorations &= ~MWM_DECOR_RESIZEH; + } + } + + if (window()->windowFlags() & Qt::WindowMinimizeButtonHint) { + mwmhints.flags |= MWM_HINTS_DECORATIONS; + mwmhints.decorations |= MWM_DECOR_MINIMIZE; + mwmhints.functions |= MWM_FUNC_MINIMIZE; + } + if (window()->windowFlags() & Qt::WindowMaximizeButtonHint) { + mwmhints.flags |= MWM_HINTS_DECORATIONS; + mwmhints.decorations |= MWM_DECOR_MAXIMIZE; + mwmhints.functions |= MWM_FUNC_MAXIMIZE; + } + if (window()->windowFlags() & Qt::WindowCloseButtonHint) + mwmhints.functions |= MWM_FUNC_CLOSE; + + setMotifWmHints(connection(), m_window, mwmhints); +} + WId QXcbWindow::winId() const { return m_window; @@ -563,7 +665,9 @@ WId QXcbWindow::winId() const void QXcbWindow::setParent(const QPlatformWindow *parent) { QPoint topLeft = geometry().topLeft(); - Q_XCB_CALL(xcb_reparent_window(xcb_connection(), xcb_window(), static_cast(parent)->xcb_window(), topLeft.x(), topLeft.y())); + + xcb_window_t xcb_parent_id = parent ? static_cast(parent)->xcb_window() : m_screen->root(); + Q_XCB_CALL(xcb_reparent_window(xcb_connection(), xcb_window(), xcb_parent_id, topLeft.x(), topLeft.y())); } void QXcbWindow::setWindowTitle(const QString &title) diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index accb32b36e..9827a808cc 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -97,6 +97,8 @@ private: void setNetWmWindowTypes(Qt::WindowFlags flags); void changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two = 0); + void updateMotifWmHintsBeforeShow(); + void show(); void hide(); diff --git a/src/widgets/kernel/qwidget_qpa.cpp b/src/widgets/kernel/qwidget_qpa.cpp index e6a55968f9..a4c68c16a5 100644 --- a/src/widgets/kernel/qwidget_qpa.cpp +++ b/src/widgets/kernel/qwidget_qpa.cpp @@ -763,7 +763,8 @@ void QWidgetPrivate::updateFrameStrut() void QWidgetPrivate::setWindowOpacity_sys(qreal level) { Q_Q(QWidget); - q->windowHandle()->setOpacity(level); + if (q->windowHandle()) + q->windowHandle()->setOpacity(level); } void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect) @@ -788,6 +789,9 @@ QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys() void QWidgetPrivate::setModal_sys() { + Q_Q(QWidget); + if (q->windowHandle()) + q->windowHandle()->setWindowModality(q->windowModality()); } #ifndef QT_NO_CURSOR diff --git a/src/widgets/platforms/x11/qwidget_x11.cpp b/src/widgets/platforms/x11/qwidget_x11.cpp index 3eec5c7331..12f4e2f856 100644 --- a/src/widgets/platforms/x11/qwidget_x11.cpp +++ b/src/widgets/platforms/x11/qwidget_x11.cpp @@ -134,7 +134,7 @@ enum { }; -static QtMWMHints GetMWMHints(Display *display, Window window) +static QtMWMHints getMWMHints(Display *display, Window window) { QtMWMHints mwmhints; -- cgit v1.2.3