Initial QPlatformWindow window state setting API and xcb implementation.
authorSamuel Rødal <samuel.rodal@nokia.com>
Fri, 13 May 2011 09:51:41 +0000 (11:51 +0200)
committerSamuel Rødal <samuel.rodal@nokia.com>
Fri, 13 May 2011 13:13:15 +0000 (15:13 +0200)
src/gui/kernel/qplatformwindow_qpa.cpp
src/gui/kernel/qplatformwindow_qpa.h
src/gui/kernel/qwindow.cpp
src/gui/kernel/qwindow.h
src/gui/kernel/qwindow_p.h
src/plugins/platforms/xcb/qxcbwindow.cpp
src/plugins/platforms/xcb/qxcbwindow.h
src/widgets/kernel/qwidget_qpa.cpp

index 24c337c..d7d1d96 100644 (file)
@@ -117,6 +117,17 @@ Qt::WindowFlags QPlatformWindow::setWindowFlags(Qt::WindowFlags 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
 */
 WId QPlatformWindow::winId() const { return WId(0); }
index 1730f3d..c74e966 100644 (file)
@@ -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);
 
index 7faf493..897b370 100644 (file)
@@ -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
index f2fde2d..7022710 100644 (file)
@@ -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;
index 6f1038e..b622774 100644 (file)
@@ -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;
 };
 
 
index f6d9c2f..dd28d13 100644 (file)
@@ -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<QXcbScreen *>(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
index 3ed58b3..831c25b 100644 (file)
@@ -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
index f683391..b7b502a 100644 (file)
@@ -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);
+                }
             }
         }
     }