From e1550cf8a6c22d90f72d14a159bebfaf77aa03ed Mon Sep 17 00:00:00 2001
From: Philippe Coval <philippe.coval@open.eurogiciel.org>
Date: Wed, 26 Mar 2014 10:16:01 +0100
Subject: [PATCH 2/2] Add minimize qt windows using wayland's xdg-shell

The feature can be disabled at compile time by removing the flag in client.pro
Since xdg-shell is experimental, code fallback to WaylandShell is no xdg

Notes:

* This change depends on presence of xdg-shell protocol file.

* You can check a demo video (qt-tizen-qtwayland-xdg-shell-20140425-rzr)
  of the test case at :
  https://www.youtube.com/watch?v=awQHSkO7PKc#

* Use Super+Tab to show window again if hidden

Bug: https://bugreports.qt-project.org/browse/QTBUG-38633
Change-Id: I2d7ed85bea1847d82439fdfc893a3dbb2581c14a
Signed-off-by: Philippe Coval <philippe.coval@open.eurogiciel.org>
---
 src/client/client.pro             |   8 ++
 src/client/qwaylanddecoration.cpp |  13 +++-
 src/client/qwaylanddisplay.cpp    |   6 ++
 src/client/qwaylanddisplay_p.h    |   4 +
 src/client/qwaylandwindow.cpp     | 106 ++++++++++++++++++++++----
 src/client/qwaylandwindow_p.h     |   5 ++
 src/client/qwaylandxdgpopup.cpp   |  73 ++++++++++++++++++
 src/client/qwaylandxdgpopup_p.h   |  75 ++++++++++++++++++
 src/client/qwaylandxdgsurface.cpp | 155 ++++++++++++++++++++++++++++++++++++++
 src/client/qwaylandxdgsurface_p.h |  98 ++++++++++++++++++++++++
 10 files changed, 524 insertions(+), 19 deletions(-)
 create mode 100644 src/client/qwaylandxdgpopup.cpp
 create mode 100644 src/client/qwaylandxdgpopup_p.h
 create mode 100644 src/client/qwaylandxdgsurface.cpp
 create mode 100644 src/client/qwaylandxdgsurface_p.h

diff --git a/src/client/client.pro b/src/client/client.pro
index 10cbd31..d04f37a 100644
--- a/src/client/client.pro
+++ b/src/client/client.pro
@@ -9,6 +9,9 @@ load(qt_module)
 
 CONFIG += link_pkgconfig qpa/genericunixfontdatabase wayland-scanner
 
+# Enable unstable wayland protocol, comment the line to use regular shell
+DEFINES += USE_XDG_SHELL
+
 !equals(QT_WAYLAND_GL_CONFIG, nogl) {
     DEFINES += QT_WAYLAND_GL_SUPPORT
 }
@@ -40,6 +43,7 @@ WAYLANDCLIENTSOURCES += \
             ../extensions/touch-extension.xml \
             ../extensions/qtkey-extension.xml \
             ../extensions/windowmanager.xml \
+            ../extensions/xdg-shell.xml \
             ../3rdparty/protocol/text.xml \
 
 SOURCES +=  qwaylandintegration.cpp \
@@ -57,6 +61,8 @@ SOURCES +=  qwaylandintegration.cpp \
             qwaylanddatadevicemanager.cpp \
             qwaylanddatasource.cpp \
             qwaylandshellsurface.cpp \
+            qwaylandxdgsurface.cpp \
+            qwaylandxdgpopup.cpp \
             qwaylandextendedoutput.cpp \
             qwaylandextendedsurface.cpp \
             qwaylandsubsurface.cpp \
@@ -85,6 +91,8 @@ HEADERS +=  qwaylandintegration_p.h \
             qwaylanddatadevicemanager_p.h \
             qwaylanddatasource_p.h \
             qwaylandshellsurface_p.h \
+            qwaylandxdgsurface_p.h \
+            qwaylandxdgpopup_p.h \
             qwaylandextendedoutput_p.h \
             qwaylandextendedsurface_p.h \
             qwaylandsubsurface_p.h \
diff --git a/src/client/qwaylanddecoration.cpp b/src/client/qwaylanddecoration.cpp
index 8e7d031..86d8907 100644
--- a/src/client/qwaylanddecoration.cpp
+++ b/src/client/qwaylanddecoration.cpp
@@ -43,6 +43,7 @@
 
 #include "qwaylandwindow_p.h"
 #include "qwaylandshellsurface_p.h"
+#include "qwaylandxdgsurface_p.h"
 #include "qwaylandinputdevice_p.h"
 #include "qwaylandscreen_p.h"
 
@@ -343,7 +344,9 @@ bool QWaylandDecoration::inMouseButtonPressedState() const
 void QWaylandDecoration::startResize(QWaylandInputDevice *inputDevice, enum wl_shell_surface_resize resize, Qt::MouseButtons buttons)
 {
     if (isLeftClicked(buttons)) {
-        m_wayland_window->shellSurface()->resize(inputDevice, resize);
+        if (m_wayland_window->shellSurface()) {
+            m_wayland_window->shellSurface()->resize(inputDevice, resize);
+        }
         inputDevice->removeMouseButtonFromState(Qt::LeftButton);
     }
 }
@@ -351,8 +354,12 @@ void QWaylandDecoration::startResize(QWaylandInputDevice *inputDevice, enum wl_s
 void QWaylandDecoration::startMove(QWaylandInputDevice *inputDevice, Qt::MouseButtons buttons)
 {
     if (isLeftClicked(buttons)) {
-        m_wayland_window->shellSurface()->move(inputDevice);
-        inputDevice->removeMouseButtonFromState(Qt::LeftButton);
+        if (m_wayland_window->xdgSurface()) {
+            m_wayland_window->xdgSurface()->move(inputDevice);
+        } else if (m_wayland_window->shellSurface()) {
+            m_wayland_window->shellSurface()->move(inputDevice);
+        }
+      inputDevice->removeMouseButtonFromState(Qt::LeftButton);
     }
 }
 
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
index 3576c0b..d984375 100644
--- a/src/client/qwaylanddisplay.cpp
+++ b/src/client/qwaylanddisplay.cpp
@@ -61,6 +61,7 @@
 #include "qwaylandqtkey_p.h"
 
 #include <QtWaylandClient/private/qwayland-text.h>
+#include <QtWaylandClient/private/qwayland-xdg-shell.h>
 
 #include <QtCore/QAbstractEventDispatcher>
 #include <QtGui/private/qguiapplication_p.h>
@@ -206,6 +207,11 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
         mCompositor.init(registry, id);
     } else if (interface == QStringLiteral("wl_shm")) {
         mShm = static_cast<struct wl_shm *>(wl_registry_bind(registry, id, &wl_shm_interface,1));
+#ifdef USE_XDG_SHELL
+    } else if (interface == QStringLiteral("xdg_shell")) {
+        mShellXdg.reset(new QtWayland::xdg_shell(registry, id));
+        mShellXdg->use_unstable_version(QtWayland::xdg_shell::version_current);
+#endif
     } else if (interface == QStringLiteral("wl_shell")){
         mShell.reset(new QtWayland::wl_shell(registry, id));
     } else if (interface == QStringLiteral("wl_seat")) {
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
index 40cb2b2..cf5dfc2 100644
--- a/src/client/qwaylanddisplay_p.h
+++ b/src/client/qwaylanddisplay_p.h
@@ -51,6 +51,7 @@
 
 #include <QtWaylandClient/private/qwayland-wayland.h>
 #include <QtWaylandClient/private/qwaylandclientexport_p.h>
+#include <QtWaylandClient/private/qwayland-xdg-shell.h>
 
 struct wl_cursor_image;
 
@@ -78,6 +79,7 @@ namespace QtWayland {
     class qt_sub_surface_extension;
     class qt_surface_extension;
     class wl_text_input_manager;
+    class xdg_shell;
 }
 
 typedef void (*RegistryListener)(void *data,
@@ -113,6 +115,7 @@ public:
     QtWayland::wl_compositor *compositor() { return &mCompositor; }
 
     QtWayland::wl_shell *shell() { return mShell.data(); }
+    QtWayland::xdg_shell *shellXdg() { return mShellXdg.data(); }
 
     QList<QWaylandInputDevice *> inputDevices() const { return mInputDevices; }
     QWaylandInputDevice *defaultInputDevice() const;
@@ -168,6 +171,7 @@ private:
     QThread *mEventThread;
     QWaylandEventThread *mEventThreadObject;
     QScopedPointer<QtWayland::wl_shell> mShell;
+    QScopedPointer<QtWayland::xdg_shell> mShellXdg;
     QList<QPlatformScreen *> mScreens;
     QList<QWaylandInputDevice *> mInputDevices;
     QList<Listener> mRegistryListeners;
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
index 265d651..e29a32e 100644
--- a/src/client/qwaylandwindow.cpp
+++ b/src/client/qwaylandwindow.cpp
@@ -46,6 +46,8 @@
 #include "qwaylandinputdevice_p.h"
 #include "qwaylandscreen_p.h"
 #include "qwaylandshellsurface_p.h"
+#include "qwaylandxdgsurface_p.h"
+#include "qwaylandxdgpopup_p.h"
 #include "qwaylandextendedsurface_p.h"
 #include "qwaylandsubsurface_p.h"
 #include "qwaylanddecoration_p.h"
@@ -69,6 +71,8 @@ QWaylandWindow::QWaylandWindow(QWindow *window)
     , mScreen(QWaylandScreen::waylandScreenFromWindow(window))
     , mDisplay(mScreen->display())
     , mShellSurface(0)
+    , mXdgSurface(0)
+    , mXdgPopup(0)
     , mExtendedWindow(0)
     , mSubSurfaceWindow(0)
     , mWindowDecoration(0)
@@ -92,20 +96,50 @@ QWaylandWindow::QWaylandWindow(QWindow *window)
     static WId id = 1;
     mWindowId = id++;
 
-    if (mDisplay->shell() && window->type() & Qt::Window && !(window->flags() & Qt::BypassWindowManagerHint))
-        mShellSurface = new QWaylandShellSurface(mDisplay->shell()->get_shell_surface(object()), this);
+    if (window->type() & Qt::Window && !(window->flags() & Qt::BypassWindowManagerHint)) {
+        if (mDisplay->shellXdg()) {
+            mXdgSurface = new QWaylandXdgSurface(mDisplay->shellXdg()->get_xdg_surface(object()), this);
+        } else if (mDisplay->shell()) {
+            mShellSurface = new QWaylandShellSurface(mDisplay->shell()->get_shell_surface(object()), this);
+        }
+    } else if (window->type() & Qt::Popup && !(window->flags() & Qt::BypassWindowManagerHint)) {
+
+        if (mDisplay->shellXdg()) {
+            QWaylandWindow *parent_wayland_window = static_cast<QWaylandWindow *>(window->handle());
+
+            // set_popup expects a position relative to the parent
+            QPoint transientPos = geometry().topLeft(); // this is absolute
+            transientPos -= parent_wayland_window->geometry().topLeft();
+            if (parent_wayland_window->decoration()) {
+                transientPos.setX(transientPos.x() + parent_wayland_window->decoration()->margins().left());
+                transientPos.setY(transientPos.y() + parent_wayland_window->decoration()->margins().top());
+        }
+
+         mXdgPopup = new QWaylandXdgPopup(mDisplay->shellXdg()->get_xdg_popup
+                                          (object(),
+                                           parent_wayland_window->object(),
+                                           mMouseDevice->wl_seat(),
+                                           mMouseDevice->serial(),
+                                           transientPos.x(), transientPos.y(),
+                                           0),
+                                          this);
+        }
+    }
     if (mDisplay->windowExtension())
         mExtendedWindow = new QWaylandExtendedSurface(this, mDisplay->windowExtension()->get_extended_surface(object()));
     if (mDisplay->subSurfaceExtension())
         mSubSurfaceWindow = new QWaylandSubSurface(this, mDisplay->subSurfaceExtension()->get_sub_surface_aware_surface(object()));
 
-    if (mShellSurface) {
-        // Set initial surface title
-        mShellSurface->set_title(window->title());
+    // Set surface class to the .desktop file name (obtained from executable name)
+    QFileInfo exeFileInfo(qApp->applicationFilePath());
+    QString className = exeFileInfo.baseName() + QLatin1String(".desktop");
 
-        // Set surface class to the .desktop file name (obtained from executable name)
-        QFileInfo exeFileInfo(qApp->applicationFilePath());
-        QString className = exeFileInfo.baseName() + QLatin1String(".desktop");
+    // Set initial surface's title and classname from previous parsing operation
+    if (mXdgSurface) {
+        mXdgSurface->set_title(window->title());
+        mXdgSurface->set_app_id(className);
+    } else if (mShellSurface) {
+        mShellSurface->set_title(window->title());
         mShellSurface->set_class(className);
     }
 
@@ -115,6 +149,8 @@ QWaylandWindow::QWaylandWindow(QWindow *window)
         if (window->type() != Qt::Popup) {
             mShellSurface->updateTransientParent(window->transientParent());
         }
+    } else if (mXdgSurface) {
+        mXdgSurface->setNormal();
     } else if (mShellSurface) {
         mShellSurface->setTopLevel();
     }
@@ -192,9 +228,13 @@ void QWaylandWindow::setGeometry(const QRect &rect)
                 qBound(window()->minimumWidth(), rect.width(), window()->maximumWidth()),
                 qBound(window()->minimumHeight(), rect.height(), window()->maximumHeight())));
 
-    if (shellSurface() && window()->transientParent() && window()->type() != Qt::Popup)
-        shellSurface()->updateTransientParent(window()->transientParent());
-
+    if (window()->transientParent() && window()->type() != Qt::Popup) {
+        if (xdgSurface()) {
+            xdgSurface()->updateTransientParent(window()->transientParent());
+        } else if (shellSurface()) {
+            shellSurface()->updateTransientParent(window()->transientParent());
+        }
+    }
     if (mWindowDecoration && window()->isVisible())
         mWindowDecoration->update();
 
@@ -213,7 +253,7 @@ void QWaylandWindow::setVisible(bool visible)
             mMouseDevice = parent->mMouseDevice;
             mMouseSerial = parent->mMouseSerial;
 
-            if (mMouseDevice)
+            if (mMouseDevice && mShellSurface)
                 mShellSurface->setPopup(transientParent(), mMouseDevice, mMouseSerial);
         }
 
@@ -399,6 +439,11 @@ QWaylandShellSurface *QWaylandWindow::shellSurface() const
     return mShellSurface;
 }
 
+QWaylandXdgSurface *QWaylandWindow::xdgSurface() const
+{
+    return mXdgSurface;
+}
+
 QWaylandExtendedSurface *QWaylandWindow::extendedWindow() const
 {
     return mExtendedWindow;
@@ -429,6 +474,19 @@ void QWaylandWindow::setWindowFlags(Qt::WindowFlags flags)
 
 bool QWaylandWindow::createDecoration()
 {
+    // so far only xdg-shell support this "unminimize" trick, may be moved elsewhere
+    if (mState == Qt::WindowMinimized) {
+        if (mXdgSurface) {
+            if (mXdgSurface->isFullscreen()) {
+                setWindowStateInternal(Qt::WindowFullScreen);
+            } else if (mXdgSurface->isMaximized()) {
+                setWindowStateInternal(Qt::WindowMaximized);
+            } else {
+                setWindowStateInternal(Qt::WindowNoState);
+            }
+        }
+    }
+
     static bool disableWaylandDecorations = !qgetenv("QT_WAYLAND_DISABLE_WINDOWDECORATION").isEmpty();
     if (disableWaylandDecorations)
         return false;
@@ -603,16 +661,32 @@ bool QWaylandWindow::setWindowStateInternal(Qt::WindowState state)
     createDecoration();
     switch (state) {
         case Qt::WindowFullScreen:
-            mShellSurface->setFullscreen();
+            if (mXdgSurface) {
+                mXdgSurface->setFullscreen();
+            } else if (mShellSurface) {
+                mShellSurface->setFullscreen();
+            }
             break;
         case Qt::WindowMaximized:
-            mShellSurface->setMaximized();
+            if (mXdgSurface) {
+                mXdgSurface->setMaximized();
+            } else if (mShellSurface) {
+                mShellSurface->setMaximized();
+            }
             break;
         case Qt::WindowMinimized:
-            mShellSurface->setMinimized();
+            if (mXdgSurface) {
+                mXdgSurface->setMinimized();
+            } else if (mShellSurface) {
+                mShellSurface->setMinimized();
+            }
             break;
         default:
-            mShellSurface->setNormal();
+            if (mXdgSurface) {
+                mXdgSurface->setNormal();
+            } else if (mShellSurface) {
+                mShellSurface->setNormal();
+            }
     }
 
     QWindowSystemInterface::handleWindowStateChanged(window(), mState);
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
index fe6f319..d2eb342 100644
--- a/src/client/qwaylandwindow_p.h
+++ b/src/client/qwaylandwindow_p.h
@@ -62,6 +62,8 @@ class QWaylandShellSurface;
 class QWaylandExtendedSurface;
 class QWaylandSubSurface;
 class QWaylandDecoration;
+class QWaylandXdgSurface;
+class QWaylandXdgPopup;
 
 class Q_WAYLAND_CLIENT_EXPORT QWaylandWindowConfigure
 {
@@ -125,6 +127,7 @@ public:
     static QWaylandWindow *fromWlSurface(::wl_surface *surface);
 
     QWaylandShellSurface *shellSurface() const;
+    QWaylandXdgSurface *xdgSurface() const;
     QWaylandExtendedSurface *extendedWindow() const;
     QWaylandSubSurface *subSurfaceWindow() const;
 
@@ -175,6 +178,8 @@ protected:
     QWaylandScreen *mScreen;
     QWaylandDisplay *mDisplay;
     QWaylandShellSurface *mShellSurface;
+    QWaylandXdgSurface *mXdgSurface;
+    QWaylandXdgPopup *mXdgPopup;
     QWaylandExtendedSurface *mExtendedWindow;
     QWaylandSubSurface *mSubSurfaceWindow;
 
diff --git a/src/client/qwaylandxdgpopup.cpp b/src/client/qwaylandxdgpopup.cpp
new file mode 100644
index 0000000..796b57a
--- /dev/null
+++ b/src/client/qwaylandxdgpopup.cpp
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the config.tests of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwaylandxdgpopup_p.h"
+
+#include "qwaylanddisplay_p.h"
+#include "qwaylandwindow_p.h"
+#include "qwaylandinputdevice_p.h"
+#include "qwaylanddecoration_p.h"
+#include "qwaylandscreen_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QWaylandXdgPopup::QWaylandXdgPopup(struct ::xdg_popup *xdg_popup, QWaylandWindow *window)
+    : QtWayland::xdg_popup(xdg_popup)
+    , m_window(window)
+{
+}
+
+QWaylandXdgPopup::~QWaylandXdgPopup()
+{
+    xdg_popup_destroy(object());
+}
+
+
+void QWaylandXdgPopup::xdg_popup_ping(uint32_t serial)
+{
+    pong(serial);
+}
+
+void QWaylandXdgPopup::xdg_popup_popup_done(uint32_t serial)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/client/qwaylandxdgpopup_p.h b/src/client/qwaylandxdgpopup_p.h
new file mode 100644
index 0000000..b992d3e
--- /dev/null
+++ b/src/client/qwaylandxdgpopup_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the config.tests of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDXDGPOPUP_H
+#define QWAYLANDXDGPOPUP_H
+
+#include <QtCore/QSize>
+
+#include <wayland-client.h>
+
+#include <QtWaylandClient/private/qwayland-xdg-shell.h>
+#include <QtWaylandClient/private/qwaylandclientexport_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandWindow;
+class QWaylandInputDevice;
+class QWindow;
+
+class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgPopup : public QtWayland::xdg_popup
+{
+public:
+    QWaylandXdgPopup(struct ::xdg_popup *shell_popup, QWaylandWindow *window);
+    ~QWaylandXdgPopup();
+
+private:
+    QWaylandWindow *m_window;
+
+    void xdg_popup_ping(uint32_t serial) Q_DECL_OVERRIDE;
+    void xdg_popup_popup_done(uint32_t serial) Q_DECL_OVERRIDE;
+
+    friend class QWaylandWindow;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDXDGPOPUP_H
diff --git a/src/client/qwaylandxdgsurface.cpp b/src/client/qwaylandxdgsurface.cpp
new file mode 100644
index 0000000..66127b9
--- /dev/null
+++ b/src/client/qwaylandxdgsurface.cpp
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the config.tests of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwaylandxdgsurface_p.h"
+
+#include "qwaylanddisplay_p.h"
+#include "qwaylandwindow_p.h"
+#include "qwaylandinputdevice_p.h"
+#include "qwaylanddecoration_p.h"
+#include "qwaylandscreen_p.h"
+
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+QWaylandXdgSurface::QWaylandXdgSurface(struct ::xdg_surface *xdg_surface, QWaylandWindow *window)
+    : QtWayland::xdg_surface(xdg_surface)
+    , m_window(window)
+    , m_maximized(false)
+    , m_minimized(false)
+    , m_fullscreen(false)
+{
+}
+
+QWaylandXdgSurface::~QWaylandXdgSurface()
+{
+    xdg_surface_destroy(object());
+}
+
+void QWaylandXdgSurface::resize(QWaylandInputDevice *inputDevice, enum resize_edge edges)
+{
+    resize(inputDevice->wl_seat(),
+           inputDevice->serial(),
+           edges);
+}
+
+void QWaylandXdgSurface::move(QWaylandInputDevice *inputDevice)
+{
+    move(inputDevice->wl_seat(),
+         inputDevice->serial());
+}
+
+void QWaylandXdgSurface::setMaximized()
+{
+    m_maximized = true;
+    m_size = m_window->window()->geometry().size();
+    set_maximized();
+}
+
+void QWaylandXdgSurface::setFullscreen()
+{
+    m_fullscreen = true;
+    m_size = m_window->window()->geometry().size();
+    set_fullscreen();
+}
+
+void QWaylandXdgSurface::setNormal()
+{
+    if (m_fullscreen || m_maximized  || m_minimized) {
+        if (m_maximized) { unset_maximized(); }
+        if (m_fullscreen) { unset_fullscreen(); }
+
+        m_fullscreen = m_maximized = m_minimized = false;
+        QMargins m = m_window->frameMargins();
+        m_window->configure(0, m_size.width() + m.left() + m.right(), m_size.height() + m.top() + m.bottom());
+    }
+}
+
+void QWaylandXdgSurface::setMinimized()
+{
+    m_minimized = true;
+    m_size = m_window->window()->geometry().size();
+    set_minimized();
+}
+
+void QWaylandXdgSurface::setTopLevel()
+{
+    // TODO: There's no xdg_shell_surface API for this, ignoring
+}
+
+void QWaylandXdgSurface::updateTransientParent(QWindow *parent)
+{
+    QWaylandWindow *parent_wayland_window = static_cast<QWaylandWindow *>(parent->handle());
+    if (!parent_wayland_window)
+        return;
+
+    // set_transient expects a position relative to the parent
+    QPoint transientPos = m_window->geometry().topLeft(); // this is absolute
+    QWindow *parentWin = m_window->window()->transientParent();
+    transientPos -= parentWin->geometry().topLeft();
+    if (parent_wayland_window->decoration()) {
+        transientPos.setX(transientPos.x() + parent_wayland_window->decoration()->margins().left());
+        transientPos.setY(transientPos.y() + parent_wayland_window->decoration()->margins().top());
+    }
+
+    uint32_t flags = 0;
+    Qt::WindowFlags wf = m_window->window()->flags();
+    if (wf.testFlag(Qt::ToolTip)
+            || wf.testFlag(Qt::WindowTransparentForInput))
+      flags |= XDG_SURFACE_SET_TRANSIENT_FOR;
+
+    set_transient_for(parent_wayland_window->object());
+}
+
+void QWaylandXdgSurface::xdg_surface_ping(uint32_t serial)
+{
+    pong(serial);
+}
+
+void QWaylandXdgSurface::xdg_surface_configure(uint32_t edges, int32_t width,
+                                               int32_t height)
+{
+    m_window->configure(edges, width, height);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/client/qwaylandxdgsurface_p.h b/src/client/qwaylandxdgsurface_p.h
new file mode 100644
index 0000000..1ad928a
--- /dev/null
+++ b/src/client/qwaylandxdgsurface_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the config.tests of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDXDGSURFACE_H
+#define QWAYLANDXDGSURFACE_H
+
+#include <QtCore/QSize>
+
+#include <wayland-client.h>
+
+#include <QtWaylandClient/private/qwayland-xdg-shell.h>
+#include <QtWaylandClient/private/qwaylandclientexport_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandWindow;
+class QWaylandInputDevice;
+class QWindow;
+
+class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgSurface : public QtWayland::xdg_surface
+{
+public:
+    QWaylandXdgSurface(struct ::xdg_surface *shell_surface, QWaylandWindow *window);
+    ~QWaylandXdgSurface();
+
+    using QtWayland::xdg_surface::resize;
+    void resize(QWaylandInputDevice *inputDevice, enum resize_edge edges);
+
+    using QtWayland::xdg_surface::move;
+    void move(QWaylandInputDevice *inputDevice);
+
+    bool isFullscreen() const { return m_fullscreen; }
+    bool isMaximized() const { return m_maximized; }
+
+private:
+    void setMaximized();
+    void setFullscreen();
+    void setNormal();
+    void setMinimized();
+
+    void setTopLevel();
+    void updateTransientParent(QWindow *parent);
+
+private:
+    QWaylandWindow *m_window;
+    bool m_maximized;
+    bool m_minimized;
+    bool m_fullscreen;
+    QSize m_size;
+
+    void xdg_surface_ping(uint32_t serial) Q_DECL_OVERRIDE;
+    void xdg_surface_configure(uint32_t edges,
+                               int32_t width,
+                               int32_t height) Q_DECL_OVERRIDE;
+    friend class QWaylandWindow;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDXDGSURFACE_H
-- 
1.8.3.2

