diff options
author | Johan Klokkhammer Helsing <johan.helsing@theqtcompany.com> | 2016-02-17 12:51:54 +0100 |
---|---|---|
committer | Johan Helsing <johan.helsing@theqtcompany.com> | 2016-03-24 11:30:33 +0000 |
commit | d87d8b8afdd377e17a98b4d0f51c4bb0aaec25c2 (patch) | |
tree | 675df7cb09e6da37db7b6eb654371f1412f10fa5 /examples | |
parent | bfa0951619e56e856cc1443f78fbdb66e3bde009 (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')
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; |