Implement QWindow minimum/maximum/base size hints and size increments.
authorSamuel Rødal <samuel.rodal@nokia.com>
Mon, 16 May 2011 14:39:50 +0000 (16:39 +0200)
committerSamuel Rødal <samuel.rodal@nokia.com>
Mon, 16 May 2011 14:40:32 +0000 (16:40 +0200)
examples/qpa/windows/window.cpp
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 d08db57..76bc117 100644 (file)
@@ -23,9 +23,15 @@ Window::Window(QWindow *parent)
 
     if (parent)
         setGeometry(QRect(160, 120, 320, 240));
-    else
+    else {
         setGeometry(QRect(10, 10, 640, 480));
 
+        setSizeIncrement(QSize(10, 10));
+        setBaseSize(QSize(640, 480));
+        setMinimumSize(QSize(240, 160));
+        setMaximumSize(QSize(800, 600));
+    }
+
     create();
     QGuiApplicationPrivate::platformIntegration()->createWindowSurface(this, winId());
 
index d7d1d96..afbff2a 100644 (file)
@@ -161,6 +161,14 @@ void QPlatformWindow::raise() { qWarning("This plugin does not support raise()")
 void QPlatformWindow::lower() { qWarning("This plugin does not support lower()"); }
 
 /*!
+  Reimplement to propagate the size hints of the QWindow.
+
+  The size hints include QWindow::minimumSize(), QWindow::maximumSize(),
+  QWindow::sizeIncrement(), and QWindow::baseSize().
+*/
+void QPlatformWindow::propagateSizeHints() {qWarning("This plugin does not support propagateSizeHints()"); }
+
+/*!
   Reimplement to be able to let Qt set the opacity level of a window
 */
 void QPlatformWindow::setOpacity(qreal level)
index c74e966..de3174b 100644 (file)
@@ -80,6 +80,8 @@ public:
     virtual void raise();
     virtual void lower();
 
+    virtual void propagateSizeHints();
+
     virtual void setOpacity(qreal level);
     virtual void requestActivateWindow();
 
index 897b370..5d4fd76 100644 (file)
@@ -143,6 +143,15 @@ void QWindow::setParent(QWindow *parent)
     d->parentWindow = parent;
 }
 
+/*!
+   Returns whether the window is top level, i.e. parent-less.
+ */
+bool QWindow::isTopLevel() const
+{
+    Q_D(const QWindow);
+    return d->parentWindow == 0;
+}
+
 void QWindow::setWindowFormat(const QWindowFormat &format)
 {
     Q_D(QWindow);
@@ -256,26 +265,68 @@ void QWindow::setWindowState(Qt::WindowState state)
 
 QSize QWindow::minimumSize() const
 {
-    qDebug() << "unimplemented:" << __FILE__ << __LINE__;
-    return QSize();
+    Q_D(const QWindow);
+    return d->minimumSize;
 }
 
 QSize QWindow::maximumSize() const
 {
-    qDebug() << "unimplemented:" << __FILE__ << __LINE__;
-    return QSize();
+    Q_D(const QWindow);
+    return d->maximumSize;
 }
 
-void QWindow::setMinimumSize(const QSize &size) const
+QSize QWindow::baseSize() const
 {
-    Q_UNUSED(size);
-    qDebug() << "unimplemented:" << __FILE__ << __LINE__;
+    Q_D(const QWindow);
+    return d->baseSize;
 }
 
-void QWindow::setMaximumSize(const QSize &size) const
+QSize QWindow::sizeIncrement() const
 {
-    Q_UNUSED(size);
-    qDebug() << "unimplemented:" << __FILE__ << __LINE__;
+    Q_D(const QWindow);
+    return d->sizeIncrement;
+}
+
+void QWindow::setMinimumSize(const QSize &size)
+{
+    Q_D(QWindow);
+    QSize adjustedSize = QSize(qBound(0, size.width(), QWINDOWSIZE_MAX), qBound(0, size.height(), QWINDOWSIZE_MAX));
+    if (d->minimumSize == adjustedSize)
+        return;
+    d->minimumSize = adjustedSize;
+    if (d->platformWindow && isTopLevel())
+        d->platformWindow->propagateSizeHints();
+}
+
+void QWindow::setMaximumSize(const QSize &size)
+{
+    Q_D(QWindow);
+    QSize adjustedSize = QSize(qBound(0, size.width(), QWINDOWSIZE_MAX), qBound(0, size.height(), QWINDOWSIZE_MAX));
+    if (d->maximumSize == adjustedSize)
+        return;
+    d->maximumSize = adjustedSize;
+    if (d->platformWindow && isTopLevel())
+        d->platformWindow->propagateSizeHints();
+}
+
+void QWindow::setBaseSize(const QSize &size)
+{
+    Q_D(QWindow);
+    if (d->baseSize == size)
+        return;
+    d->baseSize = size;
+    if (d->platformWindow && isTopLevel())
+        d->platformWindow->propagateSizeHints();
+}
+
+void QWindow::setSizeIncrement(const QSize &size)
+{
+    Q_D(QWindow);
+    if (d->sizeIncrement == size)
+        return;
+    d->sizeIncrement = size;
+    if (d->platformWindow && isTopLevel())
+        d->platformWindow->propagateSizeHints();
 }
 
 void QWindow::setGeometry(const QRect &rect)
@@ -464,4 +515,9 @@ void QWindow::wheelEvent(QWheelEvent *)
 }
 #endif //QT_NO_WHEELEVENT
 
+Q_GUI_EXPORT QWindowPrivate *qt_window_private(QWindow *window)
+{
+    return window->d_func();
+}
+
 QT_END_NAMESPACE
index 7022710..e0a1871 100644 (file)
@@ -94,6 +94,8 @@ public:
     QWindow *parent() const;
     void setParent(QWindow *parent);
 
+    bool isTopLevel() const;
+
     QWindow *topLevelWindow() const;
 
     void setWindowFormat(const QWindowFormat &format);
@@ -116,9 +118,13 @@ public:
 
     QSize minimumSize() const;
     QSize maximumSize() const;
+    QSize baseSize() const;
+    QSize sizeIncrement() const;
 
-    void setMinimumSize(const QSize &size) const;
-    void setMaximumSize(const QSize &size) const;
+    void setMinimumSize(const QSize &size);
+    void setMaximumSize(const QSize &size);
+    void setBaseSize(const QSize &size);
+    void setSizeIncrement(const QSize &size);
 
     void setGeometry(const QRect &rect);
     QRect geometry() const;
@@ -177,6 +183,7 @@ private:
     friend class QGuiApplication;
     friend class QGuiApplicationPrivate;
     friend class QWindowSurface;
+    friend Q_GUI_EXPORT QWindowPrivate *qt_window_private(QWindow *window);
 };
 
 QT_END_NAMESPACE
index b622774..215a18d 100644 (file)
@@ -52,7 +52,9 @@ QT_BEGIN_NAMESPACE
 
 QT_MODULE(Gui)
 
-class QWindowPrivate : public QObjectPrivate
+#define QWINDOWSIZE_MAX ((1<<24)-1)
+
+class Q_GUI_EXPORT QWindowPrivate : public QObjectPrivate
 {
 public:
     QWindowPrivate()
@@ -65,6 +67,7 @@ public:
         , glContext(0)
         , surface(0)
         , windowState(Qt::WindowNoState)
+        , maximumSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX)
     {
         isWindow = true;
     }
@@ -84,6 +87,11 @@ public:
     QWindowContext *glContext;
     QWindowSurface *surface;
     Qt::WindowState windowState;
+
+    QSize minimumSize;
+    QSize maximumSize;
+    QSize baseSize;
+    QSize sizeIncrement;
 };
 
 
index dd28d13..709efb2 100644 (file)
@@ -52,6 +52,7 @@
 #include <xcb/xcb_icccm.h>
 
 #include <private/qguiapplication_p.h>
+#include <private/qwindow_p.h>
 #include <private/qwindowsurface_p.h>
 
 #include <QtGui/QWindowSystemInterface>
@@ -256,31 +257,49 @@ void QXcbWindow::setGeometry(const QRect &rect)
 
 void QXcbWindow::setVisible(bool visible)
 {
-    xcb_wm_hints_t hints;
-    if (visible) {
-        // TODO: QWindow::isMinimized() or similar
+    if (visible)
+        show();
+    else
+        hide();
+}
+
+void QXcbWindow::show()
+{
+    if (window()->isTopLevel()) {
+        xcb_get_property_cookie_t cookie = xcb_get_wm_hints(xcb_connection(), m_window);
+
+        xcb_wm_hints_t hints;
+        xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, 0);
+
         if (window()->windowState() & Qt::WindowMinimized)
             xcb_wm_hints_set_iconic(&hints);
         else
             xcb_wm_hints_set_normal(&hints);
+
         xcb_set_wm_hints(xcb_connection(), m_window, &hints);
-        Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window));
-        connection()->sync();
-    } else {
-        Q_XCB_CALL(xcb_unmap_window(xcb_connection(), m_window));
-
-        // send synthetic UnmapNotify event according to icccm 4.1.4
-        xcb_unmap_notify_event_t event;
-        event.response_type = XCB_UNMAP_NOTIFY;
-        event.sequence = 0; // does this matter?
-        event.event = m_screen->root();
-        event.window = m_window;
-        event.from_configure = false;
-        Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_screen->root(),
-                                  XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
 
-        xcb_flush(xcb_connection());
+        propagateSizeHints();
     }
+
+    Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window));
+    connection()->sync();
+}
+
+void QXcbWindow::hide()
+{
+    Q_XCB_CALL(xcb_unmap_window(xcb_connection(), m_window));
+
+    // send synthetic UnmapNotify event according to icccm 4.1.4
+    xcb_unmap_notify_event_t event;
+    event.response_type = XCB_UNMAP_NOTIFY;
+    event.sequence = 0; // does this matter?
+    event.event = m_screen->root();
+    event.window = m_window;
+    event.from_configure = false;
+    Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_screen->root(),
+                              XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
+
+    xcb_flush(xcb_connection());
 }
 
 struct QtMWMHints {
@@ -577,6 +596,36 @@ void QXcbWindow::lower()
     Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values));
 }
 
+void QXcbWindow::propagateSizeHints()
+{
+    xcb_size_hints_t hints;
+
+    QRect rect = geometry();
+
+    xcb_size_hints_set_position(&hints, true, rect.x(), rect.y());
+    xcb_size_hints_set_size(&hints, true, rect.width(), rect.height());
+
+    QWindow *win = window();
+
+    QSize minimumSize = win->minimumSize();
+    QSize maximumSize = win->maximumSize();
+    QSize baseSize = win->baseSize();
+    QSize sizeIncrement = win->sizeIncrement();
+
+    if (minimumSize.width() > 0 || minimumSize.height() > 0)
+        xcb_size_hints_set_min_size(&hints, minimumSize.width(), minimumSize.height());
+
+    if (maximumSize.width() < QWINDOWSIZE_MAX || maximumSize.height() < QWINDOWSIZE_MAX)
+        xcb_size_hints_set_max_size(&hints, maximumSize.width(), maximumSize.height());
+
+    if (sizeIncrement.width() > 0 || sizeIncrement.height() > 0) {
+        xcb_size_hints_set_base_size(&hints, baseSize.width(), baseSize.height());
+        xcb_size_hints_set_resize_inc(&hints, sizeIncrement.width(), sizeIncrement.height());
+    }
+
+    xcb_set_wm_normal_hints(xcb_connection(), m_window, &hints);
+}
+
 void QXcbWindow::requestActivateWindow()
 {
     Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, XCB_TIME_CURRENT_TIME));
index 831c25b..accb32b 100644 (file)
@@ -69,6 +69,7 @@ public:
     void setWindowTitle(const QString &title);
     void raise();
     void lower();
+    void propagateSizeHints();
 
     void requestActivateWindow();
 
@@ -96,6 +97,9 @@ private:
     void setNetWmWindowTypes(Qt::WindowFlags flags);
     void changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two = 0);
 
+    void show();
+    void hide();
+
     QXcbScreen *m_screen;
 
     xcb_window_t m_window;
index b7b502a..533cc0a 100644 (file)
@@ -49,6 +49,7 @@
 #include "QtWidgets/qdesktopwidget.h"
 #include "QtGui/qplatformwindow_qpa.h"
 #include "QtGui/qplatformglcontext_qpa.h"
+#include "QtGui/private/qwindow_p.h"
 
 #include <QtGui/QPlatformCursor>
 
@@ -628,6 +629,22 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
 
 void QWidgetPrivate::setConstraints_sys()
 {
+    Q_Q(QWidget);
+    if (extra && q->windowHandle()) {
+        QWindow *win = q->windowHandle();
+        QWindowPrivate *winp = qt_window_private(win);
+
+        winp->minimumSize = QSize(extra->minw, extra->minh);
+        winp->maximumSize = QSize(extra->maxw, extra->maxh);
+
+        if (extra->topextra) {
+            winp->baseSize = QSize(extra->topextra->basew, extra->topextra->baseh);
+            winp->sizeIncrement = QSize(extra->topextra->incw, extra->topextra->inch);
+        }
+
+        if (winp->platformWindow)
+            winp->platformWindow->propagateSizeHints();
+    }
 }
 
 void QWidgetPrivate::scroll_sys(int dx, int dy)