From 850b602c7a72635eb37a998089ee085d5d505c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Fri, 13 May 2011 11:51:41 +0200 Subject: Initial QPlatformWindow window state setting API and xcb implementation. --- src/gui/kernel/qplatformwindow_qpa.cpp | 11 +++++ src/gui/kernel/qplatformwindow_qpa.h | 2 + src/gui/kernel/qwindow.cpp | 22 ++++++--- src/gui/kernel/qwindow.h | 4 +- src/gui/kernel/qwindow_p.h | 2 + src/plugins/platforms/xcb/qxcbwindow.cpp | 79 ++++++++++++++++++++++++++++++++ src/plugins/platforms/xcb/qxcbwindow.h | 3 ++ src/widgets/kernel/qwidget_qpa.cpp | 50 +++++++++++--------- 8 files changed, 144 insertions(+), 29 deletions(-) diff --git a/src/gui/kernel/qplatformwindow_qpa.cpp b/src/gui/kernel/qplatformwindow_qpa.cpp index 24c337cf57..d7d1d96f42 100644 --- a/src/gui/kernel/qplatformwindow_qpa.cpp +++ b/src/gui/kernel/qplatformwindow_qpa.cpp @@ -116,6 +116,17 @@ Qt::WindowFlags QPlatformWindow::setWindowFlags(Qt::WindowFlags flags) return flags; } +/*! + Requests setting the window state of this surface + to \a type. Returns the actual state set. + + Qt::WindowActive can be ignored. +*/ +Qt::WindowState QPlatformWindow::setWindowState(Qt::WindowState) +{ + return Qt::WindowNoState; +} + /*! Reimplement in subclasses to return a handle to the native window */ diff --git a/src/gui/kernel/qplatformwindow_qpa.h b/src/gui/kernel/qplatformwindow_qpa.h index 1730f3d85e..c74e96695d 100644 --- a/src/gui/kernel/qplatformwindow_qpa.h +++ b/src/gui/kernel/qplatformwindow_qpa.h @@ -71,6 +71,8 @@ public: virtual void setVisible(bool visible); virtual Qt::WindowFlags setWindowFlags(Qt::WindowFlags flags); + virtual Qt::WindowState setWindowState(Qt::WindowState state); + virtual WId winId() const; virtual void setParent(const QPlatformWindow *window); diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 7faf49395a..897b370cf5 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -89,6 +89,8 @@ void QWindow::create() d->windowFlags = d->platformWindow->setWindowFlags(d->windowFlags); if (!d->windowTitle.isNull()) d->platformWindow->setWindowTitle(d->windowTitle); + if (d->windowState != Qt::WindowNoState) + d->windowState = d->platformWindow->setWindowState(d->windowState); QObjectList childObjects = children(); for (int i = 0; i < childObjects.size(); i ++) { @@ -232,16 +234,24 @@ void QWindow::requestActivateWindow() } } -Qt::WindowStates QWindow::windowState() const +Qt::WindowState QWindow::windowState() const { - qDebug() << "unimplemented:" << __FILE__ << __LINE__; - return Qt::WindowNoState; + Q_D(const QWindow); + return d->windowState; } -void QWindow::setWindowState(Qt::WindowStates state) +void QWindow::setWindowState(Qt::WindowState state) { - Q_UNUSED(state); - qDebug() << "unimplemented:" << __FILE__ << __LINE__; + if (state == Qt::WindowActive) { + requestActivateWindow(); + return; + } + + Q_D(QWindow); + if (d->platformWindow) + d->windowState = d->platformWindow->setWindowState(state); + else + d->windowState = state; } QSize QWindow::minimumSize() const diff --git a/src/gui/kernel/qwindow.h b/src/gui/kernel/qwindow.h index f2fde2d532..70227106b1 100644 --- a/src/gui/kernel/qwindow.h +++ b/src/gui/kernel/qwindow.h @@ -111,8 +111,8 @@ public: void setOpacity(qreal level); void requestActivateWindow(); - Qt::WindowStates windowState() const; - void setWindowState(Qt::WindowStates state); + Qt::WindowState windowState() const; + void setWindowState(Qt::WindowState state); QSize minimumSize() const; QSize maximumSize() const; diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index 6f1038e8c4..b6227741ba 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -64,6 +64,7 @@ public: , visible(false) , glContext(0) , surface(0) + , windowState(Qt::WindowNoState) { isWindow = true; } @@ -82,6 +83,7 @@ public: QRect geometry; QWindowContext *glContext; QWindowSurface *surface; + Qt::WindowState windowState; }; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index f6d9c2f762..dd28d13eb5 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -90,6 +90,7 @@ static inline bool isTransient(const QWidget *w) QXcbWindow::QXcbWindow(QWindow *window) : QPlatformWindow(window) , m_context(0) + , m_windowState(Qt::WindowNoState) { m_screen = static_cast(QGuiApplicationPrivate::platformIntegration()->screens().at(0)); @@ -424,6 +425,84 @@ Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags) return flags; } +void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two) +{ + xcb_client_message_event_t event; + + event.response_type = XCB_CLIENT_MESSAGE; + event.format = 32; + event.window = m_window; + event.type = atom(QXcbAtom::_NET_WM_STATE); + event.data.data32[0] = set ? 1 : 0; + event.data.data32[1] = one; + event.data.data32[2] = two; + event.data.data32[3] = 0; + event.data.data32[4] = 0; + + Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event)); +} + +Qt::WindowState QXcbWindow::setWindowState(Qt::WindowState state) +{ + if (state == m_windowState) + return state; + + // unset old state + switch (m_windowState) { + case Qt::WindowMinimized: + Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window)); + break; + case Qt::WindowMaximized: + changeNetWmState(false, + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ), + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); + break; + case Qt::WindowFullScreen: + changeNetWmState(false, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); + break; + default: + break; + } + + // set new state + switch (state) { + case Qt::WindowMinimized: + { + xcb_client_message_event_t event; + + event.response_type = XCB_CLIENT_MESSAGE; + event.format = 32; + event.window = m_window; + event.type = atom(QXcbAtom::WM_CHANGE_STATE); + event.data.data32[0] = XCB_WM_STATE_ICONIC; + event.data.data32[1] = 0; + event.data.data32[2] = 0; + event.data.data32[3] = 0; + event.data.data32[4] = 0; + + Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event)); + } + break; + case Qt::WindowMaximized: + changeNetWmState(true, + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ), + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); + break; + case Qt::WindowFullScreen: + changeNetWmState(true, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); + break; + case Qt::WindowNoState: + break; + default: + break; + } + + connection()->sync(); + + m_windowState = state; + return m_windowState; +} + void QXcbWindow::setNetWmWindowTypes(Qt::WindowFlags flags) { // in order of decreasing priority diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 3ed58b33d3..831c25bdfb 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -62,6 +62,7 @@ public: void setVisible(bool visible); Qt::WindowFlags setWindowFlags(Qt::WindowFlags flags); + Qt::WindowState setWindowState(Qt::WindowState state); WId winId() const; void setParent(const QPlatformWindow *window); @@ -93,6 +94,7 @@ public: private: void setNetWmWindowTypes(Qt::WindowFlags flags); + void changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two = 0); QXcbScreen *m_screen; @@ -103,6 +105,7 @@ private: xcb_sync_counter_t m_syncCounter; bool m_hasReceivedSyncRequest; + Qt::WindowState m_windowState; }; #endif diff --git a/src/widgets/kernel/qwidget_qpa.cpp b/src/widgets/kernel/qwidget_qpa.cpp index f6833915ec..b7b502a35f 100644 --- a/src/widgets/kernel/qwidget_qpa.cpp +++ b/src/widgets/kernel/qwidget_qpa.cpp @@ -443,7 +443,7 @@ void QWidgetPrivate::setFullScreenSize_helper() data.in_set_window_state = old_state; } -static Qt::WindowStates effectiveState(Qt::WindowStates state) +static Qt::WindowState effectiveState(Qt::WindowStates state) { if (state & Qt::WindowMinimized) return Qt::WindowMinimized; @@ -466,8 +466,8 @@ void QWidget::setWindowState(Qt::WindowStates newstate) data->window_state = newstate; data->in_set_window_state = 1; bool needShow = false; - Qt::WindowStates newEffectiveState = effectiveState(newstate); - Qt::WindowStates oldEffectiveState = effectiveState(oldstate); + Qt::WindowState newEffectiveState = effectiveState(newstate); + Qt::WindowState oldEffectiveState = effectiveState(oldstate); if (isWindow() && newEffectiveState != oldEffectiveState) { d->createTLExtra(); if (oldEffectiveState == Qt::WindowNoState) { //normal @@ -479,24 +479,32 @@ void QWidget::setWindowState(Qt::WindowStates newstate) needShow = true; } - if (newEffectiveState == Qt::WindowMinimized) { - //### not ideal... - hide(); - needShow = false; - } else if (newEffectiveState == Qt::WindowFullScreen) { - d->topData()->savedFlags = windowFlags(); - setParent(0, Qt::FramelessWindowHint | (windowFlags() & Qt::WindowStaysOnTopHint)); - d->setFullScreenSize_helper(); - raise(); - needShow = true; - } else if (newEffectiveState == Qt::WindowMaximized) { - createWinId(); - d->setMaxWindowState_helper(); - } else { //normal - QRect r = d->topData()->normalGeometry; - if (r.width() >= 0) { - d->topData()->normalGeometry = QRect(0,0,-1,-1); - setGeometry(r); + Q_ASSERT(windowHandle()); + windowHandle()->setWindowState(newEffectiveState); + bool supported = windowHandle()->windowState() == newEffectiveState; + + if (!supported) { + // emulate the window state + if (newEffectiveState == Qt::WindowMinimized) { + //### not ideal... + hide(); + needShow = false; + } else if (newEffectiveState == Qt::WindowFullScreen) { + d->topData()->savedFlags = windowFlags(); + setParent(0, Qt::FramelessWindowHint | (windowFlags() & Qt::WindowStaysOnTopHint)); + d->setFullScreenSize_helper(); + raise(); + needShow = true; + } else if (newEffectiveState == Qt::WindowMaximized) { + createWinId(); + d->setMaxWindowState_helper(); + } else if (newEffectiveState == Qt::WindowNoState) { + // reset old geometry + QRect r = d->topData()->normalGeometry; + if (r.width() >= 0) { + d->topData()->normalGeometry = QRect(0,0,-1,-1); + setGeometry(r); + } } } } -- cgit v1.2.3