summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Klokkhammer Helsing <johan.helsing@theqtcompany.com>2016-02-17 12:51:54 +0100
committerJohan Helsing <johan.helsing@theqtcompany.com>2016-03-24 11:30:33 +0000
commitd87d8b8afdd377e17a98b4d0f51c4bb0aaec25c2 (patch)
tree675df7cb09e6da37db7b6eb654371f1412f10fa5
parentbfa0951619e56e856cc1443f78fbdb66e3bde009 (diff)
Initial compositor support for xdg-shell wayland extension
xdg-shell is an extension to the wayland protocol providing functionality suited towards traditional desktop environments. Most of the examples from Weston now require xdg-shell, ivi-shell or some other custom extension. In order for our compositor-api to support those examples and many real-world applications, we needed a compositor implementation of xdg-shell. This commit adds a class QWaylandXdgShell, along with QWaylandXdgSurface and QWaylandXdgPopup. These clases are used almost exactly like the corresponding QWaylandShell* variants. qwindow-compositor has been updated to use the new functionality. qwindow-compositor now only sets focus on surfaces that have a role. weston-terminal was crashing because we set keyboard focus on the cursor surface. Keyboard focus handling has been slightly changed. Most of the functionality has been moved from QWaylandKeyboard::setFocus to QWaylandInputDevice::setKeyboardFocus. This is done in order to track where the keyboard focus should have been, in case the input device (seat) does not currently have a keyboard capability. If a keyboard capability is later set on the input device, its focus will automatically be set to the value stored in QWaylandInputDevice. The reason for the change in keyboard focus handling is that we need to know if an xdgSurface has keyboard focus in order to know whether to send the Activated state in configure events. The Activated state tells the client to draw itself as having focus (i.e. title bar not grayed out). Change-Id: I1b1ca9a4223e87f5ade1e0f4c975979a400c38cb Reviewed-by: Giulio Camuffo <giulio.camuffo@kdab.com> Reviewed-by: Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-rw-r--r--examples/wayland/qwindow-compositor/compositorwindow.cpp26
-rw-r--r--examples/wayland/qwindow-compositor/compositorwindow.h6
-rw-r--r--examples/wayland/qwindow-compositor/windowcompositor.cpp124
-rw-r--r--examples/wayland/qwindow-compositor/windowcompositor.h18
-rw-r--r--src/compositor/compositor_api/qwaylandcompositor.cpp5
-rw-r--r--src/compositor/compositor_api/qwaylandcompositor.h2
-rw-r--r--src/compositor/compositor_api/qwaylandinput.cpp25
-rw-r--r--src/compositor/compositor_api/qwaylandinput.h1
-rw-r--r--src/compositor/compositor_api/qwaylandinput_p.h1
-rw-r--r--src/compositor/compositor_api/qwaylandkeyboard.cpp8
-rw-r--r--src/compositor/compositor_api/qwaylandkeyboard.h2
-rw-r--r--src/compositor/compositor_api/qwaylandsurface.cpp6
-rw-r--r--src/compositor/compositor_api/qwaylandsurface.h1
-rw-r--r--src/compositor/extensions/extensions.pri4
-rw-r--r--src/compositor/extensions/qwaylandxdgshell.cpp1049
-rw-r--r--src/compositor/extensions/qwaylandxdgshell.h224
-rw-r--r--src/compositor/extensions/qwaylandxdgshell_p.h171
17 files changed, 1641 insertions, 32 deletions
diff --git a/examples/wayland/qwindow-compositor/compositorwindow.cpp b/examples/wayland/qwindow-compositor/compositorwindow.cpp
index 4b69022f2..002831283 100644
--- a/examples/wayland/qwindow-compositor/compositorwindow.cpp
+++ b/examples/wayland/qwindow-compositor/compositorwindow.cpp
@@ -86,6 +86,24 @@ void CompositorWindow::drawBackground()
}
}
+QPointF CompositorWindow::getAnchorPosition(const QPointF &position, int resizeEdge, const QSize &windowSize)
+{
+ float y = position.y();
+ if (resizeEdge & QWaylandXdgSurface::ResizeEdge::TopEdge)
+ y += windowSize.height();
+
+ float x = position.x();
+ if (resizeEdge & QWaylandXdgSurface::ResizeEdge::LeftEdge)
+ x += windowSize.width();
+
+ return QPointF(x, y);
+}
+
+QPointF CompositorWindow::getAnchoredPosition(const QPointF &anchorPosition, int resizeEdge, const QSize &windowSize)
+{
+ return anchorPosition - getAnchorPosition(QPointF(), resizeEdge, windowSize);
+}
+
void CompositorWindow::paintGL()
{
m_compositor->startRender();
@@ -107,6 +125,8 @@ void CompositorWindow::paintGL()
if (surface && surface->isMapped()) {
QSize s = surface->size();
if (!s.isEmpty()) {
+ if (m_mouseView == view && m_grabState == ResizeGrab && m_resizeAnchored)
+ view->setPosition(getAnchoredPosition(m_resizeAnchorPosition, m_resizeEdge, s));
QPointF pos = view->position() + view->parentPosition();
QRectF surfaceGeometry(pos, s);
QOpenGLTextureBlitter::Origin surfaceOrigin =
@@ -144,11 +164,13 @@ void CompositorWindow::startMove()
m_grabState = MoveGrab;
}
-void CompositorWindow::startResize(int edge)
+void CompositorWindow::startResize(int edge, bool anchored)
{
- m_initialSize = m_mouseView->surface()->size();
+ m_initialSize = m_mouseView->windowSize();
m_grabState = ResizeGrab;
m_resizeEdge = edge;
+ m_resizeAnchored = anchored;
+ m_resizeAnchorPosition = getAnchorPosition(m_mouseView->position(), edge, m_mouseView->surface()->size());
}
void CompositorWindow::startDrag(WindowCompositorView *dragIcon)
diff --git a/examples/wayland/qwindow-compositor/compositorwindow.h b/examples/wayland/qwindow-compositor/compositorwindow.h
index 720db5bc7..c7c637e53 100644
--- a/examples/wayland/qwindow-compositor/compositorwindow.h
+++ b/examples/wayland/qwindow-compositor/compositorwindow.h
@@ -71,7 +71,7 @@ protected:
private slots:
void startMove();
- void startResize(int edge);
+ void startResize(int edge, bool anchored);
void startDrag(WindowCompositorView *dragIcon);
void setFrameOffset(const QPoint &offset);
@@ -82,6 +82,8 @@ private:
bool mouseGrab() const { return m_grabState != NoGrab ;}
void drawBackground();
void sendMouseEvent(QMouseEvent *e, WindowCompositorView *target);
+ static QPointF getAnchoredPosition(const QPointF &anchorPosition, int resizeEdge, const QSize &windowSize);
+ static QPointF getAnchorPosition(const QPointF &position, int resizeEdge, const QSize &windowSize);
QOpenGLTextureBlitter m_textureBlitter;
QSize m_backgroundImageSize;
@@ -91,6 +93,8 @@ private:
GrabState m_grabState;
QSize m_initialSize;
int m_resizeEdge;
+ bool m_resizeAnchored;
+ QPointF m_resizeAnchorPosition;
QPointF m_mouseOffset;
QPointF m_initialMousePos;
WindowCompositorView *m_dragIconView;
diff --git a/examples/wayland/qwindow-compositor/windowcompositor.cpp b/examples/wayland/qwindow-compositor/windowcompositor.cpp
index 46416f0de..023474854 100644
--- a/examples/wayland/qwindow-compositor/windowcompositor.cpp
+++ b/examples/wayland/qwindow-compositor/windowcompositor.cpp
@@ -45,6 +45,7 @@
#include <QTouchEvent>
#include <QtWaylandCompositor/QWaylandShellSurface>
+#include <QtWaylandCompositor/QWaylandXdgShell>
#include <QtWaylandCompositor/qwaylandinput.h>
#include <QtWaylandCompositor/qwaylanddrag.h>
@@ -68,12 +69,51 @@ bool WindowCompositorView::isCursor() const
return surface()->isCursorSurface();
}
+void WindowCompositorView::onXdgSetMaximized()
+{
+ m_xdgSurface->requestMaximized(output()->geometry().size());
+
+ // An improvement here, would have been to wait for the commit after the ack_configure for the
+ // request above before moving the window. This would have prevented the window from being
+ // moved until the contents of the window had actually updated. This improvement is left as an
+ // exercise for the reader.
+ setPosition(QPoint(0, 0));
+}
+
+void WindowCompositorView::onXdgUnsetMaximized()
+{
+ m_xdgSurface->requestUnMaximized();
+}
+
+void WindowCompositorView::onXdgSetFullscreen(QWaylandOutput* clientPreferredOutput)
+{
+ QWaylandOutput *outputToFullscreen = clientPreferredOutput
+ ? clientPreferredOutput
+ : output();
+
+ m_xdgSurface->requestFullscreen(outputToFullscreen->geometry().size());
+
+ // An improvement here, would have been to wait for the commit after the ack_configure for the
+ // request above before moving the window. This would have prevented the window from being
+ // moved until the contents of the window had actually updated. This improvement is left as an
+ // exercise for the reader.
+ setPosition(outputToFullscreen->position());
+}
+
+void WindowCompositorView::onXdgUnsetFullscreen()
+{
+ onXdgUnsetMaximized();
+}
+
WindowCompositor::WindowCompositor(QWindow *window)
: QWaylandCompositor()
, m_window(window)
, m_shell(new QWaylandShell(this))
+ , m_xdgShell(new QWaylandXdgShell(this))
{
connect(m_shell, &QWaylandShell::createShellSurface, this, &WindowCompositor::onCreateShellSurface);
+ connect(m_xdgShell, &QWaylandXdgShell::createXdgSurface, this, &WindowCompositor::onCreateXdgSurface);
+ connect(m_xdgShell, &QWaylandXdgShell::createXdgPopup, this, &WindowCompositor::onCreateXdgPopup);
}
WindowCompositor::~WindowCompositor()
@@ -112,8 +152,11 @@ void WindowCompositor::surfaceMappedChanged()
{
QWaylandSurface *surface = qobject_cast<QWaylandSurface *>(sender());
if (surface->isMapped()) {
- if (!surface->isCursorSurface())
+ if (surface->role() == QWaylandShellSurface::role()
+ || surface->role() == QWaylandXdgSurface::role()
+ || surface->role() == QWaylandXdgPopup::role()) {
defaultInputDevice()->setKeyboardFocus(surface);
+ }
} else if (popupActive()) {
for (int i = 0; i < m_popupViews.count(); i++) {
if (m_popupViews.at(i)->surface() == surface) {
@@ -160,6 +203,39 @@ void WindowCompositor::onCreateShellSurface(QWaylandSurface *s, const QWaylandRe
view->m_shellSurface = shellSurface;
}
+void WindowCompositor::onCreateXdgSurface(QWaylandSurface *surface, const QWaylandResource &res)
+{
+ QWaylandXdgSurface *xdgSurface = new QWaylandXdgSurface(m_xdgShell, surface, res);
+ connect(xdgSurface, &QWaylandXdgSurface::startMove, this, &WindowCompositor::onStartMove);
+ connect(xdgSurface, &QWaylandXdgSurface::startResize, this, &WindowCompositor::onXdgStartResize);
+
+ WindowCompositorView *view = findView(surface);
+ Q_ASSERT(view);
+ view->m_xdgSurface = xdgSurface;
+ connect(xdgSurface, &QWaylandXdgSurface::setMaximized, view, &WindowCompositorView::onXdgSetMaximized);
+ connect(xdgSurface, &QWaylandXdgSurface::setFullscreen, view, &WindowCompositorView::onXdgSetFullscreen);
+ connect(xdgSurface, &QWaylandXdgSurface::unsetMaximized, view, &WindowCompositorView::onXdgUnsetMaximized);
+ connect(xdgSurface, &QWaylandXdgSurface::unsetFullscreen, view, &WindowCompositorView::onXdgUnsetFullscreen);
+}
+
+void WindowCompositor::onCreateXdgPopup(QWaylandSurface *surface, QWaylandSurface *parent,
+ QWaylandInputDevice *inputDevice, const QPoint &position,
+ const QWaylandResource &resource)
+{
+ Q_UNUSED(inputDevice);
+
+ QWaylandXdgPopup *xdgPopup = new QWaylandXdgPopup(m_xdgShell, surface, parent, resource);
+
+ WindowCompositorView *view = findView(surface);
+ Q_ASSERT(view);
+
+ WindowCompositorView *parentView = findView(parent);
+ Q_ASSERT(parentView);
+
+ view->setPosition(parentView->position() + position);
+ view->m_xdgPopup = xdgPopup;
+}
+
void WindowCompositor::onStartMove()
{
closePopups();
@@ -169,7 +245,14 @@ void WindowCompositor::onStartMove()
void WindowCompositor::onStartResize(QWaylandInputDevice *, QWaylandShellSurface::ResizeEdge edges)
{
closePopups();
- emit startResize(int(edges));
+ emit startResize(int(edges), false);
+}
+
+void WindowCompositor::onXdgStartResize(QWaylandInputDevice *inputDevice,
+ QWaylandXdgSurface::ResizeEdge edges)
+{
+ Q_UNUSED(inputDevice);
+ emit startResize(int(edges), true);
}
void WindowCompositor::onSetTransient(QWaylandSurface *parent, const QPoint &relativeToParent, QWaylandShellSurface::FocusPolicy focusPolicy)
@@ -262,9 +345,14 @@ void WindowCompositor::adjustCursorSurface(QWaylandSurface *surface, int hotspot
void WindowCompositor::closePopups()
{
- Q_FOREACH (WindowCompositorView *view, m_popupViews)
- view->m_shellSurface->sendPopupDone();
- m_popupViews.clear();
+ Q_FOREACH (WindowCompositorView *view, m_popupViews) {
+ if (view->m_shellSurface) {
+ view->m_shellSurface->sendPopupDone();
+ m_popupViews.clear();
+ }
+ }
+
+ m_xdgShell->closeAllPopups();
}
void WindowCompositor::handleMouseEvent(QWaylandView *target, QMouseEvent *me)
@@ -274,9 +362,18 @@ void WindowCompositor::handleMouseEvent(QWaylandView *target, QMouseEvent *me)
closePopups();
}
QWaylandInputDevice *input = defaultInputDevice();
+ QWaylandSurface *surface = target ? target->surface() : nullptr;
switch (me->type()) {
case QEvent::MouseButtonPress:
input->sendMousePressEvent(me->button());
+ if (surface != input->keyboardFocus()) {
+ if (surface == nullptr
+ || surface->role() == QWaylandShellSurface::role()
+ || surface->role() == QWaylandXdgSurface::role()
+ || surface->role() == QWaylandXdgPopup::role()) {
+ input->setKeyboardFocus(surface);
+ }
+ }
break;
case QEvent::MouseButtonRelease:
input->sendMouseReleaseEvent(me->button());
@@ -291,11 +388,18 @@ void WindowCompositor::handleMouseEvent(QWaylandView *target, QMouseEvent *me)
void WindowCompositor::handleResize(WindowCompositorView *target, const QSize &initialSize, const QPoint &delta, int edge)
{
QWaylandShellSurface *shellSurface = target->m_shellSurface;
- if (!shellSurface)
- return;
- QWaylandShellSurface::ResizeEdge edges = QWaylandShellSurface::ResizeEdge(edge);
- QSize newSize = shellSurface->sizeForResize(initialSize, delta, edges);
- shellSurface->sendConfigure(newSize, edges);
+ if (shellSurface) {
+ QWaylandShellSurface::ResizeEdge edges = QWaylandShellSurface::ResizeEdge(edge);
+ QSize newSize = shellSurface->sizeForResize(initialSize, delta, edges);
+ shellSurface->sendConfigure(newSize, edges);
+ }
+
+ QWaylandXdgSurface *xdgSurface = target->m_xdgSurface;
+ if (xdgSurface) {
+ QWaylandXdgSurface::ResizeEdge edges = static_cast<QWaylandXdgSurface::ResizeEdge>(edge);
+ QSize newSize = xdgSurface->sizeForResize(initialSize, delta, edges);
+ xdgSurface->requestResizing(newSize);
+ }
}
void WindowCompositor::startDrag()
diff --git a/examples/wayland/qwindow-compositor/windowcompositor.h b/examples/wayland/qwindow-compositor/windowcompositor.h
index 5eac05c50..3c5525a3b 100644
--- a/examples/wayland/qwindow-compositor/windowcompositor.h
+++ b/examples/wayland/qwindow-compositor/windowcompositor.h
@@ -45,11 +45,13 @@
#include <QtWaylandCompositor/QWaylandSurface>
#include <QtWaylandCompositor/QWaylandView>
#include <QtWaylandCompositor/QWaylandShellSurface>
+#include <QtWaylandCompositor/QWaylandXdgSurface>
#include <QTimer>
QT_BEGIN_NAMESPACE
class QWaylandShell;
+class QWaylandXdgShell;
class QWaylandShellSurface;
class WindowCompositorView : public QWaylandView
@@ -65,13 +67,22 @@ public:
void setParentView(WindowCompositorView *parent) { m_parentView = parent; }
WindowCompositorView *parentView() const { return m_parentView; }
QPointF parentPosition() const { return m_parentView ? (m_parentView->position() + m_parentView->parentPosition()) : QPointF(); }
+ QSize windowSize() { return m_xdgSurface ? m_xdgSurface->windowGeometry().size() : surface()->size(); }
private:
friend class WindowCompositor;
GLuint m_texture;
QPointF m_position;
QWaylandShellSurface *m_shellSurface;
+ QWaylandXdgSurface *m_xdgSurface;
+ QWaylandXdgPopup *m_xdgPopup;
WindowCompositorView *m_parentView;
+
+public slots:
+ void onXdgSetMaximized();
+ void onXdgUnsetMaximized();
+ void onXdgSetFullscreen(QWaylandOutput *output);
+ void onXdgUnsetFullscreen();
};
class WindowCompositor : public QWaylandCompositor
@@ -99,7 +110,7 @@ protected:
signals:
void startMove();
- void startResize(int edge);
+ void startResize(int edge, bool anchored);
void dragStarted(WindowCompositorView *dragIcon);
void frameOffset(const QPoint &offset);
@@ -109,6 +120,7 @@ private slots:
void viewSurfaceDestroyed();
void onStartMove();
void onStartResize(QWaylandInputDevice *inputDevice, QWaylandShellSurface::ResizeEdge edges);
+ void onXdgStartResize(QWaylandInputDevice *inputDevice, QWaylandXdgSurface::ResizeEdge edges);
void startDrag();
@@ -116,6 +128,9 @@ private slots:
void onSurfaceCreated(QWaylandSurface *surface);
void onCreateShellSurface(QWaylandSurface *s, const QWaylandResource &resource);
+ void onCreateXdgSurface(QWaylandSurface *surface, const QWaylandResource &resource);
+ void onCreateXdgPopup(QWaylandSurface *surface, QWaylandSurface *parent, QWaylandInputDevice *inputDevice,
+ const QPoint &position, const QWaylandResource &resource);
void onSetTransient(QWaylandSurface *parentSurface, const QPoint &relativeToParent, QWaylandShellSurface::FocusPolicy focusPolicy);
void onSetPopup(QWaylandInputDevice *inputDevice, QWaylandSurface *parent, const QPoint &relativeToParent);
@@ -129,6 +144,7 @@ private:
QList<WindowCompositorView*> m_views;
QList<WindowCompositorView*> m_popupViews;
QWaylandShell *m_shell;
+ QWaylandXdgShell *m_xdgShell;
QWaylandView m_cursorView;
int m_cursorHotspotX;
int m_cursorHotspotY;
diff --git a/src/compositor/compositor_api/qwaylandcompositor.cpp b/src/compositor/compositor_api/qwaylandcompositor.cpp
index 6d7954aa7..57e8397b9 100644
--- a/src/compositor/compositor_api/qwaylandcompositor.cpp
+++ b/src/compositor/compositor_api/qwaylandcompositor.cpp
@@ -342,8 +342,9 @@ void QWaylandCompositorPrivate::initializeHardwareIntegration()
void QWaylandCompositorPrivate::initializeDefaultInputDevice()
{
Q_Q(QWaylandCompositor);
- inputDevices.append(q->createInputDevice());
- q->defaultInputDeviceChanged();
+ QWaylandInputDevice *device = q->createInputDevice();
+ inputDevices.append(device);
+ q->defaultInputDeviceChanged(device, nullptr);
}
void QWaylandCompositorPrivate::loadClientBufferIntegration()
diff --git a/src/compositor/compositor_api/qwaylandcompositor.h b/src/compositor/compositor_api/qwaylandcompositor.h
index d8a5d9ca3..ab90e12f9 100644
--- a/src/compositor/compositor_api/qwaylandcompositor.h
+++ b/src/compositor/compositor_api/qwaylandcompositor.h
@@ -125,7 +125,7 @@ Q_SIGNALS:
void subsurfaceChanged(QWaylandSurface *child, QWaylandSurface *parent);
void defaultOutputChanged();
- void defaultInputDeviceChanged();
+ void defaultInputDeviceChanged(QWaylandInputDevice *newDevice, QWaylandInputDevice *oldDevice);
void useHardwareIntegrationExtensionChanged();
protected:
diff --git a/src/compositor/compositor_api/qwaylandinput.cpp b/src/compositor/compositor_api/qwaylandinput.cpp
index becbf10ae..512ad6e37 100644
--- a/src/compositor/compositor_api/qwaylandinput.cpp
+++ b/src/compositor/compositor_api/qwaylandinput.cpp
@@ -42,6 +42,7 @@
#include <QtWaylandCompositor/QWaylandDrag>
#include <QtWaylandCompositor/QWaylandTouch>
#include <QtWaylandCompositor/QWaylandPointer>
+#include <QtWaylandCompositor/QWaylandShellSurface>
#include <QtWaylandCompositor/private/qwlinputmethod_p.h>
#include <QtWaylandCompositor/private/qwaylandinput_p.h>
#include <QtWaylandCompositor/private/qwaylandcompositor_p.h>
@@ -56,6 +57,7 @@ QWaylandInputDevicePrivate::QWaylandInputDevicePrivate(QWaylandInputDevice *inpu
, QtWaylandServer::wl_seat(compositor->display(), 4)
, compositor(compositor)
, mouseFocus(Q_NULLPTR)
+ , keyboardFocus(nullptr)
, capabilities()
, data_device()
, drag_handle(new QWaylandDrag(inputdevice))
@@ -89,6 +91,9 @@ void QWaylandInputDevicePrivate::setCapabilities(QWaylandInputDevice::Capability
for (int i = 0; i < resources.size(); i++) {
wl_seat::send_capabilities(resources.at(i)->handle, (uint32_t)capabilities);
}
+
+ if ((changed & caps & QWaylandInputDevice::Keyboard) && keyboardFocus != nullptr)
+ keyboard->setFocus(keyboardFocus);
}
}
@@ -337,15 +342,21 @@ bool QWaylandInputDevice::setKeyboardFocus(QWaylandSurface *surface)
if (surface && surface->isDestroyed())
return false;
- if (surface == keyboardFocus())
+ QWaylandSurface *oldSurface = keyboardFocus();
+ if (surface == oldSurface)
return true;
- if (!d->keyboard.isNull() && d->keyboard->setFocus(surface)) {
- if (d->data_device)
- d->data_device->setFocus(d->keyboard->focusClient());
- return true;
- }
- return false;
+ QWaylandShellSurface *shellsurface = QWaylandShellSurface::findIn(surface);
+ if (shellsurface && shellsurface->focusPolicy() == QWaylandShellSurface::NoKeyboardFocus)
+ return false;
+
+ d->keyboardFocus = surface;
+ if (!d->keyboard.isNull())
+ d->keyboard->setFocus(surface);
+ if (d->data_device)
+ d->data_device->setFocus(surface->client());
+ emit keyboardFocusChanged(surface, oldSurface);
+ return true;
}
/*!
diff --git a/src/compositor/compositor_api/qwaylandinput.h b/src/compositor/compositor_api/qwaylandinput.h
index 794585009..7384e1e5a 100644
--- a/src/compositor/compositor_api/qwaylandinput.h
+++ b/src/compositor/compositor_api/qwaylandinput.h
@@ -124,6 +124,7 @@ public:
Q_SIGNALS:
void mouseFocusChanged(QWaylandView *newFocus, QWaylandView *oldFocus);
+ void keyboardFocusChanged(QWaylandSurface *newFocus, QWaylandSurface *oldFocus);
void cursorSurfaceRequest(QWaylandSurface *surface, int hotspotX, int hotspotY);
};
diff --git a/src/compositor/compositor_api/qwaylandinput_p.h b/src/compositor/compositor_api/qwaylandinput_p.h
index ec8742d15..5e57c43cc 100644
--- a/src/compositor/compositor_api/qwaylandinput_p.h
+++ b/src/compositor/compositor_api/qwaylandinput_p.h
@@ -115,6 +115,7 @@ protected:
private:
QWaylandCompositor *compositor;
QWaylandView *mouseFocus;
+ QWaylandSurface *keyboardFocus;
QWaylandInputDevice::CapabilityFlags capabilities;
QScopedPointer<QWaylandPointer> pointer;
diff --git a/src/compositor/compositor_api/qwaylandkeyboard.cpp b/src/compositor/compositor_api/qwaylandkeyboard.cpp
index a707d6470..caf2c9255 100644
--- a/src/compositor/compositor_api/qwaylandkeyboard.cpp
+++ b/src/compositor/compositor_api/qwaylandkeyboard.cpp
@@ -41,8 +41,6 @@
#include <QtWaylandCompositor/QWaylandInputDevice>
#include <QtWaylandCompositor/QWaylandClient>
-#include <QtWaylandCompositor/QWaylandShellSurface>
-
#include <QtCore/QFile>
#include <QtCore/QStandardPaths>
@@ -532,14 +530,10 @@ QWaylandSurface *QWaylandKeyboard::focus() const
/*!
* Sets the current focus to \a surface.
*/
-bool QWaylandKeyboard::setFocus(QWaylandSurface *surface)
+void QWaylandKeyboard::setFocus(QWaylandSurface *surface)
{
Q_D(QWaylandKeyboard);
- QWaylandShellSurface *shellsurface = QWaylandShellSurface::findIn(surface);
- if (shellsurface && shellsurface->focusPolicy() == QWaylandShellSurface::NoKeyboardFocus)
- return false;
d->focused(surface);
- return true;
}
/*!
diff --git a/src/compositor/compositor_api/qwaylandkeyboard.h b/src/compositor/compositor_api/qwaylandkeyboard.h
index 89b13eeaf..e327cd3d6 100644
--- a/src/compositor/compositor_api/qwaylandkeyboard.h
+++ b/src/compositor/compositor_api/qwaylandkeyboard.h
@@ -87,7 +87,7 @@ public:
quint32 repeatDelay() const;
void setRepeatDelay(quint32 delay);
- virtual bool setFocus(QWaylandSurface *surface);
+ virtual void setFocus(QWaylandSurface *surface);
virtual void setKeymap(const QWaylandKeymap &keymap);
virtual void sendKeyModifiers(QWaylandClient *client, uint32_t serial);
diff --git a/src/compositor/compositor_api/qwaylandsurface.cpp b/src/compositor/compositor_api/qwaylandsurface.cpp
index 3ea2bc87c..97e4b6a80 100644
--- a/src/compositor/compositor_api/qwaylandsurface.cpp
+++ b/src/compositor/compositor_api/qwaylandsurface.cpp
@@ -768,6 +768,12 @@ bool QWaylandSurface::setRole(QWaylandSurfaceRole *role, wl_resource *errorResou
return true;
}
+QWaylandSurfaceRole *QWaylandSurface::role() const
+{
+ Q_D(const QWaylandSurface);
+ return d->role;
+}
+
QWaylandSurfacePrivate *QWaylandSurfacePrivate::get(QWaylandSurface *surface)
{
return surface ? surface->d_func() : Q_NULLPTR;
diff --git a/src/compositor/compositor_api/qwaylandsurface.h b/src/compositor/compositor_api/qwaylandsurface.h
index ccafd1dd3..82286cdfc 100644
--- a/src/compositor/compositor_api/qwaylandsurface.h
+++ b/src/compositor/compositor_api/qwaylandsurface.h
@@ -100,6 +100,7 @@ public:
struct wl_client *waylandClient() const { return client()->client(); }
bool setRole(QWaylandSurfaceRole *role, wl_resource *errorResource, uint32_t errorCode);
+ QWaylandSurfaceRole *role() const;
bool isMapped() const;
diff --git a/src/compositor/extensions/extensions.pri b/src/compositor/extensions/extensions.pri
index bede92580..a62490585 100644
--- a/src/compositor/extensions/extensions.pri
+++ b/src/compositor/extensions/extensions.pri
@@ -6,6 +6,7 @@ WAYLANDSERVERSOURCES += \
../extensions/windowmanager.xml \
../3rdparty/protocol/input-method.xml \
../3rdparty/protocol/text.xml \
+ ../3rdparty/protocol/xdg-shell.xml \
HEADERS += \
extensions/qwlextendedsurface_p.h \
@@ -21,6 +22,8 @@ HEADERS += \
extensions/qwlinputpanelsurface_p.h \
extensions/qwlinputmethod_p.h \
extensions/qwlinputmethodcontext_p.h \
+ extensions/qwaylandxdgshell.h \
+ extensions/qwaylandxdgshell_p.h \
SOURCES += \
extensions/qwlextendedsurface.cpp \
@@ -34,6 +37,7 @@ SOURCES += \
extensions/qwlinputpanelsurface.cpp \
extensions/qwlinputmethod.cpp \
extensions/qwlinputmethodcontext.cpp \
+ extensions/qwaylandxdgshell.cpp \
qtHaveModule(quick) {
HEADERS += \
diff --git a/src/compositor/extensions/qwaylandxdgshell.cpp b/src/compositor/extensions/qwaylandxdgshell.cpp
new file mode 100644
index 000000000..bd25e3ca3
--- /dev/null
+++ b/src/compositor/extensions/qwaylandxdgshell.cpp
@@ -0,0 +1,1049 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later 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 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwaylandxdgshell.h"
+#include "qwaylandxdgshell_p.h"
+
+#include <QtWaylandCompositor/QWaylandCompositor>
+#include <QtWaylandCompositor/QWaylandSurface>
+#include <QtWaylandCompositor/QWaylandSurfaceRole>
+#include <QtWaylandCompositor/QWaylandResource>
+#include <QtWaylandCompositor/QWaylandInputDevice>
+
+#include <QtCore/QObject>
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+QWaylandSurfaceRole QWaylandXdgSurfacePrivate::s_role("xdg_surface");
+QWaylandSurfaceRole QWaylandXdgPopupPrivate::s_role("xdg_popup");
+
+QWaylandXdgShellPrivate::QWaylandXdgShellPrivate()
+ : QWaylandExtensionTemplatePrivate()
+ , xdg_shell()
+{
+}
+
+void QWaylandXdgShellPrivate::ping(Resource *resource, uint32_t serial)
+{
+ m_pings.insert(serial);
+ send_ping(resource->handle, serial);
+}
+
+void QWaylandXdgShellPrivate::registerSurface(QWaylandXdgSurface *xdgSurface)
+{
+ m_xdgSurfaces.insert(xdgSurface->surface()->client()->client(), xdgSurface);
+}
+
+void QWaylandXdgShellPrivate::unregisterXdgSurface(QWaylandXdgSurface *xdgSurface)
+{
+ auto xdgSurfacePrivate = QWaylandXdgSurfacePrivate::get(xdgSurface);
+ if (!m_xdgSurfaces.remove(xdgSurfacePrivate->resource()->client(), xdgSurface))
+ qWarning("%s Unexpected state. Can't find registered xdg surface\n", Q_FUNC_INFO);
+}
+
+void QWaylandXdgShellPrivate::registerXdgPopup(QWaylandXdgPopup *xdgPopup)
+{
+ m_xdgPopups.insert(xdgPopup->surface()->client()->client(), xdgPopup);
+}
+
+void QWaylandXdgShellPrivate::unregisterXdgPopup(QWaylandXdgPopup *xdgPopup)
+{
+ auto xdgPopupPrivate = QWaylandXdgPopupPrivate::get(xdgPopup);
+ if (!m_xdgPopups.remove(xdgPopupPrivate->resource()->client(), xdgPopup))
+ qWarning("%s Unexpected state. Can't find registered xdg popup\n", Q_FUNC_INFO);
+}
+
+bool QWaylandXdgShellPrivate::isValidPopupParent(QWaylandSurface *parentSurface) const
+{
+ QWaylandXdgPopup *topmostPopup = topmostPopupForClient(parentSurface->client()->client());
+ if (topmostPopup && topmostPopup->surface() != parentSurface) {
+ return false;
+ }
+
+ QWaylandSurfaceRole *parentRole = parentSurface->role();
+ if (parentRole != QWaylandXdgSurface::role() && parentRole != QWaylandXdgPopup::role()) {
+ return false;
+ }
+
+ return true;
+}
+
+QWaylandXdgPopup *QWaylandXdgShellPrivate::topmostPopupForClient(wl_client *client) const
+{
+ QList<QWaylandXdgPopup *> clientPopups = m_xdgPopups.values(client);
+ return clientPopups.empty() ? nullptr : clientPopups.last();
+}
+
+QWaylandXdgSurface *QWaylandXdgShellPrivate::xdgSurfaceFromSurface(QWaylandSurface *surface)
+{
+ Q_FOREACH (QWaylandXdgSurface *xdgSurface, m_xdgSurfaces) {
+ if (surface == xdgSurface->surface())
+ return xdgSurface;
+ }
+ return nullptr;
+}
+
+void QWaylandXdgShellPrivate::xdg_shell_destroy(Resource *resource)
+{
+ if (!m_xdgSurfaces.values(resource->client()).empty())
+ wl_resource_post_error(resource->handle, XDG_SHELL_ERROR_DEFUNCT_SURFACES,
+ "xdg_shell was destroyed before children");
+
+ wl_resource_destroy(resource->handle);
+}
+
+void QWaylandXdgShellPrivate::xdg_shell_get_xdg_surface(Resource *resource, uint32_t id,
+ wl_resource *surface_res)
+{
+ Q_Q(QWaylandXdgShell);
+ QWaylandSurface *surface = QWaylandSurface::fromResource(surface_res);
+
+ if (xdgSurfaceFromSurface(surface)) {
+ wl_resource_post_error(resource->handle, XDG_SHELL_ERROR_ROLE,
+ "An active xdg_surface already exists for wl_surface@%d",
+ wl_resource_get_id(surface->resource()));
+ return;
+ }
+
+ if (!surface->setRole(QWaylandXdgSurface::role(), resource->handle, XDG_SHELL_ERROR_ROLE))
+ return;
+
+ QWaylandResource xdgSurfaceResource(wl_resource_create(resource->client(), &xdg_surface_interface,
+ wl_resource_get_version(resource->handle), id));
+
+ emit q->createXdgSurface(surface, xdgSurfaceResource);
+
+ QWaylandXdgSurface *xdgSurface = QWaylandXdgSurface::fromResource(xdgSurfaceResource.resource());
+ if (!xdgSurface) {
+ // A QWaylandXdgSurface was not created in response to the createXdgSurface signal, so we
+ // create one as fallback here instead.
+ xdgSurface = new QWaylandXdgSurface(q, surface, xdgSurfaceResource);
+ }
+
+ registerSurface(xdgSurface);
+ emit q->xdgSurfaceCreated(xdgSurface);
+}
+
+void QWaylandXdgShellPrivate::xdg_shell_use_unstable_version(Resource *resource, int32_t version)
+{
+ if (xdg_shell::version_current != version) {
+ wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "incompatible version, server is %d, but client wants %d",
+ xdg_shell::version_current, version);
+ }
+}
+
+void QWaylandXdgShellPrivate::xdg_shell_get_xdg_popup(Resource *resource, uint32_t id,
+ wl_resource *surface_res, wl_resource *parent,
+ wl_resource *seat, uint32_t serial,
+ int32_t x, int32_t y)
+{
+ Q_UNUSED(serial);
+ Q_Q(QWaylandXdgShell);
+ QWaylandSurface *surface = QWaylandSurface::fromResource(surface_res);
+ QWaylandSurface *parentSurface = QWaylandSurface::fromResource(parent);
+
+ if (!isValidPopupParent(parentSurface)) {
+ wl_resource_post_error(resource->handle, XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
+ "the client specified an invalid popup parent surface");
+ return;
+ }
+
+ if (!surface->setRole(QWaylandXdgPopup::role(), resource->handle, XDG_SHELL_ERROR_ROLE)) {
+ return;
+ }
+
+ QWaylandResource xdgPopupResource (wl_resource_create(resource->client(), &xdg_popup_interface,
+ wl_resource_get_version(resource->handle), id));
+ QWaylandInputDevice *inputDevice = QWaylandInputDevice::fromSeatResource(seat);
+ QPoint position(x, y);
+ emit q->createXdgPopup(surface, parentSurface, inputDevice, position, xdgPopupResource);
+
+ QWaylandXdgPopup *xdgPopup = QWaylandXdgPopup::fromResource(xdgPopupResource.resource());
+ if (!xdgPopup) {
+ // A QWaylandXdgPopup was not created in response to the createXdgPopup signal, so we
+ // create one as fallback here instead.
+ xdgPopup = new QWaylandXdgPopup(q, surface, parentSurface, xdgPopupResource);
+ }
+
+ registerXdgPopup(xdgPopup);
+ emit q->xdgPopupCreated(xdgPopup);
+}
+
+void QWaylandXdgShellPrivate::xdg_shell_pong(Resource *resource, uint32_t serial)
+{
+ Q_UNUSED(resource);
+ Q_Q(QWaylandXdgShell);
+ if (m_pings.remove(serial))
+ emit q->pong(serial);
+ else
+ qWarning("Received an unexpected pong!");
+}
+
+QWaylandXdgSurfacePrivate::QWaylandXdgSurfacePrivate()
+ : QWaylandExtensionTemplatePrivate()
+ , xdg_surface()
+ , m_surface(nullptr)
+ , m_parentSurface(nullptr)
+ , m_unsetWindowGeometry(true)
+ , m_lastAckedConfigure({{}, QSize(0, 0), 0})
+{
+}
+
+void QWaylandXdgSurfacePrivate::handleFocusLost()
+{
+ Q_Q(QWaylandXdgSurface);
+ QWaylandXdgSurfacePrivate::ConfigureEvent current = lastSentConfigure();
+ current.states.removeOne(QWaylandXdgSurface::State::ActivatedState);
+ q->sendConfigure(current.size, current.states);
+}
+
+void QWaylandXdgSurfacePrivate::handleFocusReceived()
+{
+ Q_Q(QWaylandXdgSurface);
+
+ QWaylandXdgSurfacePrivate::ConfigureEvent current = lastSentConfigure();
+ if (!current.states.contains(QWaylandXdgSurface::State::ActivatedState)) {
+ current.states.push_back(QWaylandXdgSurface::State::ActivatedState);
+ }
+
+ q->sendConfigure(current.size, current.states);
+}
+
+void QWaylandXdgSurfacePrivate::xdg_surface_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource);
+ Q_Q(QWaylandXdgSurface);
+ QWaylandXdgShellPrivate::get(m_xdgShell)->unregisterXdgSurface(q);
+ delete q;
+}
+
+void QWaylandXdgSurfacePrivate::xdg_surface_destroy(Resource *resource)
+{
+ wl_resource_destroy(resource->handle);
+}
+
+void QWaylandXdgSurfacePrivate::xdg_surface_move(Resource *resource, wl_resource *seat, uint32_t serial)
+{
+ Q_UNUSED(resource);
+ Q_UNUSED(serial);
+
+ Q_Q(QWaylandXdgSurface);
+ QWaylandInputDevice *input_device = QWaylandInputDevice::fromSeatResource(seat);
+ emit q->startMove(input_device);
+}
+
+void QWaylandXdgSurfacePrivate::xdg_surface_resize(Resource *resource, wl_resource *seat,
+ uint32_t serial, uint32_t edges)
+{
+ Q_UNUSED(resource);
+ Q_UNUSED(serial);
+
+ Q_Q(QWaylandXdgSurface);
+ QWaylandInputDevice *input_device = QWaylandInputDevice::fromSeatResource(seat);
+ emit q->startResize(input_device, QWaylandXdgSurface::ResizeEdge(edges));
+}
+
+void QWaylandXdgSurfacePrivate::xdg_surface_set_maximized(Resource *resource)
+{
+ Q_UNUSED(resource);
+ Q_Q(QWaylandXdgSurface);
+ emit q->setMaximized();
+}
+
+void QWaylandXdgSurfacePrivate::xdg_surface_unset_maximized(Resource *resource)
+{
+ Q_UNUSED(resource);
+ Q_Q(QWaylandXdgSurface);
+ emit q->unsetMaximized();
+}
+
+void QWaylandXdgSurfacePrivate::xdg_surface_set_fullscreen(Resource *resource, wl_resource *output_res)
+{
+ Q_UNUSED(resource);
+ Q_Q(QWaylandXdgSurface);
+ QWaylandOutput *output = output_res ? QWaylandOutput::fromResource(output_res) : nullptr;
+ emit q->setFullscreen(output);
+}
+
+void QWaylandXdgSurfacePrivate::xdg_surface_unset_fullscreen(Resource *resource)
+{
+ Q_UNUSED(resource);
+ Q_Q(QWaylandXdgSurface);
+ emit q->unsetFullscreen();
+}
+
+void QWaylandXdgSurfacePrivate::xdg_surface_set_minimized(Resource *resource)
+{
+ Q_UNUSED(resource);
+ Q_Q(QWaylandXdgSurface);
+ emit q->setMinimized();
+}
+
+void QWaylandXdgSurfacePrivate::xdg_surface_set_parent(Resource *resource, wl_resource *parent)
+{
+ Q_UNUSED(resource);
+ QWaylandXdgSurface *parentSurface = nullptr;
+ if (parent) {
+ parentSurface = static_cast<QWaylandXdgSurfacePrivate *>(
+ QWaylandXdgSurfacePrivate::Resource::fromResource(parent)->xdg_surface_object)->q_func();
+ }
+
+ if (m_parentSurface == parentSurface)
+ return;
+
+ Q_Q(QWaylandXdgSurface);
+ m_parentSurface = parentSurface;
+ emit q->parentSurfaceChanged();
+}
+
+void QWaylandXdgSurfacePrivate::xdg_surface_set_app_id(Resource *resource, const QString &app_id)
+{
+ Q_UNUSED(resource);
+ if (app_id == m_appId)
+ return;
+ Q_Q(QWaylandXdgSurface);
+ m_appId = app_id;
+ emit q->appIdChanged();
+}
+
+void QWaylandXdgSurfacePrivate::xdg_surface_show_window_menu(Resource *resource, wl_resource *seat,
+ uint32_t serial, int32_t x, int32_t y)
+{
+ Q_UNUSED(resource);
+ Q_UNUSED(serial);
+ QPoint position(x, y);
+ auto inputDevice = QWaylandInputDevice::fromSeatResource(seat);
+ Q_Q(QWaylandXdgSurface);
+ emit q->showWindowMenu(inputDevice, position);
+}
+
+void QWaylandXdgSurfacePrivate::xdg_surface_ack_configure(Resource *resource, uint32_t serial)
+{
+ Q_UNUSED(resource);
+ Q_Q(QWaylandXdgSurface);
+
+ ConfigureEvent config;
+ Q_FOREVER {
+ if (m_pendingConfigures.empty()) {
+ qWarning("Received an unexpected ack_configure!");
+ return;
+ }
+
+ config = m_pendingConfigures.takeFirst();
+
+ if (config.serial == serial)
+ break;
+ }
+
+ QVector<uint> changedStates;
+ std::set_symmetric_difference(
+ m_lastAckedConfigure.states.begin(), m_lastAckedConfigure.states.end(),
+ config.states.begin(), config.states.end(),
+ std::back_inserter(changedStates));
+
+ m_lastAckedConfigure = config;
+
+ if (!changedStates.empty()) {
+ Q_FOREACH (uint state, changedStates) {
+ switch (state) {
+ case QWaylandXdgSurface::State::MaximizedState:
+ emit q->maximizedChanged();
+ break;
+ case QWaylandXdgSurface::State::FullscreenState:
+ emit q->fullscreenChanged();
+ break;
+ case QWaylandXdgSurface::State::ResizingState:
+ emit q->resizingChanged();
+ break;
+ case QWaylandXdgSurface::State::ActivatedState:
+ emit q->activatedChanged();
+ break;
+ }
+ }
+ emit q->statesChanged();
+ }
+
+ emit q->ackConfigure(serial);
+}
+
+void QWaylandXdgSurfacePrivate::xdg_surface_set_title(Resource *resource, const QString &title)
+{
+ Q_UNUSED(resource);
+ if (title == m_title)
+ return;
+ Q_Q(QWaylandXdgSurface);
+ m_title = title;
+ emit q->titleChanged();
+}
+
+void QWaylandXdgSurfacePrivate::xdg_surface_set_window_geometry(Resource *resource,
+ int32_t x, int32_t y,
+ int32_t width, int32_t height)
+{
+ Q_UNUSED(resource);
+
+ if (width <= 0 || height <= 0) {
+ qWarning() << "Invalid (non-positive) dimensions received in set_window_geometry";
+ return;
+ }
+
+ m_unsetWindowGeometry = false;
+
+ QRect geometry(x, y, width, height);
+
+ Q_Q(QWaylandXdgSurface);
+ if ((q->maximized() || q->fullscreen()) && m_lastAckedConfigure.size != geometry.size())
+ qWarning() << "Client window geometry did not obey last acked configure";
+
+ if (geometry == m_windowGeometry)
+ return;
+
+ m_windowGeometry = geometry;
+ emit q->windowGeometryChanged();
+}
+
+QWaylandXdgPopupPrivate::QWaylandXdgPopupPrivate()
+ : QWaylandExtensionTemplatePrivate()
+ , xdg_popup()
+ , m_surface(nullptr)
+ , m_parentSurface(nullptr)
+ , m_xdgShell(nullptr)
+{
+}
+
+void QWaylandXdgPopupPrivate::xdg_popup_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource);
+ Q_Q(QWaylandXdgPopup);
+ QWaylandXdgShellPrivate::get(m_xdgShell)->unregisterXdgPopup(q);
+ delete q;
+}
+
+void QWaylandXdgPopupPrivate::xdg_popup_destroy(Resource *resource)
+{
+ //TODO: post error if not topmost popup
+ wl_resource_destroy(resource->handle);
+}
+
+/*!
+ * Constructs a QWaylandXdgShell object.
+ */
+QWaylandXdgShell::QWaylandXdgShell()
+ : QWaylandExtensionTemplate<QWaylandXdgShell>(*new QWaylandXdgShellPrivate())
+{ }
+
+/*!
+ * Constructs a QWaylandXdgShell object for the provided \a compositor.
+ */
+QWaylandXdgShell::QWaylandXdgShell(QWaylandCompositor *compositor)
+ : QWaylandExtensionTemplate<QWaylandXdgShell>(compositor, *new QWaylandXdgShellPrivate())
+{ }
+
+/*!
+ * Initializes the shell extension.
+ */
+void QWaylandXdgShell::initialize()
+{
+ Q_D(QWaylandXdgShell);
+ QWaylandExtensionTemplate::initialize();
+ QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
+ if (!compositor) {
+ qWarning() << "Failed to find QWaylandCompositor when initializing QWaylandXdgShell";
+ return;
+ }
+ d->init(compositor->display(), 1);
+
+ handleDefaultInputDeviceChanged(compositor->defaultInputDevice(), nullptr);
+
+ connect(compositor, &QWaylandCompositor::defaultInputDeviceChanged,
+ this, &QWaylandXdgShell::handleDefaultInputDeviceChanged);
+}
+
+/*!
+ * Returns the Wayland interface for the QWaylandXdgShell.
+ */
+const struct wl_interface *QWaylandXdgShell::interface()
+{
+ return QWaylandXdgShellPrivate::interface();
+}
+
+QByteArray QWaylandXdgShell::interfaceName()
+{
+ return QWaylandXdgShellPrivate::interfaceName();
+}
+
+/*!
+ * \qmlmethod void QtWaylandCompositor::XdgSurface::ping()
+ *
+ * Sends a ping event to the client. If the client replies to the event the
+ * \a pong signal will be emitted.
+ */
+
+/*!
+ * Sends a ping event to the client. If the client replies to the event the
+ * \a pong signal will be emitted.
+ */
+uint QWaylandXdgShell::ping(QWaylandClient *client)
+{
+ Q_D(QWaylandXdgShell);
+
+ QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
+ Q_ASSERT(compositor);
+
+ uint32_t serial = compositor->nextSerial();
+
+ QWaylandXdgShellPrivate::Resource *clientResource = d->resourceMap().value(client->client(), nullptr);
+ Q_ASSERT(clientResource);
+
+ d->ping(clientResource, serial);
+ return serial;
+}
+
+void QWaylandXdgShell::closeAllPopups()
+{
+ Q_D(QWaylandXdgShell);
+ Q_FOREACH (struct wl_client *client, d->m_xdgPopups.keys()) {
+ QList<QWaylandXdgPopup *> popups = d->m_xdgPopups.values(client);
+ std::reverse(popups.begin(), popups.end());
+ Q_FOREACH (QWaylandXdgPopup *currentTopmostPopup, popups) {
+ currentTopmostPopup->sendPopupDone();
+ }
+ }
+}
+
+void QWaylandXdgShell::handleDefaultInputDeviceChanged(QWaylandInputDevice *newDevice, QWaylandInputDevice *oldDevice)
+{
+ if (oldDevice != nullptr) {
+ disconnect(oldDevice, &QWaylandInputDevice::keyboardFocusChanged,
+ this, &QWaylandXdgShell::handleFocusChanged);
+ }
+
+ if (newDevice != nullptr) {
+ connect(newDevice, &QWaylandInputDevice::keyboardFocusChanged,
+ this, &QWaylandXdgShell::handleFocusChanged);
+ }
+}
+
+void QWaylandXdgShell::handleFocusChanged(QWaylandSurface *newSurface, QWaylandSurface *oldSurface)
+{
+ Q_D(QWaylandXdgShell);
+
+ QWaylandXdgSurface *newXdgSurface = d->xdgSurfaceFromSurface(newSurface);
+ QWaylandXdgSurface *oldXdgSurface = d->xdgSurfaceFromSurface(oldSurface);
+
+ if (newXdgSurface)
+ QWaylandXdgSurfacePrivate::get(newXdgSurface)->handleFocusReceived();
+
+ if (oldXdgSurface)
+ QWaylandXdgSurfacePrivate::get(oldXdgSurface)->handleFocusLost();
+}
+
+/*!
+ * \class QWaylandXdgSurface
+ * \inmodule QtWaylandCompositor
+ * \brief An xdg surface providing desktop-style compositor-specific features to a surface.
+ *
+ * This class is part of the QWaylandXdgShell extension and provides a way to
+ * extend the functionality of an existing QWaylandSurface with features
+ * specific to desktop-style compositors, such as resizing and moving the
+ * surface.
+ *
+ * It corresponds to the Wayland interface xdg_surface.
+ */
+
+/*!
+ * Constructs a QWaylandXdgSurface.
+ */
+QWaylandXdgSurface::QWaylandXdgSurface()
+ : QWaylandExtensionTemplate<QWaylandXdgSurface>(*new QWaylandXdgSurfacePrivate)
+{
+}
+
+/*!
+ * Constructs a QWaylandXdgSurface for \a surface and initializes it with the
+ * given \a xdgShell, \a surface and \a resource.
+ */
+QWaylandXdgSurface::QWaylandXdgSurface(QWaylandXdgShell *xdgShell, QWaylandSurface *surface, const QWaylandResource &res)
+ : QWaylandExtensionTemplate<QWaylandXdgSurface>(*new QWaylandXdgSurfacePrivate)
+{
+ initialize(xdgShell, surface, res);
+}
+
+/*!
+ * \qmlmethod void QtWaylandCompositor::XdgSurface::initialize(object surface, object client, int id)
+ *
+ * Initializes the XdgSurface, associating it with the given \a surface,
+ * \a client, and \a id.
+ */
+
+/*!
+ * Initializes the QWaylandXdgSurface, associating it with the given \a xdgShell, \a surface
+ * and \a resource.
+ */
+void QWaylandXdgSurface::initialize(QWaylandXdgShell *xdgShell, QWaylandSurface *surface, const QWaylandResource &resource)
+{
+ Q_D(QWaylandXdgSurface);
+ d->m_xdgShell = xdgShell;
+ d->m_surface = surface;
+ d->init(resource.resource());
+ setExtensionContainer(surface);
+ d->m_windowGeometry = QRect(QPoint(0,0), surface->size());
+ connect(surface, &QWaylandSurface::sizeChanged, this, &QWaylandXdgSurface::handleSurfaceSizeChanged);
+ emit surfaceChanged();
+ emit windowGeometryChanged();
+ QWaylandExtension::initialize();
+}
+
+/*!
+ * \internal
+ */
+void QWaylandXdgSurface::initialize()
+{
+ QWaylandExtensionTemplate::initialize();
+}
+
+QList<int> QWaylandXdgSurface::statesAsInts() const
+{
+ QList<int> list;
+ Q_FOREACH (uint state, states()) {
+ list << static_cast<int>(state);
+ }
+ return list;
+}
+
+void QWaylandXdgSurface::handleSurfaceSizeChanged()
+{
+ Q_D(QWaylandXdgSurface);
+ if (d->m_unsetWindowGeometry && d->m_windowGeometry.size() != surface()->size()) {
+ // TODO: The unset window geometry should include subsurfaces as well, so this solution
+ // won't work too well on those kinds of clients.
+ d->m_windowGeometry.setSize(surface()->size());
+ emit windowGeometryChanged();
+ }
+}
+
+/*!
+ * \qmlproperty object QtWaylandCompositor::XdgSurface::surface
+ *
+ * This property holds the surface associated with this XdgSurface.
+ */
+
+/*!
+ * \property QWaylandXdgSurface::surface
+ *
+ * This property holds the surface associated with this QWaylandXdgSurface.
+ */
+QWaylandSurface *QWaylandXdgSurface::surface() const
+{
+ Q_D(const QWaylandXdgSurface);
+ return d->m_surface;
+}
+
+/*!
+ * \qmlproperty object QtWaylandCompositor::XdgSurface::parentSurface
+ *
+ * This property holds the XdgSurface parent of this XdgSurface.
+ */
+
+/*!
+ * \property QWaylandXdgSurface::surface
+ *
+ * This property holds the XdgSurface parent of this XdgSurface.
+ */
+QWaylandXdgSurface *QWaylandXdgSurface::parentSurface() const
+{
+ Q_D(const QWaylandXdgSurface);
+ return d->m_parentSurface;
+}
+
+/*!
+ * \qmlproperty string QtWaylandCompositor::XdgSurface::title
+ *
+ * This property holds the title of the XdgSurface.
+ */
+
+/*!
+ * \property QWaylandXdgSurface::title
+ *
+ * This property holds the title of the QWaylandXdgSurface.
+ */
+QString QWaylandXdgSurface::title() const
+{
+ Q_D(const QWaylandXdgSurface);
+ return d->m_title;
+}
+
+/*!
+ * \property QWaylandXdgSurface::appId
+ *
+ * This property holds the app id of the QWaylandXdgSurface.
+ */
+QString QWaylandXdgSurface::appId() const
+{
+ Q_D(const QWaylandXdgSurface);
+ return d->m_appId;
+}
+
+/*!
+ * \property QWaylandXdgSurface::appId
+ *
+ * This property holds the window geometry of the QWaylandXdgSurface.
+ */
+QRect QWaylandXdgSurface::windowGeometry() const
+{
+ Q_D(const QWaylandXdgSurface);
+ return d->m_windowGeometry;
+}
+
+/*!
+ * \property QWaylandXdgSurface::states
+ *
+ * This property holds the last states the client acknowledged for this QWaylandXdgSurface.
+ */
+QVector<uint> QWaylandXdgSurface::states() const
+{
+ Q_D(const QWaylandXdgSurface);
+ return d->m_lastAckedConfigure.states;
+}
+
+bool QWaylandXdgSurface::maximized() const
+{
+ Q_D(const QWaylandXdgSurface);
+ return d->m_lastAckedConfigure.states.contains(QWaylandXdgSurface::State::MaximizedState);
+}
+
+bool QWaylandXdgSurface::fullscreen() const
+{
+ Q_D(const QWaylandXdgSurface);
+ return d->m_lastAckedConfigure.states.contains(QWaylandXdgSurface::State::FullscreenState);
+}
+
+bool QWaylandXdgSurface::resizing() const
+{
+ Q_D(const QWaylandXdgSurface);
+ return d->m_lastAckedConfigure.states.contains(QWaylandXdgSurface::State::ResizingState);
+}
+
+bool QWaylandXdgSurface::activated() const
+{
+ Q_D(const QWaylandXdgSurface);
+ return d->m_lastAckedConfigure.states.contains(QWaylandXdgSurface::State::ActivatedState);
+}
+
+/*!
+ * Returns the Wayland interface for the QWaylandXdgSurface.
+ */
+const wl_interface *QWaylandXdgSurface::interface()
+{
+ return QWaylandXdgSurfacePrivate::interface();
+}
+
+QByteArray QWaylandXdgSurface::interfaceName()
+{
+ return QWaylandXdgSurfacePrivate::interfaceName();
+}
+
+/*!
+ * Returns the surface role for the QWaylandXdgSurface.
+ */
+QWaylandSurfaceRole *QWaylandXdgSurface::role()
+{
+ return &QWaylandXdgSurfacePrivate::s_role;
+}
+
+/*!
+ * Returns the QWaylandXdgSurface corresponding to the \a resource.
+ */
+QWaylandXdgSurface *QWaylandXdgSurface::fromResource(wl_resource *resource)
+{
+ auto xsResource = QWaylandXdgSurfacePrivate::Resource::fromResource(resource);
+ if (!xsResource)
+ return nullptr;
+ return static_cast<QWaylandXdgSurfacePrivate *>(xsResource->xdg_surface_object)->q_func();
+}
+
+QSize QWaylandXdgSurface::sizeForResize(const QSizeF &size, const QPointF &delta,
+ QWaylandXdgSurface::ResizeEdge edge)
+{
+ qreal width = size.width();
+ qreal height = size.height();
+ if (edge & LeftEdge)
+ width -= delta.x();
+ else if (edge & RightEdge)
+ width += delta.x();
+
+ if (edge & TopEdge)
+ height -= delta.y();
+ else if (edge & BottomEdge)
+ height += delta.y();
+
+ return QSizeF(width, height).toSize();
+}
+
+/*!
+ * \qmlmethod int QtWaylandCompositor::XdgSurface::sendConfigure(size size, List<uint>)
+ *
+ * Sends a configure event to the client. Known states are enumerated in XdgSurface::State
+ */
+
+/*!
+ * Sends a configure event to the client. Known states are enumerated in QWaylandXdgSurface::State
+ */
+uint QWaylandXdgSurface::sendConfigure(const QSize &size, const QVector<uint> &states)
+{
+ Q_D(QWaylandXdgSurface);
+ auto statesBytes = QByteArray::fromRawData((char *)states.data(), states.size() * sizeof(State));
+ QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
+ Q_ASSERT(compositor);
+ uint32_t serial = compositor->nextSerial();
+ d->m_pendingConfigures.append(QWaylandXdgSurfacePrivate::ConfigureEvent{states, size, serial});
+ d->send_configure(size.width(), size.height(), statesBytes, serial);
+ return serial;
+}
+
+uint QWaylandXdgSurface::sendConfigure(const QSize &size, const QVector<QWaylandXdgSurface::State> &states)
+{
+ QVector<uint> asUints;
+ Q_FOREACH (QWaylandXdgSurface::State state, states) {
+ asUints << state;
+ }
+ return sendConfigure(size, asUints);
+}
+
+/*!
+ * \qmlmethod void QtWaylandCompositor::XdgSurface::sendClose()
+ *
+ * Sends a close event to the client.
+ */
+
+/*!
+ * Sends a close event to the client.
+ */
+void QWaylandXdgSurface::sendClose()
+{
+ Q_D(QWaylandXdgSurface);
+ d->send_close();
+}
+
+uint QWaylandXdgSurface::requestMaximized(const QSize &size)
+{
+ Q_D(QWaylandXdgSurface);
+ QWaylandXdgSurfacePrivate::ConfigureEvent conf = d->lastSentConfigure();
+
+ if (!conf.states.contains(QWaylandXdgSurface::State::MaximizedState))
+ conf.states.append(QWaylandXdgSurface::State::MaximizedState);
+ conf.states.removeOne(QWaylandXdgSurface::State::FullscreenState);
+ conf.states.removeOne(QWaylandXdgSurface::State::ResizingState);
+
+ return sendConfigure(size, conf.states);
+}
+
+uint QWaylandXdgSurface::requestUnMaximized(const QSize &size)
+{
+ Q_D(QWaylandXdgSurface);
+ QWaylandXdgSurfacePrivate::ConfigureEvent conf = d->lastSentConfigure();
+
+ conf.states.removeOne(QWaylandXdgSurface::State::MaximizedState);
+ conf.states.removeOne(QWaylandXdgSurface::State::FullscreenState);
+ conf.states.removeOne(QWaylandXdgSurface::State::ResizingState);
+
+ return sendConfigure(size, conf.states);
+}
+
+uint QWaylandXdgSurface::requestFullscreen(const QSize &size)
+{
+ Q_D(QWaylandXdgSurface);
+ QWaylandXdgSurfacePrivate::ConfigureEvent conf = d->lastSentConfigure();
+
+ if (!conf.states.contains(QWaylandXdgSurface::State::FullscreenState))
+ conf.states.append(QWaylandXdgSurface::State::FullscreenState);
+ conf.states.removeOne(QWaylandXdgSurface::State::MaximizedState);
+ conf.states.removeOne(QWaylandXdgSurface::State::ResizingState);
+
+ return sendConfigure(size, conf.states);
+}
+
+uint QWaylandXdgSurface::requestResizing(const QSize &maxSize)
+{
+ Q_D(QWaylandXdgSurface);
+ QWaylandXdgSurfacePrivate::ConfigureEvent conf = d->lastSentConfigure();
+
+ if (!conf.states.contains(QWaylandXdgSurface::State::ResizingState))
+ conf.states.append(QWaylandXdgSurface::State::ResizingState);
+ conf.states.removeOne(QWaylandXdgSurface::State::MaximizedState);
+ conf.states.removeOne(QWaylandXdgSurface::State::FullscreenState);
+
+ return sendConfigure(maxSize, conf.states);
+}
+
+/*!
+ * \class QWaylandXdgPopup
+ * \inmodule QtWaylandCompositor
+ * \brief An xdg popup providing menus for an xdg surface
+ *
+ * This class is part of the QWaylandXdgShell extension and provides a way to
+ * extend the functionality of an existing QWaylandSurface with features
+ * specific to desktop-style menus for an xdg surface.
+ *
+ * It corresponds to the Wayland interface xdg_popup.
+ */
+
+/*!
+ * Constructs a QWaylandXdgPopup.
+ */
+QWaylandXdgPopup::QWaylandXdgPopup()
+ : QWaylandExtensionTemplate<QWaylandXdgPopup>(*new QWaylandXdgPopupPrivate)
+{
+}
+
+/*!
+ * Constructs a QWaylandXdgPopup for \a surface and initializes it with the
+ * given \a parentSurface and \a resource.
+ */
+QWaylandXdgPopup::QWaylandXdgPopup(QWaylandXdgShell *xdgShell, QWaylandSurface *surface,
+ QWaylandSurface *parentSurface, const QWaylandResource &resource)
+ : QWaylandExtensionTemplate<QWaylandXdgPopup>(*new QWaylandXdgPopupPrivate)
+{
+ initialize(xdgShell, surface, parentSurface, resource);
+}
+
+/*!
+ * \qmlmethod void QtWaylandCompositor::XdgPopup::initialize(object surface, object parentSurface, object resource)
+ *
+ * Initializes the xdg popup, associating it with the given \a shell, \a surface,
+ * \a parentSurface and \a resource.
+ */
+
+/*!
+ * Initializes the QWaylandXdgPopup, associating it with the given \a shell \a surface,
+ * \a parentSurface and \a resource.
+ */
+void QWaylandXdgPopup::initialize(QWaylandXdgShell *shell, QWaylandSurface *surface,
+ QWaylandSurface *parentSurface, const QWaylandResource &resource)
+{
+ Q_D(QWaylandXdgPopup);
+ d->m_surface = surface;
+ d->m_parentSurface = parentSurface;
+ d->m_xdgShell = shell;
+ d->init(resource.resource());
+ setExtensionContainer(surface);
+ emit surfaceChanged();
+ emit parentSurfaceChanged();
+ QWaylandExtension::initialize();
+}
+
+/*!
+ * \qmlproperty object QtWaylandCompositor::XdgPopup::surface
+ *
+ * This property holds the surface associated with this XdgPopup.
+ */
+
+/*!
+ * \property QWaylandXdgPopup::surface
+ *
+ * This property holds the surface associated with this QWaylandXdgPopup.
+ */
+QWaylandSurface *QWaylandXdgPopup::surface() const
+{
+ Q_D(const QWaylandXdgPopup);
+ return d->m_surface;
+}
+
+/*!
+ * \qmlproperty object QtWaylandCompositor::XdgPopup::parentSurface
+ *
+ * This property holds the surface associated with the parent of this XdgPopup.
+ */
+
+/*!
+ * \property QWaylandXdgPopup::parentSurface
+ *
+ * This property holds the surface associated with the parent of this
+ * QWaylandXdgPopup.
+ */
+QWaylandSurface *QWaylandXdgPopup::parentSurface() const
+{
+ Q_D(const QWaylandXdgPopup);
+ return d->m_parentSurface;
+}
+
+/*!
+ * \internal
+ */
+void QWaylandXdgPopup::initialize()
+{
+ QWaylandExtensionTemplate::initialize();
+}
+
+/*!
+ * Returns the Wayland interface for the QWaylandXdgPopup.
+ */
+const wl_interface *QWaylandXdgPopup::interface()
+{
+ return QWaylandXdgPopupPrivate::interface();
+}
+
+QByteArray QWaylandXdgPopup::interfaceName()
+{
+ return QWaylandXdgPopupPrivate::interfaceName();
+}
+
+/*!
+ * Returns the surface role for the QWaylandXdgPopup.
+ */
+QWaylandSurfaceRole *QWaylandXdgPopup::role()
+{
+ return &QWaylandXdgPopupPrivate::s_role;
+}
+
+QWaylandXdgPopup *QWaylandXdgPopup::fromResource(wl_resource *resource)
+{
+ auto popupResource = QWaylandXdgPopupPrivate::Resource::fromResource(resource);
+ if (!popupResource)
+ return nullptr;
+ return static_cast<QWaylandXdgPopupPrivate *>(popupResource->xdg_popup_object)->q_func();
+}
+
+void QWaylandXdgPopup::sendPopupDone()
+{
+ Q_D(QWaylandXdgPopup);
+ d->send_popup_done();
+}
+
+QT_END_NAMESPACE
diff --git a/src/compositor/extensions/qwaylandxdgshell.h b/src/compositor/extensions/qwaylandxdgshell.h
new file mode 100644
index 000000000..c17d9eccf
--- /dev/null
+++ b/src/compositor/extensions/qwaylandxdgshell.h
@@ -0,0 +1,224 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later 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 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDXDGSHELL_H
+#define QWAYLANDXDGSHELL_H
+
+#include <QtWaylandCompositor/QWaylandExtension>
+
+#include <QtCore/QRect>
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandXdgShellPrivate;
+class QWaylandXdgSurface;
+class QWaylandXdgSurfacePrivate;
+class QWaylandXdgPopup;
+class QWaylandXdgPopupPrivate;
+
+class QWaylandSurface;
+class QWaylandSurfaceRole;
+class QWaylandResource;
+class QWaylandInputDevice;
+class QWaylandOutput;
+class QWaylandClient;
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgShell : public QWaylandExtensionTemplate<QWaylandXdgShell>
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QWaylandXdgShell)
+public:
+ QWaylandXdgShell();
+ QWaylandXdgShell(QWaylandCompositor *compositor);
+
+ void initialize() Q_DECL_OVERRIDE;
+
+ static const struct wl_interface *interface();
+ static QByteArray interfaceName();
+
+public Q_SLOTS:
+ uint ping(QWaylandClient *client);
+ void closeAllPopups();
+
+Q_SIGNALS:
+ void createXdgSurface(QWaylandSurface *surface, const QWaylandResource &resource);
+ void xdgSurfaceCreated(QWaylandXdgSurface *xdgSurface);
+ void xdgPopupCreated(QWaylandXdgPopup *xdgPopup);
+ void createXdgPopup(QWaylandSurface *surface, QWaylandSurface *parent, QWaylandInputDevice *seat, const QPoint &position, const QWaylandResource &resource);
+ void pong(uint serial);
+
+private Q_SLOTS:
+ void handleDefaultInputDeviceChanged(QWaylandInputDevice *newDevice, QWaylandInputDevice *oldDevice);
+ void handleFocusChanged(QWaylandSurface *newSurface, QWaylandSurface *oldSurface);
+
+};
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgSurface : public QWaylandExtensionTemplate<QWaylandXdgSurface>
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QWaylandXdgSurface)
+ Q_PROPERTY(QWaylandSurface *surface READ surface NOTIFY surfaceChanged)
+ Q_PROPERTY(QWaylandXdgSurface *parentSurface READ parentSurface NOTIFY parentSurfaceChanged)
+ Q_PROPERTY(QString title READ title NOTIFY titleChanged)
+ Q_PROPERTY(QString appId READ appId NOTIFY appIdChanged)
+ Q_PROPERTY(QRect windowGeometry READ windowGeometry NOTIFY windowGeometryChanged)
+
+ Q_PROPERTY(QList<int> states READ statesAsInts NOTIFY statesChanged)
+ Q_PROPERTY(bool maximized READ maximized NOTIFY maximizedChanged)
+ Q_PROPERTY(bool fullscreen READ fullscreen NOTIFY fullscreenChanged)
+ Q_PROPERTY(bool resizing READ resizing NOTIFY resizingChanged)
+ Q_PROPERTY(bool activated READ activated NOTIFY activatedChanged)
+
+public:
+ enum State : uint {
+ MaximizedState = 1,
+ FullscreenState = 2,
+ ResizingState = 3,
+ ActivatedState = 4
+ };
+ Q_ENUM(State)
+
+ enum ResizeEdge : uint {
+ NoneEdge = 0,
+ TopEdge = 1,
+ BottomEdge = 2,
+ LeftEdge = 4,
+ TopLeftEdge = 5,
+ BottomLeftEdge = 6,
+ RightEdge = 8,
+ TopRightEdge = 9,
+ BottomRightEdge = 10
+ };
+ Q_ENUM(ResizeEdge)
+
+ QWaylandXdgSurface();
+ QWaylandXdgSurface(QWaylandXdgShell* xdgShell, QWaylandSurface *surface, const QWaylandResource &resource);
+
+ Q_INVOKABLE void initialize(QWaylandXdgShell* xdgShell, QWaylandSurface *surface, const QWaylandResource &resource);
+
+ QString title() const;
+ QString appId() const;
+ QRect windowGeometry() const;
+ QVector<uint> states() const;
+ bool maximized() const;
+ bool fullscreen() const;
+ bool resizing() const;
+ bool activated() const;
+
+ QWaylandSurface *surface() const;
+ QWaylandXdgSurface *parentSurface() const;
+
+ static const struct wl_interface *interface();
+ static QByteArray interfaceName();
+ static QWaylandSurfaceRole *role();
+ static QWaylandXdgSurface *fromResource(::wl_resource *resource);
+
+ Q_INVOKABLE QSize sizeForResize(const QSizeF &size, const QPointF &delta, ResizeEdge edge);
+ Q_INVOKABLE uint sendConfigure(const QSize &size, const QVector<uint> &states);
+ Q_INVOKABLE uint sendConfigure(const QSize &size, const QVector<State> &states);
+ Q_INVOKABLE void sendClose();
+
+ Q_INVOKABLE uint requestMaximized(const QSize &size);
+ Q_INVOKABLE uint requestUnMaximized(const QSize &size = QSize(0, 0));
+ Q_INVOKABLE uint requestFullscreen(const QSize &size);
+ Q_INVOKABLE uint requestResizing(const QSize &maxSize);
+
+Q_SIGNALS:
+ void surfaceChanged();
+ void titleChanged();
+ void windowGeometryChanged();
+ void appIdChanged();
+ void parentSurfaceChanged();
+
+ void statesChanged();
+ void maximizedChanged();
+ void fullscreenChanged();
+ void resizingChanged();
+ void activatedChanged();
+
+ void showWindowMenu(QWaylandInputDevice *inputDevice, const QPoint &localSurfacePosition);
+ void startMove(QWaylandInputDevice *inputDevice);
+ void startResize(QWaylandInputDevice *inputDevice, ResizeEdge edges);
+ void setMaximized();
+ void unsetMaximized();
+ void setFullscreen(QWaylandOutput *output);
+ void unsetFullscreen();
+ void setMinimized();
+ void ackConfigure(uint serial);
+
+private:
+ void initialize();
+ QList<int> statesAsInts() const;
+
+private Q_SLOTS:
+ void handleSurfaceSizeChanged();
+};
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgPopup : public QWaylandExtensionTemplate<QWaylandXdgPopup>
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QWaylandXdgPopup)
+ Q_PROPERTY(QWaylandSurface *surface READ surface NOTIFY surfaceChanged)
+ Q_PROPERTY(QWaylandSurface *parentSurface READ parentSurface NOTIFY parentSurfaceChanged)
+
+public:
+ QWaylandXdgPopup();
+ QWaylandXdgPopup(QWaylandXdgShell *xdgShell, QWaylandSurface *surface, QWaylandSurface *parentSurface, const QWaylandResource &resource);
+
+ Q_INVOKABLE void initialize(QWaylandXdgShell *shell, QWaylandSurface *surface,
+ QWaylandSurface *parentSurface, const QWaylandResource &resource);
+
+ QWaylandSurface *surface() const;
+ QWaylandSurface *parentSurface() const;
+
+ static const struct wl_interface *interface();
+ static QByteArray interfaceName();
+ static QWaylandSurfaceRole *role();
+ static QWaylandXdgPopup *fromResource(::wl_resource *resource);
+
+ Q_INVOKABLE void sendPopupDone();
+
+Q_SIGNALS:
+ void surfaceChanged();
+ void parentSurfaceChanged();
+
+private:
+ void initialize();
+};
+
+QT_END_NAMESPACE
+
+#endif /*QWAYLANDXDGSHELL_H*/
diff --git a/src/compositor/extensions/qwaylandxdgshell_p.h b/src/compositor/extensions/qwaylandxdgshell_p.h
new file mode 100644
index 000000000..7337697d1
--- /dev/null
+++ b/src/compositor/extensions/qwaylandxdgshell_p.h
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later 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 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDXDGSHELL_P_H
+#define QWAYLANDXDGSHELL_P_H
+
+#include <QtWaylandCompositor/private/qwaylandextension_p.h>
+#include <QtWaylandCompositor/private/qwayland-server-xdg-shell.h>
+
+#include <QtWaylandCompositor/QWaylandXdgShell>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgShellPrivate
+ : public QWaylandExtensionTemplatePrivate
+ , public QtWaylandServer::xdg_shell
+{
+ Q_DECLARE_PUBLIC(QWaylandXdgShell)
+public:
+ QWaylandXdgShellPrivate();
+ void ping(Resource *resource, uint32_t serial);
+ void registerSurface(QWaylandXdgSurface *xdgSurface);
+ void unregisterXdgSurface(QWaylandXdgSurface *xdgSurface);
+ void registerXdgPopup(QWaylandXdgPopup *xdgPopup);
+ void unregisterXdgPopup(QWaylandXdgPopup *xdgPopup);
+ static QWaylandXdgShellPrivate *get(QWaylandXdgShell *xdgShell) { return xdgShell->d_func(); }
+ bool isValidPopupParent(QWaylandSurface *parentSurface) const;
+ QWaylandXdgPopup *topmostPopupForClient(struct wl_client* client) const;
+
+private:
+ QSet<uint32_t> m_pings;
+ QMultiMap<struct wl_client *, QWaylandXdgSurface *> m_xdgSurfaces;
+ QMultiMap<struct wl_client *, QWaylandXdgPopup *> m_xdgPopups;
+
+ QWaylandXdgSurface *xdgSurfaceFromSurface(QWaylandSurface *surface);
+
+ void xdg_shell_destroy(Resource *resource) Q_DECL_OVERRIDE;
+ void xdg_shell_get_xdg_surface(Resource *resource, uint32_t id,
+ struct ::wl_resource *surface) Q_DECL_OVERRIDE;
+ void xdg_shell_use_unstable_version(Resource *resource, int32_t version) Q_DECL_OVERRIDE;
+ void xdg_shell_get_xdg_popup(Resource *resource, uint32_t id, struct ::wl_resource *surface,
+ struct ::wl_resource *parent, struct ::wl_resource *seat,
+ uint32_t serial, int32_t x, int32_t y) Q_DECL_OVERRIDE;
+ void xdg_shell_pong(Resource *resource, uint32_t serial) Q_DECL_OVERRIDE;
+};
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgSurfacePrivate
+ : public QWaylandExtensionTemplatePrivate
+ , public QtWaylandServer::xdg_surface
+{
+ Q_DECLARE_PUBLIC(QWaylandXdgSurface)
+public:
+ QWaylandXdgSurfacePrivate();
+ static QWaylandXdgSurfacePrivate *get(QWaylandXdgSurface *xdgSurface) { return xdgSurface->d_func(); }
+
+ struct ConfigureEvent {
+ QVector<uint> states;
+ QSize size;
+ uint serial;
+ };
+
+ void handleFocusLost();
+ void handleFocusReceived();
+
+private:
+ QWaylandXdgShell *m_xdgShell;
+ QWaylandSurface *m_surface;
+ QWaylandXdgSurface *m_parentSurface;
+
+ QString m_title;
+ QString m_appId;
+ QRect m_windowGeometry;
+ bool m_unsetWindowGeometry;
+
+ QList<ConfigureEvent> m_pendingConfigures;
+ ConfigureEvent m_lastAckedConfigure;
+ ConfigureEvent lastSentConfigure() const { return m_pendingConfigures.empty() ? m_lastAckedConfigure : m_pendingConfigures.first(); }
+
+ void xdg_surface_destroy_resource(Resource *resource) Q_DECL_OVERRIDE;
+
+ void xdg_surface_destroy(Resource *resource) Q_DECL_OVERRIDE;
+ void xdg_surface_move(Resource *resource, struct ::wl_resource *seat,
+ uint32_t serial) Q_DECL_OVERRIDE;
+ void xdg_surface_resize(Resource *resource, struct ::wl_resource *seat, uint32_t serial,
+ uint32_t edges) Q_DECL_OVERRIDE;
+ void xdg_surface_set_maximized(Resource *resource) Q_DECL_OVERRIDE;
+ void xdg_surface_unset_maximized(Resource *resource) Q_DECL_OVERRIDE;
+ void xdg_surface_set_fullscreen(Resource *resource,
+ struct ::wl_resource *output) Q_DECL_OVERRIDE;
+ void xdg_surface_unset_fullscreen(Resource *resource) Q_DECL_OVERRIDE;
+ void xdg_surface_set_minimized(Resource *resource) Q_DECL_OVERRIDE;
+ void xdg_surface_set_parent(Resource *resource, struct ::wl_resource *parent) Q_DECL_OVERRIDE;
+ void xdg_surface_set_app_id(Resource *resource, const QString &app_id) Q_DECL_OVERRIDE;
+ void xdg_surface_show_window_menu(Resource *resource, struct ::wl_resource *seat,
+ uint32_t serial, int32_t x, int32_t y) Q_DECL_OVERRIDE;
+ void xdg_surface_ack_configure(Resource *resource, uint32_t serial) Q_DECL_OVERRIDE;
+ void xdg_surface_set_title(Resource *resource, const QString &title) Q_DECL_OVERRIDE;
+ void xdg_surface_set_window_geometry(Resource *resource, int32_t x, int32_t y,
+ int32_t width, int32_t height) Q_DECL_OVERRIDE;
+
+ static QWaylandSurfaceRole s_role;
+};
+
+class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgPopupPrivate
+ : public QWaylandExtensionTemplatePrivate
+ , public QtWaylandServer::xdg_popup
+{
+ Q_DECLARE_PUBLIC(QWaylandXdgPopup)
+
+public:
+ QWaylandXdgPopupPrivate();
+ static QWaylandXdgPopupPrivate *get(QWaylandXdgPopup *xdgPopup) { return xdgPopup->d_func(); }
+
+private:
+ QWaylandSurface *m_surface;
+ QWaylandSurface *m_parentSurface;
+ QWaylandXdgShell *m_xdgShell;
+
+ void xdg_popup_destroy_resource(Resource *resource) Q_DECL_OVERRIDE;
+ void xdg_popup_destroy(xdg_popup::Resource *resource) Q_DECL_OVERRIDE;
+
+ static QWaylandSurfaceRole s_role;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDXDGSHELL_P_H