summaryrefslogtreecommitdiffstats
path: root/examples
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 /examples
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>
Diffstat (limited to 'examples')
-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
4 files changed, 160 insertions, 14 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;