summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--README4
-rw-r--r--examples/wayland/minimal-qml/main.qml1
-rw-r--r--examples/wayland/pure-qml/qml/Chrome.qml29
-rw-r--r--examples/wayland/pure-qml/qml/Keyboard.qml3
-rw-r--r--examples/wayland/pure-qml/qml/Screen.qml46
-rw-r--r--examples/wayland/pure-qml/qml/main.qml67
-rw-r--r--src/3rdparty/protocol/qt_attribution.json2
-rw-r--r--src/3rdparty/protocol/xdg-shell-unstable-v5.xml (renamed from src/3rdparty/protocol/xdg-shell.xml)2
-rw-r--r--src/client/client.pro15
-rw-r--r--src/client/qwaylandcursor.cpp19
-rw-r--r--src/client/qwaylanddisplay.cpp15
-rw-r--r--src/client/qwaylanddisplay_p.h12
-rw-r--r--src/client/qwaylanddnd.cpp8
-rw-r--r--src/client/qwaylanddnd_p.h4
-rw-r--r--src/client/qwaylandinputdevice.cpp16
-rw-r--r--src/client/qwaylandinputdevice_p.h6
-rw-r--r--src/client/qwaylandintegration.cpp17
-rw-r--r--src/client/qwaylandnativeinterface.cpp15
-rw-r--r--src/client/qwaylandqtkey.cpp4
-rw-r--r--src/client/qwaylandqtkey_p.h26
-rw-r--r--src/client/qwaylandscreen.cpp27
-rw-r--r--src/client/qwaylandscreen_p.h6
-rw-r--r--src/client/qwaylandshellsurface_p.h9
-rw-r--r--src/client/qwaylandwindow.cpp125
-rw-r--r--src/client/qwaylandwindow_p.h36
-rw-r--r--src/client/qwaylandxdgshellv6.cpp119
-rw-r--r--src/client/qwaylandxdgshellv6_p.h14
-rw-r--r--src/client/qwaylandxdgshellv6integration.cpp29
-rw-r--r--src/client/qwaylandxdgshellv6integration_p.h1
-rw-r--r--src/client/qwaylandxdgsurface.cpp256
-rw-r--r--src/client/shellintegration/qwaylandshellintegration_p.h5
-rw-r--r--src/client/shellintegration/qwaylandshellintegrationfactory.cpp17
-rw-r--r--src/client/shellintegration/qwaylandshellintegrationfactory_p.h5
-rw-r--r--src/compositor/compositor_api/qwaylandkeyboard.cpp41
-rw-r--r--src/compositor/compositor_api/qwaylandkeyboard.h2
-rw-r--r--src/compositor/compositor_api/qwaylandkeyboard_p.h3
-rw-r--r--src/compositor/compositor_api/qwaylandquickitem.cpp13
-rw-r--r--src/compositor/compositor_api/qwaylandquickitem.h1
-rw-r--r--src/compositor/compositor_api/qwaylandseat.cpp44
-rw-r--r--src/compositor/compositor_api/qwaylandseat.h1
-rw-r--r--src/compositor/extensions/extensions.pri4
-rw-r--r--src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp45
-rw-r--r--src/compositor/extensions/qwaylandquickshellsurfaceitem.h5
-rw-r--r--src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h10
-rw-r--r--src/compositor/extensions/qwaylandxdgshellv5_p.h2
-rw-r--r--src/compositor/extensions/qwaylandxdgshellv5integration.cpp12
-rw-r--r--src/compositor/extensions/qwaylandxdgshellv6integration.cpp13
-rw-r--r--src/compositor/extensions/qwlqtkey.cpp20
-rw-r--r--src/compositor/extensions/qwlqtkey_p.h4
-rw-r--r--src/extensions/README.md18
-rw-r--r--src/extensions/qt-key-unstable-v1.xml (renamed from src/extensions/qtkey-extension.xml)54
-rw-r--r--src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglintegration.cpp27
-rw-r--r--src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglintegration.h3
-rw-r--r--src/plugins/decorations/bradient/main.cpp7
-rw-r--r--src/plugins/shellintegration/ivi-shell/qwaylandivisurface.cpp8
-rw-r--r--src/plugins/shellintegration/ivi-shell/qwaylandivisurface_p.h2
-rw-r--r--src/plugins/shellintegration/shellintegration.pro6
-rw-r--r--src/plugins/shellintegration/wl-shell/main.cpp69
-rw-r--r--src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration.cpp (renamed from src/client/qwaylandwlshellintegration.cpp)37
-rw-r--r--src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration_p.h (renamed from src/client/qwaylandwlshellintegration_p.h)5
-rw-r--r--src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp (renamed from src/client/qwaylandwlshellsurface.cpp)97
-rw-r--r--src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface_p.h (renamed from src/client/qwaylandwlshellsurface_p.h)21
-rw-r--r--src/plugins/shellintegration/wl-shell/wl-shell.json3
-rw-r--r--src/plugins/shellintegration/wl-shell/wl-shell.pro23
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/main.cpp69
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5.cpp (renamed from src/client/qwaylandxdgpopup.cpp)16
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h (renamed from src/client/qwaylandxdgpopup_p.h)15
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp (renamed from src/client/qwaylandxdgshell.cpp)34
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5_p.h (renamed from src/client/qwaylandxdgshell_p.h)25
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp (renamed from src/client/qwaylandxdgshellintegration.cpp)38
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h (renamed from src/client/qwaylandxdgshellintegration_p.h)18
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp241
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5_p.h (renamed from src/client/qwaylandxdgsurface_p.h)46
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/xdg-shell-v5.json3
-rw-r--r--src/plugins/shellintegration/xdg-shell-v5/xdg-shell-v5.pro30
-rw-r--r--tests/auto/client/client/tst_client.cpp20
-rw-r--r--tests/auto/client/shared/mockcompositor.cpp5
-rw-r--r--tests/auto/client/shared/mockcompositor.h14
-rw-r--r--tests/auto/client/shared/mocksurface.cpp5
-rw-r--r--tests/auto/client/shared/mockxdgshellv6.cpp35
-rw-r--r--tests/auto/client/shared/mockxdgshellv6.h5
-rw-r--r--tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp189
-rw-r--r--tests/auto/compositor/compositor/compositor.pro4
-rw-r--r--tests/auto/compositor/compositor/mockclient.h2
-rw-r--r--tests/auto/compositor/compositor/mockkeyboard.cpp101
-rw-r--r--tests/auto/compositor/compositor/mockkeyboard.h50
-rw-r--r--tests/auto/compositor/compositor/mockseat.cpp5
-rw-r--r--tests/auto/compositor/compositor/mockseat.h4
-rw-r--r--tests/auto/compositor/compositor/tst_compositor.cpp141
90 files changed, 1839 insertions, 838 deletions
diff --git a/.qmake.conf b/.qmake.conf
index dc68d3884..097d8b948 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,3 +1,3 @@
load(qt_build_config)
-MODULE_VERSION = 5.11.0
+MODULE_VERSION = 5.12.0
diff --git a/README b/README
index 8215b30b9..4ce158930 100644
--- a/README
+++ b/README
@@ -70,8 +70,8 @@ the generic wl_shell or xdg_shell extensions that target desktop systems.
Custom shell protocols are added through shell integration plugins.
Which shell integration to use is determined by the QT_WAYLAND_SHELL_INTEGRATION
-environment variable. If no shell is specified, the default is to first try
-xdg-shell-v6 and then wl-shell.
+environment variable. If no shell is specified, the default is to try shells in
+the following order: xdg-shell-v6, wl-shell and then ivi-shell.
Example Usage:
diff --git a/examples/wayland/minimal-qml/main.qml b/examples/wayland/minimal-qml/main.qml
index 0f0ca61bc..85c8c5783 100644
--- a/examples/wayland/minimal-qml/main.qml
+++ b/examples/wayland/minimal-qml/main.qml
@@ -67,6 +67,7 @@ WaylandCompositor {
// resize/move, and forwarding of mouse and keyboard
// events to the client process.
ShellSurfaceItem {
+ autoCreatePopupItems: true
shellSurface: modelData
onSurfaceDestroyed: shellSurfaces.remove(index)
}
diff --git a/examples/wayland/pure-qml/qml/Chrome.qml b/examples/wayland/pure-qml/qml/Chrome.qml
index e6fe97476..a63ee705c 100644
--- a/examples/wayland/pure-qml/qml/Chrome.qml
+++ b/examples/wayland/pure-qml/qml/Chrome.qml
@@ -52,15 +52,28 @@ import QtQuick 2.0
import QtWayland.Compositor 1.0
ShellSurfaceItem {
- id: rootChrome
+ id: chrome
property bool isChild: parent.shellSurface !== undefined
+ signal destroyAnimationFinished
+
+ // If the client asks to show popups on this surface, automatically create child ShellSurfaceItems
+ autoCreatePopupItems: true
+
onSurfaceDestroyed: {
bufferLocked = true;
destroyAnimation.start();
}
+ transform: [
+ Scale {
+ id: scaleTransform
+ origin.x: chrome.width / 2
+ origin.y: chrome.height / 2
+ }
+ ]
+
Connections {
target: shellSurface
@@ -76,17 +89,19 @@ ShellSurfaceItem {
SequentialAnimation {
id: destroyAnimation
+
ParallelAnimation {
NumberAnimation { target: scaleTransform; property: "yScale"; to: 2/height; duration: 150 }
NumberAnimation { target: scaleTransform; property: "xScale"; to: 0.4; duration: 150 }
- NumberAnimation { target: rootChrome; property: "opacity"; to: rootChrome.isChild ? 0 : 1; duration: 150 }
+ NumberAnimation { target: chrome; property: "opacity"; to: chrome.isChild ? 0 : 1; duration: 150 }
}
NumberAnimation { target: scaleTransform; property: "xScale"; to: 0; duration: 150 }
- ScriptAction { script: { rootChrome.destroy(); } }
+ ScriptAction { script: destroyAnimationFinished() }
}
SequentialAnimation {
id: receivedFocusAnimation
+
ParallelAnimation {
NumberAnimation { target: scaleTransform; property: "yScale"; to: 1.02; duration: 100; easing.type: Easing.OutQuad }
NumberAnimation { target: scaleTransform; property: "xScale"; to: 1.02; duration: 100; easing.type: Easing.OutQuad }
@@ -96,12 +111,4 @@ ShellSurfaceItem {
NumberAnimation { target: scaleTransform; property: "xScale"; to: 1; duration: 100; easing.type: Easing.InOutQuad }
}
}
-
- transform: [
- Scale {
- id:scaleTransform
- origin.x: rootChrome.width / 2
- origin.y: rootChrome.height / 2
- }
- ]
}
diff --git a/examples/wayland/pure-qml/qml/Keyboard.qml b/examples/wayland/pure-qml/qml/Keyboard.qml
index e1f0a8b19..b2586ffd4 100644
--- a/examples/wayland/pure-qml/qml/Keyboard.qml
+++ b/examples/wayland/pure-qml/qml/Keyboard.qml
@@ -52,9 +52,8 @@ import QtQuick 2.5
import QtQuick.VirtualKeyboard 2.1
InputPanel {
- id: inputPanel
visible: active
- y: active ? parent.height - inputPanel.height : parent.height
+ y: active ? parent.height - height : parent.height
anchors.left: parent.left
anchors.right: parent.right
}
diff --git a/examples/wayland/pure-qml/qml/Screen.qml b/examples/wayland/pure-qml/qml/Screen.qml
index 562eb86c5..b156cb434 100644
--- a/examples/wayland/pure-qml/qml/Screen.qml
+++ b/examples/wayland/pure-qml/qml/Screen.qml
@@ -54,49 +54,69 @@ import QtWayland.Compositor 1.0
WaylandOutput {
id: output
- property alias surfaceArea: background
- sizeFollowsWindow: true
- window: Window {
- id: screen
- property QtObject output
+ property ListModel shellSurfaces: ListModel {}
+ property bool isNestedCompositor: Qt.platform.pluginName.startsWith("wayland") || Qt.platform.pluginName === "xcb"
+
+ function handleShellSurface(shellSurface) {
+ shellSurfaces.append({shellSurface: shellSurface});
+ }
+
+ // During development, it can be useful to start the compositor inside X11 or
+ // another Wayland compositor. In such cases, set sizeFollowsWindow to true to
+ // enable resizing of the compositor window to be forwarded to the Wayland clients
+ // as the output (screen) changing resolution. Consider setting it to false if you
+ // are running the compositor using eglfs, linuxfb or similar QPA backends.
+ sizeFollowsWindow: output.isNestedCompositor
+ window: Window {
width: 1024
height: 760
visible: true
WaylandMouseTracker {
id: mouseTracker
+
anchors.fill: parent
- windowSystemCursorEnabled: true
+ // Set this to false to disable the outer mouse cursor when running nested
+ // compositors. Otherwise you would see two mouse cursors, one for each compositor.
+ windowSystemCursorEnabled: output.isNestedCompositor
+
Image {
id: background
+
anchors.fill: parent
fillMode: Image.Tile
source: "qrc:/images/background.jpg"
smooth: true
+
+ Repeater {
+ model: output.shellSurfaces
+ // Chrome displays a shell surface on the screen (See Chrome.qml)
+ Chrome {
+ shellSurface: modelData
+ onDestroyAnimationFinished: output.shellSurfaces.remove(index)
+ }
+ }
}
+
+ // Virtual Keyboard
Loader {
anchors.fill: parent
source: "Keyboard.qml"
}
+
+ // Draws the mouse cursor for a given Wayland seat
WaylandCursorItem {
- id: cursor
inputEventsEnabled: false
x: mouseTracker.mouseX
y: mouseTracker.mouseY
-
seat: output.compositor.defaultSeat
}
}
Shortcut {
- sequence: "Meta+F"
- onActivated: qtWindowManager.showIsFullScreen = !qtWindowManager.showIsFullScreen
- }
-
- Shortcut {
sequence: "Ctrl+Alt+Backspace"
onActivated: Qt.quit()
}
diff --git a/examples/wayland/pure-qml/qml/main.qml b/examples/wayland/pure-qml/qml/main.qml
index 77ed3ecd9..b188ebbb5 100644
--- a/examples/wayland/pure-qml/qml/main.qml
+++ b/examples/wayland/pure-qml/qml/main.qml
@@ -52,68 +52,21 @@ import QtQuick 2.0
import QtWayland.Compositor 1.1
WaylandCompositor {
- id: comp
+ id: waylandCompositor
- property var primarySurfacesArea: null
-
- Screen {
- compositor: comp
- }
-
- Component {
- id: chromeComponent
- Chrome {
- }
- }
-
- Component {
- id: surfaceComponent
- WaylandSurface {
- }
- }
-
- QtWindowManager {
- id: qtWindowManager
- onShowIsFullScreenChanged: console.debug("Show is fullscreen hint for Qt applications:", showIsFullScreen)
- }
-
- WlShell {
- onWlShellSurfaceCreated: {
- chromeComponent.createObject(defaultOutput.surfaceArea, { "shellSurface": shellSurface } );
- }
- }
-
- property variant viewsBySurface: ({})
-
- XdgShellV5 {
- onXdgSurfaceCreated: {
- var item = chromeComponent.createObject(defaultOutput.surfaceArea, { "shellSurface": xdgSurface } );
- viewsBySurface[xdgSurface.surface] = item;
- }
- onXdgPopupCreated: {
- var parentView = viewsBySurface[xdgPopup.parentSurface];
- var item = chromeComponent.createObject(parentView, { "shellSurface": xdgPopup } );
- viewsBySurface[xdgPopup.surface] = item;
- }
- }
+ Screen { id: screen; compositor: waylandCompositor }
+ // Shell surface extension. Needed to provide a window concept for Wayland clients.
+ // I.e. requests and events for maximization, minimization, resizing, closing etc.
XdgShellV6 {
- onToplevelCreated: {
- var item = chromeComponent.createObject(defaultOutput.surfaceArea, { "shellSurface": xdgSurface } );
- viewsBySurface[xdgSurface.surface] = item;
- }
- onPopupCreated: {
- var parentView = viewsBySurface[popup.parentXdgSurface.surface];
- var item = chromeComponent.createObject(parentView, { "shellSurface": xdgSurface } );
- viewsBySurface[xdgSurface.surface] = item;
- }
+ onToplevelCreated: screen.handleShellSurface(xdgSurface)
}
- TextInputManager {
+ // Deprecated shell extension, still used by some clients
+ WlShell {
+ onWlShellSurfaceCreated: screen.handleShellSurface(shellSurface)
}
- onSurfaceRequested: {
- var surface = surfaceComponent.createObject(comp, { } );
- surface.initialize(comp, client, id, version);
- }
+ // Extension for Virtual keyboard support
+ TextInputManager {}
}
diff --git a/src/3rdparty/protocol/qt_attribution.json b/src/3rdparty/protocol/qt_attribution.json
index f35dec4f3..94d77f609 100644
--- a/src/3rdparty/protocol/qt_attribution.json
+++ b/src/3rdparty/protocol/qt_attribution.json
@@ -41,7 +41,7 @@ Copyright (c) 2013 BMW Car IT GmbH"
"Name": "Wayland XDG Shell Protocol",
"QDocModule": "qtwaylandcompositor",
"QtUsage": "Used in the Qt Wayland Compositor, and the Qt Wayland platform plugin.",
- "Files": "xdg-shell.xml",
+ "Files": "xdg-shell-unstable-v5.xml xdg-shell-unstable-v6.xml",
"Description": "The XDG-Shell protocol is an extended way to manage surfaces under Wayland compositors.",
"Homepage": "https://wayland.freedesktop.org",
diff --git a/src/3rdparty/protocol/xdg-shell.xml b/src/3rdparty/protocol/xdg-shell-unstable-v5.xml
index f98e760d4..89c9d58c5 100644
--- a/src/3rdparty/protocol/xdg-shell.xml
+++ b/src/3rdparty/protocol/xdg-shell-unstable-v5.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<protocol name="xdg_shell">
+<protocol name="xdg_shell_unstable_v5">
<copyright>
Copyright © 2008-2013 Kristian Høgsberg
diff --git a/src/client/client.pro b/src/client/client.pro
index eae7ad52e..3b11902de 100644
--- a/src/client/client.pro
+++ b/src/client/client.pro
@@ -25,10 +25,9 @@ INCLUDEPATH += $$PWD/../shared
WAYLANDCLIENTSOURCES += \
../extensions/surface-extension.xml \
../extensions/touch-extension.xml \
- ../extensions/qtkey-extension.xml \
+ ../extensions/qt-key-unstable-v1.xml \
../extensions/qt-windowmanager.xml \
../3rdparty/protocol/text-input-unstable-v2.xml \
- ../3rdparty/protocol/xdg-shell.xml \
../3rdparty/protocol/xdg-shell-unstable-v6.xml \
WAYLANDCLIENTSOURCES_SYSTEM += \
@@ -43,12 +42,6 @@ SOURCES += qwaylandintegration.cpp \
qwaylandscreen.cpp \
qwaylandshmwindow.cpp \
qwaylandshellsurface.cpp \
- qwaylandwlshellsurface.cpp \
- qwaylandwlshellintegration.cpp \
- qwaylandxdgshell.cpp \
- qwaylandxdgsurface.cpp \
- qwaylandxdgpopup.cpp \
- qwaylandxdgshellintegration.cpp \
qwaylandxdgshellv6.cpp \
qwaylandxdgshellv6integration.cpp \
qwaylandextendedsurface.cpp \
@@ -76,12 +69,6 @@ HEADERS += qwaylandintegration_p.h \
qwaylandbuffer_p.h \
qwaylandshmwindow_p.h \
qwaylandshellsurface_p.h \
- qwaylandwlshellsurface_p.h \
- qwaylandwlshellintegration_p.h \
- qwaylandxdgshell_p.h \
- qwaylandxdgsurface_p.h \
- qwaylandxdgpopup_p.h \
- qwaylandxdgshellintegration_p.h \
qwaylandxdgshellv6_p.h \
qwaylandxdgshellv6integration_p.h \
qwaylandextendedsurface_p.h \
diff --git a/src/client/qwaylandcursor.cpp b/src/client/qwaylandcursor.cpp
index 21a6c0811..a356950c3 100644
--- a/src/client/qwaylandcursor.cpp
+++ b/src/client/qwaylandcursor.cpp
@@ -60,11 +60,14 @@ QWaylandCursor::QWaylandCursor(QWaylandScreen *screen)
QByteArray cursorTheme = qgetenv("XCURSOR_THEME");
if (cursorTheme.isEmpty())
cursorTheme = QByteArray("default");
- QByteArray cursorSizeFromEnv = qgetenv("XCURSOR_SIZE");
- bool hasCursorSize = false;
- int cursorSize = cursorSizeFromEnv.toInt(&hasCursorSize);
- if (!hasCursorSize || cursorSize <= 0)
+ int cursorSize = qEnvironmentVariableIntValue("XCURSOR_SIZE");
+ if (cursorSize <= 0)
cursorSize = 32;
+
+ // wl_surface.set_buffer_scale is not supported on earlier versions
+ if (mDisplay->compositorVersion() >= 3)
+ cursorSize *= screen->devicePixelRatio();
+
mCursorTheme = wl_cursor_theme_load(cursorTheme, cursorSize, mDisplay->shm()->object());
if (!mCursorTheme)
qDebug() << "Could not load theme" << cursorTheme;
@@ -84,7 +87,7 @@ struct wl_cursor_image *QWaylandCursor::cursorImage(Qt::CursorShape newShape)
/* Hide cursor */
if (newShape == Qt::BlankCursor)
{
- mDisplay->setCursor(nullptr, nullptr);
+ mDisplay->setCursor(nullptr, nullptr, 1);
return nullptr;
}
@@ -125,12 +128,10 @@ QSharedPointer<QWaylandBuffer> QWaylandCursor::cursorBitmapImage(const QCursor *
void QWaylandCursor::changeCursor(QCursor *cursor, QWindow *window)
{
- Q_UNUSED(window)
-
const Qt::CursorShape newShape = cursor ? cursor->shape() : Qt::ArrowCursor;
if (newShape == Qt::BitmapCursor) {
- mDisplay->setCursor(cursorBitmapImage(cursor), cursor->hotSpot());
+ mDisplay->setCursor(cursorBitmapImage(cursor), cursor->hotSpot(), window->screen()->devicePixelRatio());
return;
}
@@ -140,7 +141,7 @@ void QWaylandCursor::changeCursor(QCursor *cursor, QWindow *window)
}
struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
- mDisplay->setCursor(buffer, image);
+ mDisplay->setCursor(buffer, image, window->screen()->devicePixelRatio());
}
void QWaylandCursor::pointerEvent(const QMouseEvent &event)
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
index a9fff410a..9cbb3524d 100644
--- a/src/client/qwaylanddisplay.cpp
+++ b/src/client/qwaylanddisplay.cpp
@@ -51,9 +51,6 @@
#include "qwaylanddatadevicemanager_p.h"
#endif
#include "qwaylandhardwareintegration_p.h"
-#include "qwaylandxdgshell_p.h"
-#include "qwaylandxdgsurface_p.h"
-#include "qwaylandwlshellsurface_p.h"
#include "qwaylandinputcontext_p.h"
#include "qwaylandwindowmanagerintegration_p.h"
@@ -66,7 +63,6 @@
#include "qwaylandqtkey_p.h"
#include <QtWaylandClient/private/qwayland-text-input-unstable-v2.h>
-#include <QtWaylandClient/private/qwayland-xdg-shell.h>
#include <QtCore/QAbstractEventDispatcher>
#include <QtGui/private/qguiapplication_p.h>
@@ -241,7 +237,6 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
mScreens.append(screen);
// We need to get the output events before creating surfaces
forceRoundTrip();
- screen->init();
mWaylandIntegration->screenAdded(screen);
} else if (interface == QStringLiteral("wl_compositor")) {
mCompositorVersion = qMin((int)version, 3);
@@ -261,7 +256,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
mSubCompositor.reset(new QtWayland::wl_subcompositor(registry, id, 1));
} else if (interface == QStringLiteral("qt_touch_extension")) {
mTouchExtension.reset(new QWaylandTouchExtension(this, id));
- } else if (interface == QStringLiteral("qt_key_extension")) {
+ } else if (interface == QStringLiteral("zqt_key_v1")) {
mQtKeyExtension.reset(new QWaylandQtKeyExtension(this, id));
} else if (interface == QStringLiteral("zwp_text_input_manager_v2")) {
mTextInputManager.reset(new QtWayland::zwp_text_input_manager_v2(registry, id, 1));
@@ -477,23 +472,23 @@ QWaylandInputDevice *QWaylandDisplay::defaultInputDevice() const
}
#if QT_CONFIG(cursor)
-void QWaylandDisplay::setCursor(struct wl_buffer *buffer, struct wl_cursor_image *image)
+void QWaylandDisplay::setCursor(struct wl_buffer *buffer, struct wl_cursor_image *image, qreal dpr)
{
/* Qt doesn't tell us which input device we should set the cursor
* for, so set it for all devices. */
for (int i = 0; i < mInputDevices.count(); i++) {
QWaylandInputDevice *inputDevice = mInputDevices.at(i);
- inputDevice->setCursor(buffer, image);
+ inputDevice->setCursor(buffer, image, dpr);
}
}
-void QWaylandDisplay::setCursor(const QSharedPointer<QWaylandBuffer> &buffer, const QPoint &hotSpot)
+void QWaylandDisplay::setCursor(const QSharedPointer<QWaylandBuffer> &buffer, const QPoint &hotSpot, qreal dpr)
{
/* Qt doesn't tell us which input device we should set the cursor
* for, so set it for all devices. */
for (int i = 0; i < mInputDevices.count(); i++) {
QWaylandInputDevice *inputDevice = mInputDevices.at(i);
- inputDevice->setCursor(buffer, hotSpot);
+ inputDevice->setCursor(buffer, hotSpot, dpr);
}
}
#endif // QT_CONFIG(cursor)
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
index a65ed320d..d39e561f6 100644
--- a/src/client/qwaylanddisplay_p.h
+++ b/src/client/qwaylanddisplay_p.h
@@ -63,7 +63,6 @@
#include <QtWaylandClient/private/qwayland-wayland.h>
#include <QtWaylandClient/private/qtwaylandclientglobal_p.h>
-#include <QtWaylandClient/private/qwayland-xdg-shell.h>
#include <QtWaylandClient/private/qwaylandshm_p.h>
struct wl_cursor_image;
@@ -75,16 +74,13 @@ class QSocketNotifier;
class QPlatformScreen;
namespace QtWayland {
- class qt_shell;
- class qt_sub_surface_extension;
class qt_surface_extension;
class zwp_text_input_manager_v2;
- class xdg_shell;
}
namespace QtWaylandClient {
-Q_DECLARE_LOGGING_CATEGORY(lcQpaWayland);
+Q_WAYLAND_CLIENT_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcQpaWayland);
class QWaylandInputDevice;
class QWaylandBuffer;
@@ -95,10 +91,8 @@ class QWaylandDataDeviceManager;
class QWaylandTouchExtension;
class QWaylandQtKeyExtension;
class QWaylandWindow;
-class QWaylandEventThread;
class QWaylandIntegration;
class QWaylandHardwareIntegration;
-class QWaylandXdgShell;
class QWaylandShellSurface;
typedef void (*RegistryListener)(void *data,
@@ -127,8 +121,8 @@ public:
QWaylandWindowManagerIntegration *windowManagerIntegration() const;
#if QT_CONFIG(cursor)
- void setCursor(struct wl_buffer *buffer, struct wl_cursor_image *image);
- void setCursor(const QSharedPointer<QWaylandBuffer> &buffer, const QPoint &hotSpot);
+ void setCursor(struct wl_buffer *buffer, struct wl_cursor_image *image, qreal dpr);
+ void setCursor(const QSharedPointer<QWaylandBuffer> &buffer, const QPoint &hotSpot, qreal dpr);
#endif
struct wl_display *wl_display() const { return mDisplay; }
struct ::wl_registry *wl_registry() { return object(); }
diff --git a/src/client/qwaylanddnd.cpp b/src/client/qwaylanddnd.cpp
index fe620506d..b01a9db36 100644
--- a/src/client/qwaylanddnd.cpp
+++ b/src/client/qwaylanddnd.cpp
@@ -77,15 +77,19 @@ void QWaylandDrag::cancel()
m_display->currentInputDevice()->dataDevice()->cancelDrag();
}
-void QWaylandDrag::move(const QPoint &globalPos)
+void QWaylandDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
{
Q_UNUSED(globalPos);
+ Q_UNUSED(b);
+ Q_UNUSED(mods);
// Do nothing
}
-void QWaylandDrag::drop(const QPoint &globalPos)
+void QWaylandDrag::drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
{
Q_UNUSED(globalPos);
+ Q_UNUSED(b);
+ Q_UNUSED(mods);
// Do nothing
}
diff --git a/src/client/qwaylanddnd_p.h b/src/client/qwaylanddnd_p.h
index 04b39826c..474fe2ab1 100644
--- a/src/client/qwaylanddnd_p.h
+++ b/src/client/qwaylanddnd_p.h
@@ -78,8 +78,8 @@ public:
protected:
void startDrag() override;
void cancel() override;
- void move(const QPoint &globalPos) override;
- void drop(const QPoint &globalPos) override;
+ void move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
+ void drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
void endDrag() override;
diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp
index 93344d13f..4835bd68e 100644
--- a/src/client/qwaylandinputdevice.cpp
+++ b/src/client/qwaylandinputdevice.cpp
@@ -371,7 +371,7 @@ void QWaylandInputDevice::setCursor(Qt::CursorShape newShape, QWaylandScreen *sc
}
struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
- setCursor(buffer, image);
+ setCursor(buffer, image, screen->devicePixelRatio());
}
void QWaylandInputDevice::setCursor(const QCursor &cursor, QWaylandScreen *screen)
@@ -381,20 +381,20 @@ void QWaylandInputDevice::setCursor(const QCursor &cursor, QWaylandScreen *scree
mPointer->mCursorShape = cursor.shape();
if (cursor.shape() == Qt::BitmapCursor) {
- setCursor(screen->waylandCursor()->cursorBitmapImage(&cursor), cursor.hotSpot());
+ setCursor(screen->waylandCursor()->cursorBitmapImage(&cursor), cursor.hotSpot(), screen->devicePixelRatio());
return;
}
setCursor(cursor.shape(), screen);
}
-void QWaylandInputDevice::setCursor(struct wl_buffer *buffer, struct wl_cursor_image *image)
+void QWaylandInputDevice::setCursor(struct wl_buffer *buffer, struct wl_cursor_image *image, int bufferScale)
{
setCursor(buffer,
image ? QPoint(image->hotspot_x, image->hotspot_y) : QPoint(),
- image ? QSize(image->width, image->height) : QSize());
+ image ? QSize(image->width, image->height) : QSize(), bufferScale);
}
-void QWaylandInputDevice::setCursor(struct wl_buffer *buffer, const QPoint &hotSpot, const QSize &size)
+void QWaylandInputDevice::setCursor(struct wl_buffer *buffer, const QPoint &hotSpot, const QSize &size, int bufferScale)
{
if (mCaps & WL_SEAT_CAPABILITY_POINTER) {
bool force = mPointer->mEnterSerial > mPointer->mCursorSerial;
@@ -417,14 +417,16 @@ void QWaylandInputDevice::setCursor(struct wl_buffer *buffer, const QPoint &hotS
mPointer->set_cursor(mPointer->mEnterSerial, pointerSurface,
hotSpot.x(), hotSpot.y());
wl_surface_attach(pointerSurface, buffer, 0, 0);
+ if (mQDisplay->compositorVersion() >= 3)
+ wl_surface_set_buffer_scale(pointerSurface, bufferScale);
wl_surface_damage(pointerSurface, 0, 0, size.width(), size.height());
wl_surface_commit(pointerSurface);
}
}
-void QWaylandInputDevice::setCursor(const QSharedPointer<QWaylandBuffer> &buffer, const QPoint &hotSpot)
+void QWaylandInputDevice::setCursor(const QSharedPointer<QWaylandBuffer> &buffer, const QPoint &hotSpot, int bufferScale)
{
- setCursor(buffer->buffer(), hotSpot, buffer->size());
+ setCursor(buffer->buffer(), hotSpot, buffer->size(), bufferScale);
mPixmapCursor = buffer;
}
#endif
diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h
index 48c1cf57f..4b12cc089 100644
--- a/src/client/qwaylandinputdevice_p.h
+++ b/src/client/qwaylandinputdevice_p.h
@@ -110,9 +110,9 @@ public:
#if QT_CONFIG(cursor)
void setCursor(const QCursor &cursor, QWaylandScreen *screen);
- void setCursor(struct wl_buffer *buffer, struct ::wl_cursor_image *image);
- void setCursor(struct wl_buffer *buffer, const QPoint &hotSpot, const QSize &size);
- void setCursor(const QSharedPointer<QWaylandBuffer> &buffer, const QPoint &hotSpot);
+ void setCursor(struct wl_buffer *buffer, struct ::wl_cursor_image *image, int bufferScale);
+ void setCursor(struct wl_buffer *buffer, const QPoint &hotSpot, const QSize &size, int bufferScale);
+ void setCursor(const QSharedPointer<QWaylandBuffer> &buffer, const QPoint &hotSpot, int bufferScale);
#endif
void handleWindowDestroyed(QWaylandWindow *window);
void handleEndDrag();
diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp
index b804988b2..fbfdd57f4 100644
--- a/src/client/qwaylandintegration.cpp
+++ b/src/client/qwaylandintegration.cpp
@@ -77,8 +77,6 @@
#include "qwaylandshellintegration_p.h"
#include "qwaylandshellintegrationfactory_p.h"
-#include "qwaylandxdgshellintegration_p.h"
-#include "qwaylandwlshellintegration_p.h"
#include "qwaylandxdgshellv6integration_p.h"
#include "qwaylandinputdeviceintegration_p.h"
@@ -409,9 +407,9 @@ void QWaylandIntegration::initializeShellIntegration()
}
}
- if (!mShellIntegration || !mShellIntegration->initialize(mDisplay.data())) {
- mShellIntegration.reset();
- qWarning("Failed to load shell integration %s", qPrintable(targetKey));
+ if (!mShellIntegration) {
+ qCWarning(lcQpaWayland) << "Loading shell integration failed.";
+ qCWarning(lcQpaWayland) << "Attempted to load the following shells" << preferredShells;
}
}
@@ -443,15 +441,12 @@ void QWaylandIntegration::initializeInputDeviceIntegration()
QWaylandShellIntegration *QWaylandIntegration::createShellIntegration(const QString &integrationName)
{
- if (integrationName == QLatin1Literal("wl-shell")) {
- return QWaylandWlShellIntegration::create(mDisplay.data());
- } else if (integrationName == QLatin1Literal("xdg-shell-v5")) {
- return QWaylandXdgShellIntegration::create(mDisplay.data());
- } else if (integrationName == QLatin1Literal("xdg-shell-v6")) {
+ if (integrationName == QLatin1Literal("xdg-shell-v6")) {
return QWaylandXdgShellV6Integration::create(mDisplay.data());
} else if (QWaylandShellIntegrationFactory::keys().contains(integrationName)) {
- return QWaylandShellIntegrationFactory::create(integrationName, QStringList());
+ return QWaylandShellIntegrationFactory::create(integrationName, mDisplay.data());
} else {
+ qCWarning(lcQpaWayland) << "No shell integration named" << integrationName << "found";
return nullptr;
}
}
diff --git a/src/client/qwaylandnativeinterface.cpp b/src/client/qwaylandnativeinterface.cpp
index 9946c3235..76acb526b 100644
--- a/src/client/qwaylandnativeinterface.cpp
+++ b/src/client/qwaylandnativeinterface.cpp
@@ -40,13 +40,13 @@
#include "qwaylandnativeinterface_p.h"
#include "qwaylanddisplay_p.h"
#include "qwaylandwindow_p.h"
+#include "qwaylandshellintegration_p.h"
#include "qwaylandsubsurface_p.h"
#include "qwaylandextendedsurface_p.h"
#include "qwaylandintegration_p.h"
#include "qwaylanddisplay_p.h"
#include "qwaylandwindowmanagerintegration_p.h"
#include "qwaylandscreen_p.h"
-#include "qwaylandwlshellsurface_p.h"
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/QScreen>
#include <QtWaylandClient/private/qwaylandclientbufferintegration_p.h>
@@ -91,18 +91,13 @@ void *QWaylandNativeInterface::nativeResourceForWindow(const QByteArray &resourc
QWaylandWindow *w = static_cast<QWaylandWindow*>(window->handle());
return w ? w->object() : nullptr;
}
- if (lowerCaseResource == "wl_shell_surface") {
- QWaylandWindow *w = static_cast<QWaylandWindow*>(window->handle());
- if (!w)
- return nullptr;
- QWaylandWlShellSurface *s = qobject_cast<QWaylandWlShellSurface *>(w->shellSurface());
- if (!s)
- return nullptr;
- return s->object();
- }
+
if (lowerCaseResource == "egldisplay" && m_integration->clientBufferIntegration())
return m_integration->clientBufferIntegration()->nativeResource(QWaylandClientBufferIntegration::EglDisplay);
+ if (auto shellIntegration = m_integration->shellIntegration())
+ return shellIntegration->nativeResourceForWindow(resourceString, window);
+
return nullptr;
}
diff --git a/src/client/qwaylandqtkey.cpp b/src/client/qwaylandqtkey.cpp
index ce0d2124e..a60185bd6 100644
--- a/src/client/qwaylandqtkey.cpp
+++ b/src/client/qwaylandqtkey.cpp
@@ -46,12 +46,12 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
QWaylandQtKeyExtension::QWaylandQtKeyExtension(QWaylandDisplay *display, uint32_t id)
- : QtWayland::qt_key_extension(display->wl_registry(), id, 2)
+ : QtWayland::zqt_key_v1(display->wl_registry(), id, 1)
, m_display(display)
{
}
-void QWaylandQtKeyExtension::key_extension_qtkey(struct wl_surface *surface,
+void QWaylandQtKeyExtension::zqt_key_v1_key(struct wl_surface *surface,
uint32_t time,
uint32_t type,
uint32_t key,
diff --git a/src/client/qwaylandqtkey_p.h b/src/client/qwaylandqtkey_p.h
index 9091cf819..117c44a6d 100644
--- a/src/client/qwaylandqtkey_p.h
+++ b/src/client/qwaylandqtkey_p.h
@@ -54,7 +54,7 @@
#include <qpa/qwindowsysteminterface.h>
#include <QtWaylandClient/qtwaylandclientglobal.h>
-#include <QtWaylandClient/private/qwayland-qtkey-extension.h>
+#include <QtWaylandClient/private/qwayland-qt-key-unstable-v1.h>
QT_BEGIN_NAMESPACE
@@ -62,7 +62,7 @@ namespace QtWaylandClient {
class QWaylandDisplay;
-class Q_WAYLAND_CLIENT_EXPORT QWaylandQtKeyExtension : public QtWayland::qt_key_extension
+class Q_WAYLAND_CLIENT_EXPORT QWaylandQtKeyExtension : public QtWayland::zqt_key_v1
{
public:
QWaylandQtKeyExtension(QWaylandDisplay *display, uint32_t id);
@@ -70,17 +70,17 @@ public:
private:
QWaylandDisplay *m_display = nullptr;
- void key_extension_qtkey(struct wl_surface *surface,
- uint32_t time,
- uint32_t type,
- uint32_t key,
- uint32_t modifiers,
- uint32_t nativeScanCode,
- uint32_t nativeVirtualKey,
- uint32_t nativeModifiers,
- const QString &text,
- uint32_t autorep,
- uint32_t count) override;
+ void zqt_key_v1_key(struct wl_surface *surface,
+ uint32_t time,
+ uint32_t type,
+ uint32_t key,
+ uint32_t modifiers,
+ uint32_t nativeScanCode,
+ uint32_t nativeVirtualKey,
+ uint32_t nativeModifiers,
+ const QString &text,
+ uint32_t autorep,
+ uint32_t count) override;
};
diff --git a/src/client/qwaylandscreen.cpp b/src/client/qwaylandscreen.cpp
index 38d97a91d..37fe5f323 100644
--- a/src/client/qwaylandscreen.cpp
+++ b/src/client/qwaylandscreen.cpp
@@ -60,20 +60,6 @@ QWaylandScreen::QWaylandScreen(QWaylandDisplay *waylandDisplay, int version, uin
{
}
-QWaylandScreen::~QWaylandScreen()
-{
-#if QT_CONFIG(cursor)
- delete mWaylandCursor;
-#endif
-}
-
-void QWaylandScreen::init()
-{
-#if QT_CONFIG(cursor)
- mWaylandCursor = new QWaylandCursor(this);
-#endif
-}
-
QWaylandDisplay * QWaylandScreen::display() const
{
return mWaylandDisplay;
@@ -165,11 +151,20 @@ qreal QWaylandScreen::refreshRate() const
}
#if QT_CONFIG(cursor)
+
QPlatformCursor *QWaylandScreen::cursor() const
{
- return mWaylandCursor;
+ return const_cast<QWaylandScreen *>(this)->waylandCursor();
+}
+
+QWaylandCursor *QWaylandScreen::waylandCursor()
+{
+ if (!mWaylandCursor)
+ mWaylandCursor.reset(new QWaylandCursor(this));
+ return mWaylandCursor.data();
}
-#endif
+
+#endif // QT_CONFIG(cursor)
QWaylandScreen * QWaylandScreen::waylandScreenFromWindow(QWindow *window)
{
diff --git a/src/client/qwaylandscreen_p.h b/src/client/qwaylandscreen_p.h
index 9df55d603..39b72bc24 100644
--- a/src/client/qwaylandscreen_p.h
+++ b/src/client/qwaylandscreen_p.h
@@ -67,9 +67,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandScreen : public QPlatformScreen, QtWayland
{
public:
QWaylandScreen(QWaylandDisplay *waylandDisplay, int version, uint32_t id);
- ~QWaylandScreen() override;
- void init();
QWaylandDisplay *display() const;
QString manufacturer() const override;
@@ -95,7 +93,7 @@ public:
#if QT_CONFIG(cursor)
QPlatformCursor *cursor() const override;
- QWaylandCursor *waylandCursor() const { return mWaylandCursor; }
+ QWaylandCursor *waylandCursor();
#endif
uint32_t outputId() const { return m_outputId; }
@@ -130,7 +128,7 @@ private:
Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation;
#if QT_CONFIG(cursor)
- QWaylandCursor *mWaylandCursor = nullptr;
+ QScopedPointer<QWaylandCursor> mWaylandCursor;
#endif
};
diff --git a/src/client/qwaylandshellsurface_p.h b/src/client/qwaylandshellsurface_p.h
index fdc309a63..6b6bb9e84 100644
--- a/src/client/qwaylandshellsurface_p.h
+++ b/src/client/qwaylandshellsurface_p.h
@@ -96,12 +96,9 @@ public:
inline QWaylandWindow *window() { return m_window; }
virtual void setType(Qt::WindowType type, QWaylandWindow *transientParent) = 0;
-
-protected:
- virtual void setMaximized() {}
- virtual void setFullscreen() {}
- virtual void setNormal() {}
- virtual void setMinimized() {}
+ virtual void applyConfigure() {}
+ virtual void requestWindowStates(Qt::WindowStates states) {Q_UNUSED(states);}
+ virtual bool wantsDecorations() const { return false; }
private:
QWaylandWindow *m_window = nullptr;
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
index fdfd66688..ef49e8ea8 100644
--- a/src/client/qwaylandwindow.cpp
+++ b/src/client/qwaylandwindow.cpp
@@ -44,8 +44,6 @@
#include "qwaylandinputdevice_p.h"
#include "qwaylandscreen_p.h"
#include "qwaylandshellsurface_p.h"
-#include "qwaylandwlshellsurface_p.h"
-#include "qwaylandxdgsurface_p.h"
#include "qwaylandsubsurface_p.h"
#include "qwaylandabstractdecoration_p.h"
#include "qwaylandwindowmanagerintegration_p.h"
@@ -200,11 +198,8 @@ void QWaylandWindow::initWindow()
else
setGeometry_helper(window()->geometry());
setMask(window()->mask());
- // setWindowStateInternal is a no-op if the argument is equal to mState,
- // but since we're creating the shellsurface only now we reset mState to
- // make sure the state gets sent out to the compositor
- mState = Qt::WindowNoState;
- setWindowStateInternal(window()->windowStates());
+ if (mShellSurface)
+ mShellSurface->requestWindowStates(window()->windowStates());
handleContentOrientationChange(window()->contentOrientation());
mFlags = window()->flags();
}
@@ -333,7 +328,16 @@ void QWaylandWindow::setGeometry(const QRect &rect)
sendExposeEvent(QRect(QPoint(), geometry().size()));
}
+void QWaylandWindow::resizeFromApplyConfigure(const QSize &sizeWithMargins, const QPoint &offset)
+{
+ QMargins margins = frameMargins();
+ int widthWithoutMargins = qMax(sizeWithMargins.width() - (margins.left()+margins.right()), 1);
+ int heightWithoutMargins = qMax(sizeWithMargins.height() - (margins.top()+margins.bottom()), 1);
+ QRect geometry(QPoint(), QSize(widthWithoutMargins, heightWithoutMargins));
+ mOffset += offset;
+ setGeometry(geometry);
+}
void QWaylandWindow::sendExposeEvent(const QRect &rect)
{
@@ -421,46 +425,24 @@ void QWaylandWindow::setMask(const QRegion &mask)
wl_surface::commit();
}
-void QWaylandWindow::configure(uint32_t edges, int32_t width, int32_t height)
+void QWaylandWindow::applyConfigureWhenPossible()
{
QMutexLocker resizeLocker(&mResizeLock);
- mConfigure.edges |= edges;
- mConfigure.width = width;
- mConfigure.height = height;
-
- if (!mRequestResizeSent && !mConfigure.isEmpty()) {
- mRequestResizeSent= true;
- QMetaObject::invokeMethod(this, "requestResize", Qt::QueuedConnection);
+ if (!mWaitingToApplyConfigure) {
+ mWaitingToApplyConfigure = true;
+ QMetaObject::invokeMethod(this, "applyConfigure", Qt::QueuedConnection);
}
}
-void QWaylandWindow::doResize()
+void QWaylandWindow::doApplyConfigure()
{
- if (mConfigure.isEmpty()) {
+ if (!mWaitingToApplyConfigure)
return;
- }
-
- int widthWithoutMargins = qMax(mConfigure.width-(frameMargins().left() +frameMargins().right()),1);
- int heightWithoutMargins = qMax(mConfigure.height-(frameMargins().top()+frameMargins().bottom()),1);
- widthWithoutMargins = qMax(widthWithoutMargins, window()->minimumSize().width());
- heightWithoutMargins = qMax(heightWithoutMargins, window()->minimumSize().height());
- QRect geometry = QRect(0,0, widthWithoutMargins, heightWithoutMargins);
-
- int x = 0;
- int y = 0;
- QSize size = this->geometry().size();
- if (mConfigure.edges & WL_SHELL_SURFACE_RESIZE_LEFT) {
- x = size.width() - geometry.width();
- }
- if (mConfigure.edges & WL_SHELL_SURFACE_RESIZE_TOP) {
- y = size.height() - geometry.height();
- }
- mOffset += QPoint(x, y);
-
- setGeometry(geometry);
+ if (mShellSurface)
+ mShellSurface->applyConfigure();
- mConfigure.clear();
+ mWaitingToApplyConfigure = false;
}
void QWaylandWindow::setCanResize(bool canResize)
@@ -472,8 +454,8 @@ void QWaylandWindow::setCanResize(bool canResize)
if (mResizeDirty) {
QWindowSystemInterface::handleGeometryChange(window(), geometry());
}
- if (!mConfigure.isEmpty()) {
- doResize();
+ if (mWaitingToApplyConfigure) {
+ doApplyConfigure();
sendExposeEvent(QRect(QPoint(), geometry().size()));
} else if (mResizeDirty) {
mResizeDirty = false;
@@ -482,15 +464,13 @@ void QWaylandWindow::setCanResize(bool canResize)
}
}
-void QWaylandWindow::requestResize()
+void QWaylandWindow::applyConfigure()
{
QMutexLocker lock(&mResizeLock);
- if (mCanResize || !mSentInitialResize) {
- doResize();
- }
+ if (mCanResize || !mSentInitialResize)
+ doApplyConfigure();
- mRequestResizeSent = false;
lock.unlock();
sendExposeEvent(QRect(QPoint(), geometry().size()));
QWindowSystemInterface::flushWindowSystemEvents();
@@ -596,9 +576,8 @@ void QWaylandWindow::frameCallback(void *data, struct wl_callback *callback, uin
self->mWaitingForFrameSync = false;
if (self->mUpdateRequested) {
- QWindowPrivate *w = QWindowPrivate::get(self->window());
self->mUpdateRequested = false;
- w->deliverUpdateRequest();
+ self->deliverUpdateRequest();
}
}
@@ -673,10 +652,10 @@ void QWaylandWindow::setOrientationMask(Qt::ScreenOrientations mask)
mShellSurface->setContentOrientationMask(mask);
}
-void QWaylandWindow::setWindowState(Qt::WindowStates state)
+void QWaylandWindow::setWindowState(Qt::WindowStates states)
{
- if (setWindowStateInternal(state))
- QWindowSystemInterface::flushWindowSystemEvents(); // Required for oldState to work on WindowStateChanged
+ if (mShellSurface)
+ mShellSurface->requestWindowStates(states);
}
void QWaylandWindow::setWindowFlags(Qt::WindowFlags flags)
@@ -690,20 +669,6 @@ void QWaylandWindow::setWindowFlags(Qt::WindowFlags flags)
bool QWaylandWindow::createDecoration()
{
- // so far only xdg-shell support this "unminimize" trick, may be moved elsewhere
- if (mState & Qt::WindowMinimized) {
- QWaylandXdgSurface *xdgSurface = qobject_cast<QWaylandXdgSurface *>(mShellSurface);
- if ( xdgSurface ) {
- Qt::WindowStates states;
- if (xdgSurface->isFullscreen())
- states |= Qt::WindowFullScreen;
- if (xdgSurface->isMaximized())
- states |= Qt::WindowMaximized;
-
- setWindowStateInternal(states);
- }
- }
-
if (!mDisplay->supportsWindowDecoration())
return false;
@@ -720,12 +685,14 @@ bool QWaylandWindow::createDecoration()
default:
break;
}
- if (mFlags & Qt::FramelessWindowHint || isFullscreen())
+ if (mFlags & Qt::FramelessWindowHint)
decoration = false;
if (mFlags & Qt::BypassWindowManagerHint)
decoration = false;
if (mSubSurfaceWindow)
decoration = false;
+ if (mShellSurface && !mShellSurface->wantsDecorations())
+ decoration = false;
bool hadDecoration = mWindowDecoration;
if (decoration && !decorationPluginFailed) {
@@ -971,31 +938,11 @@ bool QWaylandWindow::setMouseGrabEnabled(bool grab)
return true;
}
-bool QWaylandWindow::setWindowStateInternal(Qt::WindowStates state)
+void QWaylandWindow::handleWindowStatesChanged(Qt::WindowStates states)
{
- if (mState == state) {
- return false;
- }
-
- // As of february 2013 QWindow::setWindowState sets the new state value after
- // QPlatformWindow::setWindowState returns, so we cannot rely on QWindow::windowState
- // here. We use then this mState variable.
- mState = state;
-
- if (mShellSurface) {
- createDecoration();
- if (state & Qt::WindowMaximized)
- mShellSurface->setMaximized();
- if (state & Qt::WindowFullScreen)
- mShellSurface->setFullscreen();
- if (state & Qt::WindowMinimized)
- mShellSurface->setMinimized();
- if (!state)
- mShellSurface->setNormal();
- }
-
- QWindowSystemInterface::handleWindowStateChanged(window(), mState);
- return true;
+ createDecoration();
+ QWindowSystemInterface::handleWindowStateChanged(window(), states, mLastReportedWindowStates);
+ mLastReportedWindowStates = states;
}
void QWaylandWindow::sendProperty(const QString &name, const QVariant &value)
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
index 3324bf700..55f3a515f 100644
--- a/src/client/qwaylandwindow_p.h
+++ b/src/client/qwaylandwindow_p.h
@@ -77,23 +77,6 @@ class QWaylandScreen;
class QWaylandShmBackingStore;
class QWaylandPointerEvent;
-class Q_WAYLAND_CLIENT_EXPORT QWaylandWindowConfigure
-{
-public:
- QWaylandWindowConfigure()
- { }
-
- void clear()
- { width = height = edges = 0; }
-
- bool isEmpty() const
- { return !height || !width; }
-
- int width = 0;
- int height = 0;
- uint32_t edges = 0;
-};
-
class Q_WAYLAND_CLIENT_EXPORT QWaylandWindow : public QObject, public QPlatformWindow, public QtWayland::wl_surface
{
Q_OBJECT
@@ -118,8 +101,9 @@ public:
void setWindowIcon(const QIcon &icon) override;
void setGeometry(const QRect &rect) override;
+ void resizeFromApplyConfigure(const QSize &sizeWithMargins, const QPoint &offset = {0, 0});
- void configure(uint32_t edges, int32_t width, int32_t height);
+ void applyConfigureWhenPossible(); //rename to possible?
using QtWayland::wl_surface::attach;
void attach(QWaylandBuffer *buffer, int x, int y);
@@ -145,8 +129,9 @@ public:
void handleContentOrientationChange(Qt::ScreenOrientation orientation) override;
void setOrientationMask(Qt::ScreenOrientations mask);
- void setWindowState(Qt::WindowStates state) override;
+ void setWindowState(Qt::WindowStates states) override;
void setWindowFlags(Qt::WindowFlags flags) override;
+ void handleWindowStatesChanged(Qt::WindowStates states);
void raise() override;
void lower() override;
@@ -170,9 +155,6 @@ public:
bool createDecoration();
- inline bool isMaximized() const { return mState & Qt::WindowMaximized; }
- inline bool isFullscreen() const { return mState & Qt::WindowFullScreen; }
-
#if QT_CONFIG(cursor)
void setMouseCursor(QWaylandInputDevice *device, const QCursor &cursor);
void restoreMouseCursor(QWaylandInputDevice *device);
@@ -181,7 +163,7 @@ public:
QWaylandWindow *transientParent() const;
QMutex *resizeMutex() { return &mResizeLock; }
- void doResize();
+ void doApplyConfigure();
void setCanResize(bool canResize);
bool setMouseGrabEnabled(bool grab) override;
@@ -206,7 +188,7 @@ public:
void requestUpdate() override;
public slots:
- void requestResize();
+ void applyConfigure();
protected:
void surface_enter(struct ::wl_output *output) override;
@@ -228,8 +210,7 @@ protected:
QWaitCondition mFrameSyncWait;
QMutex mResizeLock;
- QWaylandWindowConfigure mConfigure;
- bool mRequestResizeSent = false;
+ bool mWaitingToApplyConfigure = false;
bool mCanResize = true;
bool mResizeDirty = false;
bool mResizeAfterSwap;
@@ -241,9 +222,9 @@ protected:
QIcon mWindowIcon;
- Qt::WindowStates mState = Qt::WindowNoState;
Qt::WindowFlags mFlags;
QRegion mMask;
+ Qt::WindowStates mLastReportedWindowStates = Qt::WindowNoState;
QWaylandShmBackingStore *mBackingStore = nullptr;
@@ -251,7 +232,6 @@ private slots:
void handleScreenRemoved(QScreen *qScreen);
private:
- bool setWindowStateInternal(Qt::WindowStates flags);
void setGeometry_helper(const QRect &rect);
void initWindow();
void initializeWlSurface();
diff --git a/src/client/qwaylandxdgshellv6.cpp b/src/client/qwaylandxdgshellv6.cpp
index a166a3bc9..beabddbbb 100644
--- a/src/client/qwaylandxdgshellv6.cpp
+++ b/src/client/qwaylandxdgshellv6.cpp
@@ -46,8 +46,6 @@
#include "qwaylandscreen_p.h"
#include "qwaylandabstractdecoration_p.h"
-#include <QtCore/QDebug>
-
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
@@ -56,32 +54,65 @@ QWaylandXdgSurfaceV6::Toplevel::Toplevel(QWaylandXdgSurfaceV6 *xdgSurface)
: QtWayland::zxdg_toplevel_v6(xdgSurface->get_toplevel())
, m_xdgSurface(xdgSurface)
{
+ requestWindowStates(xdgSurface->window()->window()->windowStates());
}
QWaylandXdgSurfaceV6::Toplevel::~Toplevel()
{
+ if (m_applied.states & Qt::WindowActive) {
+ QWaylandWindow *window = m_xdgSurface->window();
+ window->display()->handleWindowDeactivated(window);
+ }
if (isInitialized())
destroy();
}
void QWaylandXdgSurfaceV6::Toplevel::applyConfigure()
{
- //TODO: resize, activate etc
- m_xdgSurface->m_window->configure(0, m_configureState.width, m_configureState.height);
+ if (!(m_applied.states & (Qt::WindowMaximized|Qt::WindowFullScreen)))
+ m_normalSize = m_xdgSurface->m_window->window()->frameGeometry().size();
+
+ if (m_pending.size.isEmpty() && !m_normalSize.isEmpty())
+ m_pending.size = m_normalSize;
+
+ if ((m_pending.states & Qt::WindowActive) && !(m_applied.states & Qt::WindowActive))
+ m_xdgSurface->m_window->display()->handleWindowActivated(m_xdgSurface->m_window);
+
+ if (!(m_pending.states & Qt::WindowActive) && (m_applied.states & Qt::WindowActive))
+ m_xdgSurface->m_window->display()->handleWindowDeactivated(m_xdgSurface->m_window);
+
+ // TODO: none of the other plugins send WindowActive either, but is it on purpose?
+ Qt::WindowStates statesWithoutActive = m_pending.states & ~Qt::WindowActive;
+
+ m_xdgSurface->m_window->handleWindowStatesChanged(statesWithoutActive);
+ m_xdgSurface->m_window->resizeFromApplyConfigure(m_pending.size);
+ m_applied = m_pending;
}
void QWaylandXdgSurfaceV6::Toplevel::zxdg_toplevel_v6_configure(int32_t width, int32_t height, wl_array *states)
{
- m_configureState.width = width;
- m_configureState.height = height;
+ m_pending.size = QSize(width, height);
- uint32_t *state = reinterpret_cast<uint32_t *>(states->data);
+ auto *xdgStates = static_cast<uint32_t *>(states->data);
size_t numStates = states->size / sizeof(uint32_t);
- m_configureState.states.reserve(numStates);
- m_configureState.states.clear();
- for (size_t i = 0; i < numStates; i++)
- m_configureState.states << state[i];
+ m_pending.states = Qt::WindowNoState;
+
+ for (size_t i = 0; i < numStates; i++) {
+ switch (xdgStates[i]) {
+ case ZXDG_TOPLEVEL_V6_STATE_ACTIVATED:
+ m_pending.states |= Qt::WindowActive;
+ break;
+ case ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED:
+ m_pending.states |= Qt::WindowMaximized;
+ break;
+ case ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN:
+ m_pending.states |= Qt::WindowFullScreen;
+ break;
+ default:
+ break;
+ }
+ }
}
void QWaylandXdgSurfaceV6::Toplevel::zxdg_toplevel_v6_close()
@@ -89,6 +120,32 @@ void QWaylandXdgSurfaceV6::Toplevel::zxdg_toplevel_v6_close()
m_xdgSurface->m_window->window()->close();
}
+void QWaylandXdgSurfaceV6::Toplevel::requestWindowStates(Qt::WindowStates states)
+{
+ // Re-send what's different from the applied state
+ Qt::WindowStates changedStates = m_applied.states ^ states;
+
+ if (changedStates & Qt::WindowMaximized) {
+ if (states & Qt::WindowMaximized)
+ set_maximized();
+ else
+ unset_maximized();
+ }
+
+ if (changedStates & Qt::WindowFullScreen) {
+ if (states & Qt::WindowFullScreen)
+ set_fullscreen(nullptr);
+ else
+ unset_fullscreen();
+ }
+
+ // Minimized state is not reported by the protocol, so always send it
+ if (states & Qt::WindowMinimized) {
+ set_minimized();
+ m_xdgSurface->window()->handleWindowStatesChanged(states & ~Qt::WindowMinimized);
+ }
+}
+
QWaylandXdgSurfaceV6::Popup::Popup(QWaylandXdgSurfaceV6 *xdgSurface, QWaylandXdgSurfaceV6 *parent,
QtWayland::zxdg_positioner_v6 *positioner)
: zxdg_popup_v6(xdgSurface->get_popup(parent->object(), positioner->object()))
@@ -104,7 +161,6 @@ QWaylandXdgSurfaceV6::Popup::~Popup()
void QWaylandXdgSurfaceV6::Popup::applyConfigure()
{
-
}
void QWaylandXdgSurfaceV6::Popup::zxdg_popup_v6_popup_done()
@@ -187,6 +243,34 @@ bool QWaylandXdgSurfaceV6::handleExpose(const QRegion &region)
return false;
}
+void QWaylandXdgSurfaceV6::applyConfigure()
+{
+ Q_ASSERT(m_pendingConfigureSerial != 0);
+
+ if (m_toplevel)
+ m_toplevel->applyConfigure();
+ if (m_popup)
+ m_popup->applyConfigure();
+
+ m_configured = true;
+ ack_configure(m_pendingConfigureSerial);
+
+ m_pendingConfigureSerial = 0;
+}
+
+bool QWaylandXdgSurfaceV6::wantsDecorations() const
+{
+ return m_toplevel && !(m_toplevel->m_pending.states & Qt::WindowFullScreen);
+}
+
+void QWaylandXdgSurfaceV6::requestWindowStates(Qt::WindowStates states)
+{
+ if (m_toplevel)
+ m_toplevel->requestWindowStates(states);
+ else
+ qCWarning(lcQpaWayland) << "Non-toplevel surfaces can't request window states";
+}
+
void QWaylandXdgSurfaceV6::setToplevel()
{
Q_ASSERT(!m_toplevel && !m_popup);
@@ -220,21 +304,14 @@ void QWaylandXdgSurfaceV6::setPopup(QWaylandWindow *parent, QWaylandInputDevice
void QWaylandXdgSurfaceV6::zxdg_surface_v6_configure(uint32_t serial)
{
- m_configured = true;
- if (m_toplevel)
- m_toplevel->applyConfigure();
- else if (m_popup)
- m_popup->applyConfigure();
-
+ m_window->applyConfigureWhenPossible();
+ m_pendingConfigureSerial = serial;
if (!m_exposeRegion.isEmpty()) {
QWindowSystemInterface::handleExposeEvent(m_window->window(), m_exposeRegion);
m_exposeRegion = QRegion();
}
- ack_configure(serial);
}
-
-
QWaylandXdgShellV6::QWaylandXdgShellV6(struct ::wl_registry *registry, uint32_t id, uint32_t availableVersion)
: QtWayland::zxdg_shell_v6(registry, id, qMin(availableVersion, 1u))
{
diff --git a/src/client/qwaylandxdgshellv6_p.h b/src/client/qwaylandxdgshellv6_p.h
index b72d3d18a..d2448bc66 100644
--- a/src/client/qwaylandxdgshellv6_p.h
+++ b/src/client/qwaylandxdgshellv6_p.h
@@ -73,6 +73,7 @@ class QWaylandXdgShellV6;
class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgSurfaceV6 : public QWaylandShellSurface, public QtWayland::zxdg_surface_v6
{
+ Q_OBJECT
public:
QWaylandXdgSurfaceV6(QWaylandXdgShellV6 *shell, ::zxdg_surface_v6 *surface, QWaylandWindow *window);
~QWaylandXdgSurfaceV6() override;
@@ -85,8 +86,12 @@ public:
void setType(Qt::WindowType type, QWaylandWindow *transientParent) override;
bool handleExpose(const QRegion &) override;
+ bool handlesActiveState() const { return m_toplevel; }
+ void applyConfigure() override;
+ bool wantsDecorations() const override;
protected:
+ void requestWindowStates(Qt::WindowStates states) override;
void zxdg_surface_v6_configure(uint32_t serial) override;
private:
@@ -101,10 +106,12 @@ private:
void zxdg_toplevel_v6_configure(int32_t width, int32_t height, wl_array *states) override;
void zxdg_toplevel_v6_close() override;
+ void requestWindowStates(Qt::WindowStates states);
struct {
- int32_t width, height;
- QVarLengthArray<uint32_t> states;
- } m_configureState;
+ QSize size = {0, 0};
+ Qt::WindowStates states = Qt::WindowNoState;
+ } m_pending, m_applied;
+ QSize m_normalSize;
QWaylandXdgSurfaceV6 *m_xdgSurface = nullptr;
};
@@ -129,6 +136,7 @@ private:
Popup *m_popup = nullptr;
bool m_configured = false;
QRegion m_exposeRegion;
+ uint m_pendingConfigureSerial = 0;
};
class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgShellV6 : public QtWayland::zxdg_shell_v6
diff --git a/src/client/qwaylandxdgshellv6integration.cpp b/src/client/qwaylandxdgshellv6integration.cpp
index cb82354b6..0eb6b5929 100644
--- a/src/client/qwaylandxdgshellv6integration.cpp
+++ b/src/client/qwaylandxdgshellv6integration.cpp
@@ -41,9 +41,6 @@
#include <QtWaylandClient/private/qwaylandwindow_p.h>
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
-#include <QtWaylandClient/private/qwaylandxdgsurface_p.h>
-#include <QtWaylandClient/private/qwaylandxdgpopup_p.h>
-#include <QtWaylandClient/private/qwaylandxdgshell_p.h>
#include <QtWaylandClient/private/qwaylandxdgshellv6_p.h>
QT_BEGIN_NAMESPACE
@@ -62,9 +59,15 @@ QWaylandXdgShellV6Integration::QWaylandXdgShellV6Integration(QWaylandDisplay *di
QWaylandXdgShellV6Integration *QWaylandXdgShellV6Integration::create(QWaylandDisplay *display)
{
- if (display->hasRegistryGlobal(QLatin1String("zxdg_shell_v6")))
- return new QWaylandXdgShellV6Integration(display);
- return nullptr;
+ if (!display->hasRegistryGlobal(QLatin1String("zxdg_shell_v6")))
+ return nullptr;
+
+ QScopedPointer<QWaylandXdgShellV6Integration> integration;
+ integration.reset(new QWaylandXdgShellV6Integration(display));
+ if (integration && !integration->initialize(display))
+ return nullptr;
+
+ return integration.take();
}
bool QWaylandXdgShellV6Integration::initialize(QWaylandDisplay *display)
@@ -78,6 +81,20 @@ QWaylandShellSurface *QWaylandXdgShellV6Integration::createShellSurface(QWayland
return m_xdgShell->getXdgSurface(window);
}
+void QWaylandXdgShellV6Integration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus)
+{
+ if (newFocus) {
+ auto *xdgSurface = qobject_cast<QWaylandXdgSurfaceV6 *>(newFocus->shellSurface());
+ if (xdgSurface && !xdgSurface->handlesActiveState())
+ m_display->handleWindowActivated(newFocus);
+ }
+ if (oldFocus && qobject_cast<QWaylandXdgSurfaceV6 *>(oldFocus->shellSurface())) {
+ auto *xdgSurface = qobject_cast<QWaylandXdgSurfaceV6 *>(oldFocus->shellSurface());
+ if (xdgSurface && !xdgSurface->handlesActiveState())
+ m_display->handleWindowDeactivated(oldFocus);
+ }
+}
+
}
QT_END_NAMESPACE
diff --git a/src/client/qwaylandxdgshellv6integration_p.h b/src/client/qwaylandxdgshellv6integration_p.h
index bdfd19723..66323a775 100644
--- a/src/client/qwaylandxdgshellv6integration_p.h
+++ b/src/client/qwaylandxdgshellv6integration_p.h
@@ -67,6 +67,7 @@ public:
static QWaylandXdgShellV6Integration *create(QWaylandDisplay* display);
bool initialize(QWaylandDisplay *display) override;
QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
+ void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
private:
QWaylandXdgShellV6Integration(QWaylandDisplay *display);
diff --git a/src/client/qwaylandxdgsurface.cpp b/src/client/qwaylandxdgsurface.cpp
deleted file mode 100644
index 4dfc5e6da..000000000
--- a/src/client/qwaylandxdgsurface.cpp
+++ /dev/null
@@ -1,256 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the config.tests of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwaylandxdgsurface_p.h"
-
-#include "qwaylanddisplay_p.h"
-#include "qwaylandwindow_p.h"
-#include "qwaylandinputdevice_p.h"
-#include "qwaylandabstractdecoration_p.h"
-#include "qwaylandscreen_p.h"
-#include "qwaylandextendedsurface_p.h"
-#include "qwaylandxdgshell_p.h"
-
-
-QT_BEGIN_NAMESPACE
-
-namespace QtWaylandClient {
-
-QWaylandXdgSurface::QWaylandXdgSurface(QWaylandXdgShell *shell, QWaylandWindow *window)
- : QWaylandShellSurface(window)
- , QtWayland::xdg_surface(shell->get_xdg_surface(window->object()))
- , m_window(window)
- , m_shell(shell)
-{
- if (window->display()->windowExtension())
- m_extendedWindow = new QWaylandExtendedSurface(window);
-}
-
-QWaylandXdgSurface::~QWaylandXdgSurface()
-{
- if (m_active)
- window()->display()->handleWindowDeactivated(m_window);
-
- xdg_surface_destroy(object());
- delete m_extendedWindow;
-}
-
-void QWaylandXdgSurface::resize(QWaylandInputDevice *inputDevice, enum wl_shell_surface_resize edges)
-{
- // May need some conversion if types get incompatibles, ATM they're identical
- enum resize_edge const * const arg = reinterpret_cast<enum resize_edge const * const>(&edges);
- resize(inputDevice, *arg);
-}
-
-void QWaylandXdgSurface::resize(QWaylandInputDevice *inputDevice, enum resize_edge edges)
-{
- resize(inputDevice->wl_seat(),
- inputDevice->serial(),
- edges);
-}
-
-bool QWaylandXdgSurface::move(QWaylandInputDevice *inputDevice)
-{
- move(inputDevice->wl_seat(),
- inputDevice->serial());
- return true;
-}
-
-void QWaylandXdgSurface::setMaximized()
-{
- if (!m_maximized)
- set_maximized();
-}
-
-void QWaylandXdgSurface::setFullscreen()
-{
- if (!m_fullscreen)
- set_fullscreen(nullptr);
-}
-
-void QWaylandXdgSurface::setNormal()
-{
- if (m_fullscreen || m_maximized || m_minimized) {
- if (m_maximized) {
- unset_maximized();
- }
- if (m_fullscreen) {
- unset_fullscreen();
- }
-
- m_fullscreen = m_maximized = m_minimized = false;
- }
-}
-
-void QWaylandXdgSurface::setMinimized()
-{
- m_minimized = true;
- set_minimized();
-}
-
-void QWaylandXdgSurface::updateTransientParent(QWaylandWindow *parent)
-{
- if (!parent)
- return;
- auto parentXdgSurface = qobject_cast<QWaylandXdgSurface *>(parent->shellSurface());
- Q_ASSERT(parentXdgSurface);
- set_parent(parentXdgSurface->object());
-}
-
-void QWaylandXdgSurface::setTitle(const QString & title)
-{
- return QtWayland::xdg_surface::set_title(title);
-}
-
-void QWaylandXdgSurface::setAppId(const QString & appId)
-{
- return QtWayland::xdg_surface::set_app_id(appId);
-}
-
-void QWaylandXdgSurface::raise()
-{
- if (m_extendedWindow)
- m_extendedWindow->raise();
-}
-
-void QWaylandXdgSurface::lower()
-{
- if (m_extendedWindow)
- m_extendedWindow->lower();
-}
-
-void QWaylandXdgSurface::setContentOrientationMask(Qt::ScreenOrientations orientation)
-{
- if (m_extendedWindow)
- m_extendedWindow->setContentOrientationMask(orientation);
-}
-
-void QWaylandXdgSurface::setWindowFlags(Qt::WindowFlags flags)
-{
- if (m_extendedWindow)
- m_extendedWindow->setWindowFlags(flags);
-}
-
-void QWaylandXdgSurface::sendProperty(const QString &name, const QVariant &value)
-{
- if (m_extendedWindow)
- m_extendedWindow->updateGenericProperty(name, value);
-}
-
-void QWaylandXdgSurface::setType(Qt::WindowType type, QWaylandWindow *transientParent)
-{
- Q_UNUSED(type)
- if (transientParent)
- updateTransientParent(transientParent);
-}
-
-void QWaylandXdgSurface::xdg_surface_configure(int32_t width, int32_t height, struct wl_array *states,uint32_t serial)
-{
- uint32_t *state = reinterpret_cast<uint32_t*>(states->data);
- size_t numStates = states->size / sizeof(uint32_t);
- bool aboutToMaximize = false;
- bool aboutToFullScreen = false;
- bool aboutToActivate = false;
-
- for (size_t i = 0; i < numStates; i++) {
- switch (state[i]) {
- case XDG_SURFACE_STATE_MAXIMIZED:
- aboutToMaximize = ((width > 0) && (height > 0));
- break;
- case XDG_SURFACE_STATE_FULLSCREEN:
- aboutToFullScreen = true;
- break;
- case XDG_SURFACE_STATE_RESIZING:
- m_normalSize = QSize(width, height);
- break;
- case XDG_SURFACE_STATE_ACTIVATED:
- aboutToActivate = true;
- break;
- default:
- break;
- }
- }
-
- if (!m_active && aboutToActivate) {
- m_active = true;
- window()->display()->handleWindowActivated(m_window);
- } else if (m_active && !aboutToActivate) {
- m_active = false;
- window()->display()->handleWindowDeactivated(m_window);
- }
-
- if (!m_fullscreen && aboutToFullScreen) {
- if (!m_maximized)
- m_normalSize = m_window->window()->frameGeometry().size();
- m_fullscreen = true;
- m_window->window()->showFullScreen();
- } else if (m_fullscreen && !aboutToFullScreen) {
- m_fullscreen = false;
- if ( m_maximized ) {
- m_window->window()->showMaximized();
- } else {
- m_window->window()->showNormal();
- }
- } else if (!m_maximized && aboutToMaximize) {
- if (!m_fullscreen)
- m_normalSize = m_window->window()->frameGeometry().size();
- m_maximized = true;
- m_window->window()->showMaximized();
- } else if (m_maximized && !aboutToMaximize) {
- m_maximized = false;
- m_window->window()->showNormal();
- }
-
- if (width <= 0 || height <= 0) {
- if (!m_normalSize.isEmpty())
- m_window->configure(0, m_normalSize.width(), m_normalSize.height());
- } else {
- m_window->configure(0, width, height);
- }
-
- ack_configure(serial);
-}
-
-void QWaylandXdgSurface::xdg_surface_close()
-{
-}
-
-}
-
-QT_END_NAMESPACE
diff --git a/src/client/shellintegration/qwaylandshellintegration_p.h b/src/client/shellintegration/qwaylandshellintegration_p.h
index 7f3a2cefc..ccad00481 100644
--- a/src/client/shellintegration/qwaylandshellintegration_p.h
+++ b/src/client/shellintegration/qwaylandshellintegration_p.h
@@ -79,6 +79,11 @@ public:
if (oldFocus)
m_display->handleWindowDeactivated(oldFocus);
}
+ virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) {
+ Q_UNUSED(resource);
+ Q_UNUSED(window);
+ return nullptr;
+ }
protected:
QWaylandDisplay *m_display = nullptr;
diff --git a/src/client/shellintegration/qwaylandshellintegrationfactory.cpp b/src/client/shellintegration/qwaylandshellintegrationfactory.cpp
index c5a505bbe..48fda14d4 100644
--- a/src/client/shellintegration/qwaylandshellintegrationfactory.cpp
+++ b/src/client/shellintegration/qwaylandshellintegrationfactory.cpp
@@ -78,19 +78,24 @@ QStringList QWaylandShellIntegrationFactory::keys(const QString &pluginPath)
#endif
}
-QWaylandShellIntegration *QWaylandShellIntegrationFactory::create(const QString &name, const QStringList &args, const QString &pluginPath)
+QWaylandShellIntegration *QWaylandShellIntegrationFactory::create(const QString &name, QWaylandDisplay *display, const QStringList &args, const QString &pluginPath)
{
#if QT_CONFIG(library)
+ QScopedPointer<QWaylandShellIntegration> integration;
+
// Try loading the plugin from platformPluginPath first:
if (!pluginPath.isEmpty()) {
QCoreApplication::addLibraryPath(pluginPath);
- if (QWaylandShellIntegration *ret = qLoadPlugin<QWaylandShellIntegration, QWaylandShellIntegrationPlugin>(directLoader(), name, args))
- return ret;
+ integration.reset(qLoadPlugin<QWaylandShellIntegration, QWaylandShellIntegrationPlugin>(directLoader(), name, args));
}
- if (QWaylandShellIntegration *ret = qLoadPlugin<QWaylandShellIntegration, QWaylandShellIntegrationPlugin>(loader(), name, args))
- return ret;
+ if (!integration)
+ integration.reset(qLoadPlugin<QWaylandShellIntegration, QWaylandShellIntegrationPlugin>(loader(), name, args));
#endif
- return nullptr;
+
+ if (integration && !integration->initialize(display))
+ return nullptr;
+
+ return integration.take();
}
}
diff --git a/src/client/shellintegration/qwaylandshellintegrationfactory_p.h b/src/client/shellintegration/qwaylandshellintegrationfactory_p.h
index 3edb0a89d..515a18e1f 100644
--- a/src/client/shellintegration/qwaylandshellintegrationfactory_p.h
+++ b/src/client/shellintegration/qwaylandshellintegrationfactory_p.h
@@ -51,7 +51,10 @@
// We mean it.
//
+#include <QtWaylandClient/private/qwaylanddisplay_p.h>
+
#include <QtWaylandClient/qtwaylandclientglobal.h>
+
#include <QtCore/QStringList>
QT_BEGIN_NAMESPACE
@@ -64,7 +67,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandShellIntegrationFactory
{
public:
static QStringList keys(const QString &pluginPath = QString());
- static QWaylandShellIntegration *create(const QString &name, const QStringList &args, const QString &pluginPath = QString());
+ static QWaylandShellIntegration *create(const QString &name, QWaylandDisplay *display, const QStringList &args = QStringList(), const QString &pluginPath = QString());
};
}
diff --git a/src/compositor/compositor_api/qwaylandkeyboard.cpp b/src/compositor/compositor_api/qwaylandkeyboard.cpp
index 7ab8bff9e..c172bca85 100644
--- a/src/compositor/compositor_api/qwaylandkeyboard.cpp
+++ b/src/compositor/compositor_api/qwaylandkeyboard.cpp
@@ -54,6 +54,7 @@
#if QT_CONFIG(xkbcommon_evdev)
#include <sys/mman.h>
#include <sys/types.h>
+#include <qwaylandxkb_p.h>
#endif
QT_BEGIN_NAMESPACE
@@ -196,6 +197,32 @@ void QWaylandKeyboardPrivate::modifiers(uint32_t serial, uint32_t mods_depressed
}
}
+#if QT_CONFIG(xkbcommon_evdev)
+void QWaylandKeyboardPrivate::maybeUpdateXkbScanCodeTable()
+{
+ if (!scanCodesByQtKey.isEmpty() || !xkbState())
+ return;
+
+ if (xkb_keymap *keymap = xkb_state_get_keymap(xkb_state)) {
+ xkb_keymap_key_for_each(keymap, [](xkb_keymap *keymap, xkb_keycode_t keycode, void *d){
+ auto *scanCodesByQtKey = static_cast<QMap<ScanCodeKey, uint>*>(d);
+ uint numLayouts = xkb_keymap_num_layouts_for_key(keymap, keycode);
+ for (uint layout = 0; layout < numLayouts; ++layout) {
+ const xkb_keysym_t *syms = nullptr;
+ xkb_keymap_key_get_syms_by_level(keymap, keycode, layout, 0, &syms);
+ if (!syms)
+ continue;
+
+ Qt::KeyboardModifiers mods = {};
+ int qtKey = QWaylandXkb::keysymToQtKey(syms[0], mods).first;
+ if (qtKey != 0)
+ scanCodesByQtKey->insert({layout, qtKey}, keycode);
+ }
+ }, &scanCodesByQtKey);
+ }
+}
+#endif
+
void QWaylandKeyboardPrivate::updateModifierState(uint code, uint32_t state)
{
#if QT_CONFIG(xkbcommon_evdev)
@@ -355,6 +382,7 @@ void QWaylandKeyboardPrivate::createXKBKeymap()
struct xkb_keymap *xkbKeymap = xkb_keymap_new_from_names(xkb_context, &rule_names, static_cast<xkb_keymap_compile_flags>(0));
if (xkbKeymap) {
+ scanCodesByQtKey.clear();
createXKBState(xkbKeymap);
xkb_keymap_unref(xkbKeymap);
} else {
@@ -561,4 +589,17 @@ void QWaylandKeyboard::addClient(QWaylandClient *client, uint32_t id, uint32_t v
d->add(client->client(), id, qMin<uint32_t>(QtWaylandServer::wl_keyboard::interfaceVersion(), version));
}
+uint QWaylandKeyboard::toScanCode(int qtKey) const
+{
+ uint scanCode = 0;
+#if QT_CONFIG(xkbcommon_evdev)
+ Q_D(const QWaylandKeyboard);
+ const_cast<QWaylandKeyboardPrivate *>(d)->maybeUpdateXkbScanCodeTable();
+ scanCode = d->scanCodesByQtKey.value({d->group, qtKey}, 0);
+#else
+ Q_UNUSED(qtKey);
+#endif
+ return scanCode;
+}
+
QT_END_NAMESPACE
diff --git a/src/compositor/compositor_api/qwaylandkeyboard.h b/src/compositor/compositor_api/qwaylandkeyboard.h
index 580f0c4ed..e5d5e086e 100644
--- a/src/compositor/compositor_api/qwaylandkeyboard.h
+++ b/src/compositor/compositor_api/qwaylandkeyboard.h
@@ -82,6 +82,8 @@ public:
virtual void addClient(QWaylandClient *client, uint32_t id, uint32_t version);
+ uint toScanCode(int qtKey) const;
+
Q_SIGNALS:
void focusChanged(QWaylandSurface *surface);
void repeatRateChanged(quint32 repeatRate);
diff --git a/src/compositor/compositor_api/qwaylandkeyboard_p.h b/src/compositor/compositor_api/qwaylandkeyboard_p.h
index 6db312cfb..cd1f27956 100644
--- a/src/compositor/compositor_api/qwaylandkeyboard_p.h
+++ b/src/compositor/compositor_api/qwaylandkeyboard_p.h
@@ -89,6 +89,7 @@ public:
#if QT_CONFIG(xkbcommon_evdev)
struct xkb_state *xkbState() const { return xkb_state; }
uint32_t xkbModsMask() const { return modsDepressed | modsLatched | modsLocked; }
+ void maybeUpdateXkbScanCodeTable();
#endif
void keyEvent(uint code, uint32_t state);
@@ -131,6 +132,8 @@ private:
size_t keymap_size;
int keymap_fd = -1;
char *keymap_area = nullptr;
+ using ScanCodeKey = std::pair<uint,int>; // group/layout and QtKey
+ QMap<ScanCodeKey, uint> scanCodesByQtKey;
struct xkb_context *xkb_context = nullptr;
struct xkb_state *xkb_state = nullptr;
#endif
diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp
index d4cc94e4b..f3e0ffa78 100644
--- a/src/compositor/compositor_api/qwaylandquickitem.cpp
+++ b/src/compositor/compositor_api/qwaylandquickitem.cpp
@@ -1315,6 +1315,19 @@ void QWaylandQuickItem::raise()
stackAfter(top);
}
+void QWaylandQuickItem::sendMouseMoveEvent(const QPointF &position, QWaylandSeat *seat)
+{
+ if (seat == nullptr)
+ seat = compositor()->defaultSeat();
+
+ if (!seat) {
+ qWarning() << "No seat, can't send mouse event";
+ return;
+ }
+
+ seat->sendMouseMoveEvent(view(), position);
+}
+
/*!
* \internal
*
diff --git a/src/compositor/compositor_api/qwaylandquickitem.h b/src/compositor/compositor_api/qwaylandquickitem.h
index 047fdeb65..0aa863f5f 100644
--- a/src/compositor/compositor_api/qwaylandquickitem.h
+++ b/src/compositor/compositor_api/qwaylandquickitem.h
@@ -151,6 +151,7 @@ public Q_SLOTS:
void setPaintEnabled(bool paintEnabled);
void raise();
void lower();
+ void sendMouseMoveEvent(const QPointF &position, QWaylandSeat *seat = nullptr);
private Q_SLOTS:
void surfaceMappedChanged();
diff --git a/src/compositor/compositor_api/qwaylandseat.cpp b/src/compositor/compositor_api/qwaylandseat.cpp
index c67e6020d..957f5ea83 100644
--- a/src/compositor/compositor_api/qwaylandseat.cpp
+++ b/src/compositor/compositor_api/qwaylandseat.cpp
@@ -440,10 +440,50 @@ void QWaylandSeat::sendFullKeyEvent(QKeyEvent *event)
return;
if (!d->keyboard.isNull() && !event->isAutoRepeat()) {
+
+ uint scanCode = event->nativeScanCode();
+ if (scanCode == 0)
+ scanCode = d->keyboard->toScanCode(event->key());
+
+ if (scanCode == 0) {
+ qWarning() << "Can't send Wayland key event: Unable to get a valid scan code";
+ return;
+ }
+
if (event->type() == QEvent::KeyPress)
- d->keyboard->sendKeyPressEvent(event->nativeScanCode());
+ d->keyboard->sendKeyPressEvent(scanCode);
else if (event->type() == QEvent::KeyRelease)
- d->keyboard->sendKeyReleaseEvent(event->nativeScanCode());
+ d->keyboard->sendKeyReleaseEvent(scanCode);
+ }
+}
+
+/*!
+ * \qmlmethod void QtWaylandCompositor::WaylandSeat::sendKeyEvent(int qtKey, bool pressed)
+ * \since 5.12
+ *
+ * Sends a key press or release to the keyboard device.
+ */
+
+/*!
+ * Sends a key press or release to the keyboard device.
+ *
+ * \since 5.12
+ */
+void QWaylandSeat::sendKeyEvent(int qtKey, bool pressed)
+{
+ Q_D(QWaylandSeat);
+ if (!keyboardFocus()) {
+ qWarning("Cannot send Wayland key event, no keyboard focus, fix the compositor");
+ return;
+ }
+
+ if (auto scanCode = d->keyboard->toScanCode(qtKey)) {
+ if (pressed)
+ d->keyboard->sendKeyPressEvent(scanCode);
+ else
+ d->keyboard->sendKeyReleaseEvent(scanCode);
+ } else {
+ qWarning() << "Can't send Wayland key event: Unable to get scan code for" << Qt::Key(qtKey);
}
}
diff --git a/src/compositor/compositor_api/qwaylandseat.h b/src/compositor/compositor_api/qwaylandseat.h
index f438b6639..6a4d6e176 100644
--- a/src/compositor/compositor_api/qwaylandseat.h
+++ b/src/compositor/compositor_api/qwaylandseat.h
@@ -97,6 +97,7 @@ public:
void sendKeyReleaseEvent(uint code);
void sendFullKeyEvent(QKeyEvent *event);
+ Q_INVOKABLE void sendKeyEvent(int qtKey, bool pressed);
uint sendTouchPointEvent(QWaylandSurface *surface, int id, const QPointF &point, Qt::TouchPointState state);
Q_INVOKABLE uint sendTouchPointPressed(QWaylandSurface *surface, int id, const QPointF &position);
diff --git a/src/compositor/extensions/extensions.pri b/src/compositor/extensions/extensions.pri
index 68e473e14..77c09aa23 100644
--- a/src/compositor/extensions/extensions.pri
+++ b/src/compositor/extensions/extensions.pri
@@ -3,10 +3,10 @@ CONFIG += generated_privates
WAYLANDSERVERSOURCES += \
../extensions/touch-extension.xml \
- ../extensions/qtkey-extension.xml \
+ ../extensions/qt-key-unstable-v1.xml \
../extensions/qt-windowmanager.xml \
../3rdparty/protocol/text-input-unstable-v2.xml \
- ../3rdparty/protocol/xdg-shell.xml \
+ ../3rdparty/protocol/xdg-shell-unstable-v5.xml \
../3rdparty/protocol/xdg-shell-unstable-v6.xml \
../3rdparty/protocol/ivi-application.xml \
diff --git a/src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp b/src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp
index 6b8845797..84e9c356d 100644
--- a/src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp
+++ b/src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp
@@ -45,6 +45,21 @@
QT_BEGIN_NAMESPACE
+QWaylandQuickShellSurfaceItem *QWaylandQuickShellSurfaceItemPrivate::maybeCreateAutoPopup(QWaylandShellSurface* shellSurface)
+{
+ if (!m_autoCreatePopupItems)
+ return nullptr;
+
+ Q_Q(QWaylandQuickShellSurfaceItem);
+ auto *popupItem = new QWaylandQuickShellSurfaceItem(q);
+ popupItem->setShellSurface(shellSurface);
+ popupItem->setAutoCreatePopupItems(true);
+ QObject::connect(popupItem, &QWaylandQuickShellSurfaceItem::surfaceDestroyed, [popupItem](){
+ popupItem->deleteLater();
+ });
+ return popupItem;
+}
+
/*!
* \qmltype ShellSurfaceItem
* \inherits WaylandQuickItem
@@ -163,6 +178,36 @@ void QWaylandQuickShellSurfaceItem::setMoveItem(QQuickItem *moveItem)
moveItemChanged();
}
+/*!
+ * \qmlproperty bool QtWaylandCompositor::ShellSurfaceItem::autoCreatePopupItems
+ *
+ * This property holds whether ShellSurfaceItems for popups parented to the shell
+ * surface managed by this item should automatically be created.
+ */
+
+/*!
+ * \property QWaylandQuickShellSurfaceItem::autoCreatePopupItems
+ *
+ * This property holds whether QWaylandQuickShellSurfaceItems for popups
+ * parented to the shell surface managed by this item should automatically be created.
+ */
+bool QWaylandQuickShellSurfaceItem::autoCreatePopupItems()
+{
+ Q_D(const QWaylandQuickShellSurfaceItem);
+ return d->m_autoCreatePopupItems;
+}
+
+void QWaylandQuickShellSurfaceItem::setAutoCreatePopupItems(bool enabled)
+{
+ Q_D(QWaylandQuickShellSurfaceItem);
+
+ if (enabled == d->m_autoCreatePopupItems)
+ return;
+
+ d->m_autoCreatePopupItems = enabled;
+ emit autoCreatePopupItemsChanged();
+}
+
void QWaylandQuickShellSurfaceItem::mouseMoveEvent(QMouseEvent *event)
{
Q_D(QWaylandQuickShellSurfaceItem);
diff --git a/src/compositor/extensions/qwaylandquickshellsurfaceitem.h b/src/compositor/extensions/qwaylandquickshellsurfaceitem.h
index e2c823651..d14fa3fce 100644
--- a/src/compositor/extensions/qwaylandquickshellsurfaceitem.h
+++ b/src/compositor/extensions/qwaylandquickshellsurfaceitem.h
@@ -54,6 +54,7 @@ class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandQuickShellSurfaceItem : public QWaylan
Q_DECLARE_PRIVATE(QWaylandQuickShellSurfaceItem)
Q_PROPERTY(QWaylandShellSurface *shellSurface READ shellSurface WRITE setShellSurface NOTIFY shellSurfaceChanged)
Q_PROPERTY(QQuickItem *moveItem READ moveItem WRITE setMoveItem NOTIFY moveItemChanged)
+ Q_PROPERTY(bool autoCreatePopupItems READ autoCreatePopupItems WRITE setAutoCreatePopupItems NOTIFY autoCreatePopupItemsChanged)
public:
QWaylandQuickShellSurfaceItem(QQuickItem *parent = nullptr);
~QWaylandQuickShellSurfaceItem() override;
@@ -64,9 +65,13 @@ public:
QQuickItem *moveItem() const;
void setMoveItem(QQuickItem *moveItem);
+ bool autoCreatePopupItems();
+ void setAutoCreatePopupItems(bool enabled);
+
Q_SIGNALS:
void shellSurfaceChanged();
void moveItemChanged();
+ void autoCreatePopupItemsChanged();
protected:
QWaylandQuickShellSurfaceItem(QWaylandQuickShellSurfaceItemPrivate &dd, QQuickItem *parent);
diff --git a/src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h b/src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h
index abb56221e..7a458381e 100644
--- a/src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h
+++ b/src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h
@@ -40,6 +40,7 @@
#ifndef QWAYLANDQUICKSHELLSURFACEITEM_P_H
#define QWAYLANDQUICKSHELLSURFACEITEM_P_H
+#include <QtWaylandCompositor/QWaylandQuickShellSurfaceItem>
#include <QtWaylandCompositor/private/qwaylandquickitem_p.h>
#include <QtCore/QBasicTimer>
@@ -60,15 +61,20 @@ QT_BEGIN_NAMESPACE
class QWaylandQuickShellIntegration;
class QWaylandShellSurface;
+class QWaylandQuickShellSurfaceItem;
class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandQuickShellSurfaceItemPrivate : public QWaylandQuickItemPrivate
{
+ Q_DECLARE_PUBLIC(QWaylandQuickShellSurfaceItem)
public:
- QWaylandQuickShellSurfaceItemPrivate()
- {}
+ QWaylandQuickShellSurfaceItemPrivate() {}
+ QWaylandQuickShellSurfaceItem *maybeCreateAutoPopup(QWaylandShellSurface* shellSurface);
+ static QWaylandQuickShellSurfaceItemPrivate *get(QWaylandQuickShellSurfaceItem *item) { return item->d_func(); }
+
QWaylandQuickShellIntegration *m_shellIntegration = nullptr;
QWaylandShellSurface *m_shellSurface = nullptr;
QQuickItem *m_moveItem = nullptr;
+ bool m_autoCreatePopupItems = false;
};
class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandQuickShellIntegration : public QObject
diff --git a/src/compositor/extensions/qwaylandxdgshellv5_p.h b/src/compositor/extensions/qwaylandxdgshellv5_p.h
index b0b51698d..032441e8d 100644
--- a/src/compositor/extensions/qwaylandxdgshellv5_p.h
+++ b/src/compositor/extensions/qwaylandxdgshellv5_p.h
@@ -41,7 +41,7 @@
#define QWAYLANDXDGSHELLV5_P_H
#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h>
-#include <QtWaylandCompositor/private/qwayland-server-xdg-shell.h>
+#include <QtWaylandCompositor/private/qwayland-server-xdg-shell-unstable-v5.h>
#include <QtWaylandCompositor/QWaylandXdgShellV5>
diff --git a/src/compositor/extensions/qwaylandxdgshellv5integration.cpp b/src/compositor/extensions/qwaylandxdgshellv5integration.cpp
index a349a25aa..ea04a33d2 100644
--- a/src/compositor/extensions/qwaylandxdgshellv5integration.cpp
+++ b/src/compositor/extensions/qwaylandxdgshellv5integration.cpp
@@ -50,6 +50,12 @@ QT_BEGIN_NAMESPACE
namespace QtWayland {
+static void handlePopupCreated(QWaylandQuickShellSurfaceItem *parentItem, QWaylandXdgPopupV5 *popup)
+{
+ if (parentItem->surface() == popup->parentSurface())
+ QWaylandQuickShellSurfaceItemPrivate::get(parentItem)->maybeCreateAutoPopup(popup);
+}
+
XdgShellV5Integration::XdgShellV5Integration(QWaylandQuickShellSurfaceItem *item)
: QWaylandQuickShellIntegration(item)
, m_item(item)
@@ -66,6 +72,9 @@ XdgShellV5Integration::XdgShellV5Integration(QWaylandQuickShellSurfaceItem *item
connect(m_xdgSurface, &QWaylandXdgSurfaceV5::maximizedChanged, this, &XdgShellV5Integration::handleMaximizedChanged);
connect(m_xdgSurface, &QWaylandXdgSurfaceV5::activatedChanged, this, &XdgShellV5Integration::handleActivatedChanged);
connect(m_xdgSurface->surface(), &QWaylandSurface::sizeChanged, this, &XdgShellV5Integration::handleSurfaceSizeChanged);
+ connect(m_xdgSurface->shell(), &QWaylandXdgShellV5::xdgPopupCreated, this, [item](QWaylandXdgPopupV5 *popup){
+ handlePopupCreated(item, popup);
+ });
}
XdgShellV5Integration::~XdgShellV5Integration()
@@ -213,6 +222,9 @@ XdgPopupV5Integration::XdgPopupV5Integration(QWaylandQuickShellSurfaceItem *item
QWaylandQuickShellEventFilter::startFilter(client, [shell]() { shell->closeAllPopups(); });
connect(m_xdgPopup, &QWaylandXdgPopupV5::destroyed, this, &XdgPopupV5Integration::handlePopupDestroyed);
+ connect(m_xdgPopup->shell(), &QWaylandXdgShellV5::xdgPopupCreated, this, [item](QWaylandXdgPopupV5 *popup) {
+ handlePopupCreated(item, popup);
+ });
}
XdgPopupV5Integration::~XdgPopupV5Integration()
diff --git a/src/compositor/extensions/qwaylandxdgshellv6integration.cpp b/src/compositor/extensions/qwaylandxdgshellv6integration.cpp
index 17ee10db7..68230937f 100644
--- a/src/compositor/extensions/qwaylandxdgshellv6integration.cpp
+++ b/src/compositor/extensions/qwaylandxdgshellv6integration.cpp
@@ -44,6 +44,12 @@ QT_BEGIN_NAMESPACE
namespace QtWayland {
+static void handlePopupCreated(QWaylandQuickShellSurfaceItem *parentItem, QWaylandXdgPopupV6 *popup)
+{
+ if (parentItem->shellSurface() == popup->parentXdgSurface())
+ QWaylandQuickShellSurfaceItemPrivate::get(parentItem)->maybeCreateAutoPopup(popup->xdgSurface());
+}
+
XdgToplevelV6Integration::XdgToplevelV6Integration(QWaylandQuickShellSurfaceItem *item)
: QWaylandQuickShellIntegration(item)
, m_item(item)
@@ -54,12 +60,16 @@ XdgToplevelV6Integration::XdgToplevelV6Integration(QWaylandQuickShellSurfaceItem
Q_ASSERT(m_toplevel);
m_item->setSurface(m_xdgSurface->surface());
+
connect(m_toplevel, &QWaylandXdgToplevelV6::startMove, this, &XdgToplevelV6Integration::handleStartMove);
connect(m_toplevel, &QWaylandXdgToplevelV6::startResize, this, &XdgToplevelV6Integration::handleStartResize);
connect(m_toplevel, &QWaylandXdgToplevelV6::setMaximized, this, &XdgToplevelV6Integration::handleSetMaximized);
connect(m_toplevel, &QWaylandXdgToplevelV6::unsetMaximized, this, &XdgToplevelV6Integration::handleUnsetMaximized);
connect(m_toplevel, &QWaylandXdgToplevelV6::maximizedChanged, this, &XdgToplevelV6Integration::handleMaximizedChanged);
connect(m_toplevel, &QWaylandXdgToplevelV6::activatedChanged, this, &XdgToplevelV6Integration::handleActivatedChanged);
+ connect(m_xdgSurface->shell(), &QWaylandXdgShellV6::popupCreated, this, [item](QWaylandXdgPopupV6 *popup, QWaylandXdgSurfaceV6 *){
+ handlePopupCreated(item, popup);
+ });
connect(m_xdgSurface->surface(), &QWaylandSurface::sizeChanged, this, &XdgToplevelV6Integration::handleSurfaceSizeChanged);
}
@@ -181,6 +191,9 @@ XdgPopupV6Integration::XdgPopupV6Integration(QWaylandQuickShellSurfaceItem *item
handleGeometryChanged();
connect(m_popup, &QWaylandXdgPopupV6::configuredGeometryChanged, this, &XdgPopupV6Integration::handleGeometryChanged);
+ connect(m_xdgSurface->shell(), &QWaylandXdgShellV6::popupCreated, this, [item](QWaylandXdgPopupV6 *popup, QWaylandXdgSurfaceV6 *){
+ handlePopupCreated(item, popup);
+ });
}
void XdgPopupV6Integration::handleGeometryChanged()
diff --git a/src/compositor/extensions/qwlqtkey.cpp b/src/compositor/extensions/qwlqtkey.cpp
index 73d06ae6b..94a2b5a77 100644
--- a/src/compositor/extensions/qwlqtkey.cpp
+++ b/src/compositor/extensions/qwlqtkey.cpp
@@ -48,7 +48,7 @@ namespace QtWayland {
QtKeyExtensionGlobal::QtKeyExtensionGlobal(QWaylandCompositor *compositor)
: QWaylandCompositorExtensionTemplate(compositor)
- , QtWaylandServer::qt_key_extension(compositor->display(), 2)
+ , QtWaylandServer::zqt_key_v1(compositor->display(), 1)
, m_compositor(compositor)
{
}
@@ -60,15 +60,15 @@ bool QtKeyExtensionGlobal::postQtKeyEvent(QKeyEvent *event, QWaylandSurface *sur
Resource *target = surface ? resourceMap().value(surface->waylandClient()) : 0;
if (target) {
- send_qtkey(target->handle,
- surface ? surface->resource() : nullptr,
- time, event->type(), event->key(), event->modifiers(),
- event->nativeScanCode(),
- event->nativeVirtualKey(),
- event->nativeModifiers(),
- event->text(),
- event->isAutoRepeat(),
- event->count());
+ send_key(target->handle,
+ surface ? surface->resource() : nullptr,
+ time, event->type(), event->key(), event->modifiers(),
+ event->nativeScanCode(),
+ event->nativeVirtualKey(),
+ event->nativeModifiers(),
+ event->text(),
+ event->isAutoRepeat(),
+ event->count());
return true;
}
diff --git a/src/compositor/extensions/qwlqtkey_p.h b/src/compositor/extensions/qwlqtkey_p.h
index d3f573757..4944829ef 100644
--- a/src/compositor/extensions/qwlqtkey_p.h
+++ b/src/compositor/extensions/qwlqtkey_p.h
@@ -53,7 +53,7 @@
#include <QtWaylandCompositor/QWaylandCompositorExtensionTemplate>
#include <QtWaylandCompositor/QWaylandCompositor>
-#include <QtWaylandCompositor/private/qwayland-server-qtkey-extension.h>
+#include <QtWaylandCompositor/private/qwayland-server-qt-key-unstable-v1.h>
#include <wayland-util.h>
@@ -64,7 +64,7 @@ class QKeyEvent;
namespace QtWayland {
-class QtKeyExtensionGlobal : public QWaylandCompositorExtensionTemplate<QtKeyExtensionGlobal>, public QtWaylandServer::qt_key_extension
+class QtKeyExtensionGlobal : public QWaylandCompositorExtensionTemplate<QtKeyExtensionGlobal>, public QtWaylandServer::zqt_key_v1
{
Q_OBJECT
public:
diff --git a/src/extensions/README.md b/src/extensions/README.md
new file mode 100644
index 000000000..f75e0f236
--- /dev/null
+++ b/src/extensions/README.md
@@ -0,0 +1,18 @@
+# Internal Qt protocol extensions
+
+The protocol extensions in this folder are considered implementation details of
+Qt. I.e. they may removed, renamed or changed without warning.
+
+## Suffixed protocols
+
+For protocols that have a version suffix, however, we will strive to not break
+backwards compatibility without bumping the suffix (renaming the protocol).
+E.g.: If your client sees a `zqt_key_v1` global, it can safely bind to it:
+the key event will always take the same number of arguments, regardless of
+compositor version.
+
+This is important also within a Qt-only scope if there are multiple versions of
+Qt on the system. Consider for instance an application statically linked to Qt
+(such as Qt Creator) running against a Qt compositor installed by the distro).
+In such cases we don't want the compositor and client to disagree on the
+protocol definition.
diff --git a/src/extensions/qtkey-extension.xml b/src/extensions/qt-key-unstable-v1.xml
index 34cf24797..0f8d8284c 100644
--- a/src/extensions/qtkey-extension.xml
+++ b/src/extensions/qt-key-unstable-v1.xml
@@ -1,7 +1,7 @@
-<protocol name="qtkey_extension">
+<protocol name="qt_key_unstable_v1">
<copyright>
- Copyright (C) 2015 The Qt Company Ltd.
+ Copyright (C) 2018 The Qt Company Ltd.
Contact: http://www.qt.io/licensing/
This file is part of the plugins of the Qt Toolkit.
@@ -38,26 +38,36 @@
$QT_END_LICENSE$
</copyright>
- <interface name="qt_key_extension" version="2">
- <event name="qtkey">
- <description summary="qtkey event">
- Serialized QKeyEvent
- </description>
-
- <arg name="surface" type="object" interface="wl_surface"/>
- <arg name="time" type="uint"/>
- <arg name="type" type="uint"/>
- <arg name="key" type="uint"/>
- <arg name="modifiers" type="uint"/>
- <arg name="nativeScanCode" type="uint"/>
- <arg name="nativeVirtualKey" type="uint"/>
- <arg name="nativeModifiers" type="uint"/>
- <arg name="text" type="string"/>
- <arg name="autorepeat" type="uint"/>
- <arg name="count" type="uint"/>
- </event>
+ <interface name="zqt_key_v1" version="1">
+ <description summary="send serialized QKeyEvents">
+ This protocol is independent of the Wayland seat concept. Its
+ intention is to let a QKeyEvent be transferred from a Qt compositor
+ to a Qt client without losing or adding false information by going
+ through wl_seat and wl_keyboard.
- <request name="dummy">
- </request>
+ Note: This protocol is considered private to Qt. We will do our
+ best to bump version numbers when we make backwards compatible
+ changes, bump the protocol name and interface suffixes when we make
+ backwards incompatible changes, but we provide no guarantees. We
+ may also remove the protocol without warning. Implement this at
+ your own risk.
+ </description>
+ <event name="key">
+ <description summary="send key event">
+ The key event notifies the client that a QKeyEvent has occurred on
+ the server side.
+ </description>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ <arg name="time" type="uint"/>
+ <arg name="type" type="uint"/>
+ <arg name="key" type="uint"/>
+ <arg name="modifiers" type="uint"/>
+ <arg name="nativeScanCode" type="uint"/>
+ <arg name="nativeVirtualKey" type="uint"/>
+ <arg name="nativeModifiers" type="uint"/>
+ <arg name="text" type="string"/>
+ <arg name="autorepeat" type="uint"/>
+ <arg name="count" type="uint"/>
+ </event>
</interface>
</protocol>
diff --git a/src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglintegration.cpp b/src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglintegration.cpp
index 4478b9fdf..cd0f285cd 100644
--- a/src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglintegration.cpp
+++ b/src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglintegration.cpp
@@ -124,6 +124,33 @@ EGLDisplay QWaylandBrcmEglIntegration::eglDisplay() const
return m_eglDisplay;
}
+void *QWaylandBrcmEglIntegration::nativeResource(NativeResource resource)
+{
+ switch (resource) {
+ case EglDisplay:
+ return m_eglDisplay;
+ default:
+ break;
+ }
+ return nullptr;
+}
+
+void *QWaylandBrcmEglIntegration::nativeResourceForContext(NativeResource resource, QPlatformOpenGLContext *context)
+{
+ Q_ASSERT(context);
+ switch (resource) {
+ case EglConfig:
+ return static_cast<QWaylandBrcmGLContext *>(context)->eglConfig();
+ case EglContext:
+ return static_cast<QWaylandBrcmGLContext *>(context)->eglContext();
+ case EglDisplay:
+ return m_eglDisplay;
+ default:
+ break;
+ }
+ return nullptr;
+}
+
}
QT_END_NAMESPACE
diff --git a/src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglintegration.h b/src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglintegration.h
index 651400d87..5e8a3bf46 100644
--- a/src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglintegration.h
+++ b/src/hardwareintegration/client/brcm-egl/qwaylandbrcmeglintegration.h
@@ -82,6 +82,9 @@ public:
PFNEGLCREATEGLOBALIMAGEBRCMPROC eglCreateGlobalImageBRCM;
PFNEGLDESTROYGLOBALIMAGEBRCMPROC eglDestroyGlobalImageBRCM;
+ void *nativeResource(NativeResource resource) override;
+ void *nativeResourceForContext(NativeResource resource, QPlatformOpenGLContext *context) override;
+
private:
static void wlDisplayHandleGlobal(void *data, struct wl_registry *registry, uint32_t id, const QString &interface, uint32_t version);
diff --git a/src/plugins/decorations/bradient/main.cpp b/src/plugins/decorations/bradient/main.cpp
index 9a7e91e6f..d3627d2f7 100644
--- a/src/plugins/decorations/bradient/main.cpp
+++ b/src/plugins/decorations/bradient/main.cpp
@@ -270,8 +270,7 @@ void QWaylandBradientDecoration::paint(QPaintDevice *device)
p.drawPixmap(closeButtonRect(), closePixmap, closePixmap.rect());
// Maximize button
- QPixmap maximizePixmap(waylandWindow()->isMaximized()
- ? qt_normalizeup_xpm : qt_maximize_xpm);
+ QPixmap maximizePixmap((window()->windowStates() & Qt::WindowMaximized) ? qt_normalizeup_xpm : qt_maximize_xpm);
p.drawPixmap(maximizeButtonRect(), maximizePixmap, maximizePixmap.rect());
// Minimize button
@@ -356,7 +355,7 @@ bool QWaylandBradientDecoration::handleMouse(QWaylandInputDevice *inputDevice, c
QWindowSystemInterface::handleCloseEvent(window());
} else if (maximizeButtonRect().contains(local)) {
if (clickButton(b, Maximize))
- window()->setWindowState(waylandWindow()->isMaximized() ? Qt::WindowNoState : Qt::WindowMaximized);
+ window()->setWindowStates(window()->windowStates() ^ Qt::WindowMaximized);
} else if (minimizeButtonRect().contains(local)) {
if (clickButton(b, Minimize))
window()->setWindowState(Qt::WindowMinimized);
@@ -390,7 +389,7 @@ bool QWaylandBradientDecoration::handleTouch(QWaylandInputDevice *inputDevice, c
if (closeButtonRect().contains(local))
QWindowSystemInterface::handleCloseEvent(window());
else if (maximizeButtonRect().contains(local))
- window()->setWindowState(waylandWindow()->isMaximized() ? Qt::WindowNoState : Qt::WindowMaximized);
+ window()->setWindowStates(window()->windowStates() ^ Qt::WindowMaximized);
else if (minimizeButtonRect().contains(local))
window()->setWindowState(Qt::WindowMinimized);
else if (local.y() <= margins().top())
diff --git a/src/plugins/shellintegration/ivi-shell/qwaylandivisurface.cpp b/src/plugins/shellintegration/ivi-shell/qwaylandivisurface.cpp
index ec529b124..871709cdf 100644
--- a/src/plugins/shellintegration/ivi-shell/qwaylandivisurface.cpp
+++ b/src/plugins/shellintegration/ivi-shell/qwaylandivisurface.cpp
@@ -82,6 +82,11 @@ void QWaylandIviSurface::setType(Qt::WindowType type, QWaylandWindow *transientP
Q_UNUSED(transientParent)
}
+void QWaylandIviSurface::applyConfigure()
+{
+ m_window->resizeFromApplyConfigure(m_pendingSize);
+}
+
void QWaylandIviSurface::createExtendedSurface(QWaylandWindow *window)
{
if (window->display()->windowExtension())
@@ -90,7 +95,8 @@ void QWaylandIviSurface::createExtendedSurface(QWaylandWindow *window)
void QWaylandIviSurface::ivi_surface_configure(int32_t width, int32_t height)
{
- this->m_window->configure(0, width, height);
+ m_pendingSize = {width, height};
+ m_window->applyConfigureWhenPossible();
}
void QWaylandIviSurface::ivi_controller_surface_visibility(int32_t visibility)
diff --git a/src/plugins/shellintegration/ivi-shell/qwaylandivisurface_p.h b/src/plugins/shellintegration/ivi-shell/qwaylandivisurface_p.h
index ff943060b..6ec28e758 100644
--- a/src/plugins/shellintegration/ivi-shell/qwaylandivisurface_p.h
+++ b/src/plugins/shellintegration/ivi-shell/qwaylandivisurface_p.h
@@ -63,6 +63,7 @@ public:
~QWaylandIviSurface() override;
void setType(Qt::WindowType type, QWaylandWindow *transientParent) override;
+ void applyConfigure() override;
private:
void createExtendedSurface(QWaylandWindow *window);
@@ -71,6 +72,7 @@ private:
QWaylandWindow *m_window = nullptr;
QWaylandExtendedSurface *m_extendedWindow = nullptr;
+ QSize m_pendingSize = {0, 0};
};
}
diff --git a/src/plugins/shellintegration/shellintegration.pro b/src/plugins/shellintegration/shellintegration.pro
index 9867d2b40..12a900db2 100644
--- a/src/plugins/shellintegration/shellintegration.pro
+++ b/src/plugins/shellintegration/shellintegration.pro
@@ -1,3 +1,7 @@
TEMPLATE = subdirs
-SUBDIRS += ivi-shell
+SUBDIRS += \
+ ivi-shell \
+ xdg-shell-v5 \
+ wl-shell \
+
diff --git a/src/plugins/shellintegration/wl-shell/main.cpp b/src/plugins/shellintegration/wl-shell/main.cpp
new file mode 100644
index 000000000..9b033b5f3
--- /dev/null
+++ b/src/plugins/shellintegration/wl-shell/main.cpp
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2017 ITAGE Corporation, author: <yusuke.binsaki@itage.co.jp>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwaylandwlshellintegration_p.h"
+
+#include <QtWaylandClient/private/qwaylandshellintegrationplugin_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+class QWaylandWlShellIntegrationPlugin : public QWaylandShellIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QWaylandShellIntegrationFactoryInterface_iid FILE "wl-shell.json")
+
+public:
+ QWaylandShellIntegration *create(const QString &key, const QStringList &paramList) override;
+};
+
+QWaylandShellIntegration *QWaylandWlShellIntegrationPlugin::create(const QString &key, const QStringList &paramList)
+{
+ Q_UNUSED(key);
+ Q_UNUSED(paramList);
+ return new QWaylandWlShellIntegration();
+}
+
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/client/qwaylandwlshellintegration.cpp b/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration.cpp
index 81c46be29..be156dad2 100644
--- a/src/client/qwaylandwlshellintegration.cpp
+++ b/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration.cpp
@@ -38,23 +38,16 @@
****************************************************************************/
#include "qwaylandwlshellintegration_p.h"
+#include "qwaylandwlshellsurface_p.h"
#include <QtWaylandClient/private/qwaylandwindow_p.h>
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
-#include <QtWaylandClient/private/qwaylandwlshellsurface_p.h>
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
-QWaylandWlShellIntegration *QWaylandWlShellIntegration::create(QWaylandDisplay *display)
-{
- if (display->hasRegistryGlobal(QLatin1String("wl_shell")))
- return new QWaylandWlShellIntegration(display);
- return nullptr;
-}
-
-QWaylandWlShellIntegration::QWaylandWlShellIntegration(QWaylandDisplay *display)
+bool QWaylandWlShellIntegration::initialize(QWaylandDisplay *display)
{
Q_FOREACH (QWaylandDisplay::RegistryGlobal global, display->globals()) {
if (global.interface == QLatin1String("wl_shell")) {
@@ -62,19 +55,33 @@ QWaylandWlShellIntegration::QWaylandWlShellIntegration(QWaylandDisplay *display)
break;
}
}
-}
-bool QWaylandWlShellIntegration::initialize(QWaylandDisplay *display)
-{
- QWaylandShellIntegration::initialize(display);
- return m_wlShell != nullptr;
-};
+ if (!m_wlShell) {
+ qCDebug(lcQpaWayland) << "Couldn't find global wl_shell";
+ return false;
+ }
+
+ return QWaylandShellIntegration::initialize(display);
+}
QWaylandShellSurface *QWaylandWlShellIntegration::createShellSurface(QWaylandWindow *window)
{
return new QWaylandWlShellSurface(m_wlShell->get_shell_surface(window->object()), window);
}
+void *QWaylandWlShellIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
+{
+ QByteArray lowerCaseResource = resource.toLower();
+ if (lowerCaseResource == "wl_shell_surface") {
+ if (auto waylandWindow = static_cast<QWaylandWindow *>(window->handle())) {
+ if (auto shellSurface = qobject_cast<QWaylandWlShellSurface *>(waylandWindow->shellSurface())) {
+ return shellSurface->object();
+ }
+ }
+ }
+ return nullptr;
}
+} // namespace QtWaylandClient
+
QT_END_NAMESPACE
diff --git a/src/client/qwaylandwlshellintegration_p.h b/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration_p.h
index 7a6b53524..80a7507d4 100644
--- a/src/client/qwaylandwlshellintegration_p.h
+++ b/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration_p.h
@@ -63,13 +63,12 @@ namespace QtWaylandClient {
class Q_WAYLAND_CLIENT_EXPORT QWaylandWlShellIntegration : public QWaylandShellIntegration
{
public:
- static QWaylandWlShellIntegration *create(QWaylandDisplay* display);
+ QWaylandWlShellIntegration() {}
bool initialize(QWaylandDisplay *) override;
QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
+ void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) override;
private:
- QWaylandWlShellIntegration(QWaylandDisplay* display);
-
QtWayland::wl_shell *m_wlShell = nullptr;
};
diff --git a/src/client/qwaylandwlshellsurface.cpp b/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp
index 098eddcbc..9f2bcc00c 100644
--- a/src/client/qwaylandwlshellsurface.cpp
+++ b/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface.cpp
@@ -39,12 +39,12 @@
#include "qwaylandwlshellsurface_p.h"
-#include "qwaylanddisplay_p.h"
-#include "qwaylandwindow_p.h"
-#include "qwaylandinputdevice_p.h"
-#include "qwaylandabstractdecoration_p.h"
-#include "qwaylandscreen_p.h"
-#include "qwaylandextendedsurface_p.h"
+#include <QtWaylandClient/private/qwaylanddisplay_p.h>
+#include <QtWaylandClient/private/qwaylandwindow_p.h>
+#include <QtWaylandClient/private/qwaylandinputdevice_p.h>
+#include <QtWaylandClient/private/qwaylandabstractdecoration_p.h>
+#include <QtWaylandClient/private/qwaylandscreen_p.h>
+#include <QtWaylandClient/private/qwaylandextendedsurface_p.h>
#include <QtCore/QDebug>
@@ -121,35 +121,70 @@ void QWaylandWlShellSurface::sendProperty(const QString &name, const QVariant &v
m_extendedWindow->updateGenericProperty(name, value);
}
-void QWaylandWlShellSurface::setMaximized()
+void QWaylandWlShellSurface::applyConfigure()
{
- m_maximized = true;
- m_size = m_window->window()->geometry().size();
- set_maximized(nullptr);
+ if ((m_pending.states & (Qt::WindowMaximized|Qt::WindowFullScreen))
+ && !(m_applied.states & (Qt::WindowMaximized|Qt::WindowFullScreen))) {
+ m_normalSize = m_window->window()->frameGeometry().size();
+ }
+
+ if (m_pending.states != m_applied.states)
+ m_window->handleWindowStatesChanged(m_pending.states);
+
+ if (!m_pending.size.isEmpty()) {
+ int x = 0;
+ int y = 0;
+ if (m_pending.edges & resize_left)
+ x = m_applied.size.width() - m_pending.size.width();
+ if (m_pending.edges & resize_top)
+ y = m_applied.size.height() - m_pending.size.height();
+ QPoint offset(x, y);
+ m_window->resizeFromApplyConfigure(m_pending.size, offset);
+ } else if (m_pending.size.isValid() && !m_normalSize.isEmpty()) {
+ m_window->resizeFromApplyConfigure(m_normalSize);
+ }
+
+ m_applied = m_pending;
}
-void QWaylandWlShellSurface::setFullscreen()
+bool QWaylandWlShellSurface::wantsDecorations() const
{
- m_fullscreen = true;
- m_size = m_window->window()->geometry().size();
- set_fullscreen(WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, nullptr);
+ return !(m_pending.states & Qt::WindowFullScreen);
}
-void QWaylandWlShellSurface::setNormal()
+void QWaylandWlShellSurface::requestWindowStates(Qt::WindowStates states)
{
- if (m_fullscreen || m_maximized) {
- m_fullscreen = m_maximized = false;
- setTopLevel();
- QMargins m = m_window->frameMargins();
- m_window->configure(0, m_size.width() + m.left() + m.right(), m_size.height() + m.top() + m.bottom());
+ // On wl-shell the client is in charge of states, so diff from the pending state
+ Qt::WindowStates changedStates = m_pending.states ^ states;
+ Qt::WindowStates addedStates = changedStates & states;
+
+ if (addedStates & Qt::WindowMinimized)
+ qCWarning(lcQpaWayland) << "Minimizing is not supported on wl-shell. Consider using xdg-shell instead.";
+
+ if (addedStates & Qt::WindowMaximized) {
+ set_maximized(nullptr);
+ m_window->applyConfigureWhenPossible();
}
-}
-void QWaylandWlShellSurface::setMinimized()
-{
- qCWarning(lcQpaWayland) << "Minimization is not supported on wl-shell. Consider using xdg-shell instead.";
+ if (addedStates & Qt::WindowFullScreen) {
+ set_fullscreen(WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, nullptr);
+ m_window->applyConfigureWhenPossible();
+ }
+
+ bool isNormal = ~states & (Qt::WindowMaximized | Qt::WindowFullScreen);
+ if (isNormal && (changedStates & (Qt::WindowMaximized | Qt::WindowFullScreen))) {
+ setTopLevel(); // set normal window
+ // There's usually no configure event after this, so just clear the rest of the pending
+ // configure here and queue the applyConfigure call
+ m_pending.size = {0, 0};
+ m_pending.edges = resize_none;
+ m_window->applyConfigureWhenPossible();
+ }
+
+ m_pending.states = states & ~Qt::WindowMinimized;
}
+
void QWaylandWlShellSurface::setTopLevel()
{
set_toplevel();
@@ -194,11 +229,11 @@ void QWaylandWlShellSurface::setPopup(QWaylandWindow *parent, QWaylandInputDevic
{
QWaylandWindow *parent_wayland_window = parent;
if (!parent_wayland_window) {
- qWarning("setPopup called without parent window");
+ qCWarning(lcQpaWayland) << "setPopup called without a parent window";
return;
}
if (!device) {
- qWarning("setPopup called without input device");
+ qCWarning(lcQpaWayland) << "setPopup called without an input device";
return;
}
@@ -230,11 +265,13 @@ void QWaylandWlShellSurface::shell_surface_ping(uint32_t serial)
pong(serial);
}
-void QWaylandWlShellSurface::shell_surface_configure(uint32_t edges,
- int32_t width,
- int32_t height)
+void QWaylandWlShellSurface::shell_surface_configure(uint32_t edges, int32_t width, int32_t height)
{
- m_window->configure(edges, width, height);
+ m_pending.size = QSize(width, height);
+ m_pending.edges = static_cast<enum resize>(edges);
+ if (m_pending.edges && !m_pending.size.isEmpty())
+ m_normalSize = m_pending.size;
+ m_window->applyConfigureWhenPossible();
}
void QWaylandWlShellSurface::shell_surface_popup_done()
diff --git a/src/client/qwaylandwlshellsurface_p.h b/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface_p.h
index 497ec6043..ca81dd685 100644
--- a/src/client/qwaylandwlshellsurface_p.h
+++ b/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface_p.h
@@ -93,21 +93,26 @@ public:
void sendProperty(const QString &name, const QVariant &value) override;
void setType(Qt::WindowType type, QWaylandWindow *transientParent) override;
+ void applyConfigure() override;
+ bool wantsDecorations() const override;
-private:
- void setMaximized() override;
- void setFullscreen() override;
- void setNormal() override;
- void setMinimized() override;
+protected:
+ void requestWindowStates(Qt::WindowStates states) override;
+private:
void setTopLevel();
void updateTransientParent(QWindow *parent);
void setPopup(QWaylandWindow *parent, QWaylandInputDevice *device, uint serial);
QWaylandWindow *m_window = nullptr;
- bool m_maximized = false;
- bool m_fullscreen = false;
- QSize m_size;
+ struct {
+ Qt::WindowStates states = Qt::WindowNoState;
+ QSize size;
+ enum resize edges = resize_none;
+ } m_applied, m_pending;
+ QSize m_normalSize;
+ // There's really no need to have pending and applied state on wl-shell, but we do it just to
+ // keep the different shell implementations more similar.
QWaylandExtendedSurface *m_extendedWindow = nullptr;
void shell_surface_ping(uint32_t serial) override;
diff --git a/src/plugins/shellintegration/wl-shell/wl-shell.json b/src/plugins/shellintegration/wl-shell/wl-shell.json
new file mode 100644
index 000000000..1859bb58a
--- /dev/null
+++ b/src/plugins/shellintegration/wl-shell/wl-shell.json
@@ -0,0 +1,3 @@
+{
+ "Keys":[ "wl-shell" ]
+}
diff --git a/src/plugins/shellintegration/wl-shell/wl-shell.pro b/src/plugins/shellintegration/wl-shell/wl-shell.pro
new file mode 100644
index 000000000..211dc876f
--- /dev/null
+++ b/src/plugins/shellintegration/wl-shell/wl-shell.pro
@@ -0,0 +1,23 @@
+QT += gui-private waylandclient-private
+CONFIG += wayland-scanner
+
+QMAKE_USE += wayland-client
+
+WAYLANDCLIENTSOURCES += \
+ ../../../3rdparty/protocol/wayland.xml
+
+HEADERS += \
+ qwaylandwlshellintegration_p.h \
+ qwaylandwlshellsurface_p.h \
+
+SOURCES += \
+ main.cpp \
+ qwaylandwlshellintegration.cpp \
+ qwaylandwlshellsurface.cpp \
+
+OTHER_FILES += \
+ wl-shell.json
+
+PLUGIN_TYPE = wayland-shell-integration
+PLUGIN_CLASS_NAME = QWaylandWlShellIntegrationPlugin
+load(qt_plugin)
diff --git a/src/plugins/shellintegration/xdg-shell-v5/main.cpp b/src/plugins/shellintegration/xdg-shell-v5/main.cpp
new file mode 100644
index 000000000..d365f682d
--- /dev/null
+++ b/src/plugins/shellintegration/xdg-shell-v5/main.cpp
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2017 ITAGE Corporation, author: <yusuke.binsaki@itage.co.jp>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwaylandxdgshellv5integration_p.h"
+
+#include <QtWaylandClient/private/qwaylandshellintegrationplugin_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+class QWaylandXdgShellV5IntegrationPlugin : public QWaylandShellIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QWaylandShellIntegrationFactoryInterface_iid FILE "xdg-shell-v5.json")
+
+public:
+ QWaylandShellIntegration *create(const QString &key, const QStringList &paramList) override;
+};
+
+QWaylandShellIntegration *QWaylandXdgShellV5IntegrationPlugin::create(const QString &key, const QStringList &paramList)
+{
+ Q_UNUSED(key);
+ Q_UNUSED(paramList);
+ return new QWaylandXdgShellV5Integration();
+}
+
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/client/qwaylandxdgpopup.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5.cpp
index 46a12a828..542b1628d 100644
--- a/src/client/qwaylandxdgpopup.cpp
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5.cpp
@@ -37,17 +37,17 @@
**
****************************************************************************/
-#include "qwaylandxdgpopup_p.h"
+#include "qwaylandxdgpopupv5_p.h"
-#include "qwaylandwindow_p.h"
-#include "qwaylanddisplay_p.h"
-#include "qwaylandextendedsurface_p.h"
+#include <QtWaylandClient/private/qwaylanddisplay_p.h>
+#include <QtWaylandClient/private/qwaylandwindow_p.h>
+#include <QtWaylandClient/private/qwaylandextendedsurface_p.h>
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
-QWaylandXdgPopup::QWaylandXdgPopup(struct ::xdg_popup *popup, QWaylandWindow *window)
+QWaylandXdgPopupV5::QWaylandXdgPopupV5(struct ::xdg_popup *popup, QWaylandWindow *window)
: QWaylandShellSurface(window)
, QtWayland::xdg_popup(popup)
, m_window(window)
@@ -56,19 +56,19 @@ QWaylandXdgPopup::QWaylandXdgPopup(struct ::xdg_popup *popup, QWaylandWindow *wi
m_extendedWindow = new QWaylandExtendedSurface(window);
}
-QWaylandXdgPopup::~QWaylandXdgPopup()
+QWaylandXdgPopupV5::~QWaylandXdgPopupV5()
{
xdg_popup_destroy(object());
delete m_extendedWindow;
}
-void QWaylandXdgPopup::setType(Qt::WindowType type, QWaylandWindow *transientParent)
+void QWaylandXdgPopupV5::setType(Qt::WindowType type, QWaylandWindow *transientParent)
{
Q_UNUSED(type);
Q_UNUSED(transientParent);
}
-void QWaylandXdgPopup::xdg_popup_popup_done()
+void QWaylandXdgPopupV5::xdg_popup_popup_done()
{
m_window->window()->close();
}
diff --git a/src/client/qwaylandxdgpopup_p.h b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h
index b027c05dc..638b71534 100644
--- a/src/client/qwaylandxdgpopup_p.h
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgpopupv5_p.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QWAYLANDXDGPOPUP_P_H
-#define QWAYLANDXDGPOPUP_P_H
+#ifndef QWAYLANDXDGPOPUPV5_P_H
+#define QWAYLANDXDGPOPUPV5_P_H
//
// W A R N I N G
@@ -51,10 +51,11 @@
// We mean it.
//
+#include "qwayland-xdg-shell-unstable-v5.h"
+
#include <wayland-client.h>
#include <QtWaylandClient/qtwaylandclientglobal.h>
-#include <QtWaylandClient/private/qwayland-xdg-shell.h>
#include <QtWaylandClient/private/qwaylandshellsurface_p.h>
QT_BEGIN_NAMESPACE
@@ -66,13 +67,13 @@ namespace QtWaylandClient {
class QWaylandWindow;
class QWaylandExtendedSurface;
-class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgPopup : public QWaylandShellSurface
+class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgPopupV5 : public QWaylandShellSurface
, public QtWayland::xdg_popup
{
Q_OBJECT
public:
- QWaylandXdgPopup(struct ::xdg_popup *popup, QWaylandWindow *window);
- ~QWaylandXdgPopup() override;
+ QWaylandXdgPopupV5(struct ::xdg_popup *popup, QWaylandWindow *window);
+ ~QWaylandXdgPopupV5() override;
void setType(Qt::WindowType type, QWaylandWindow *transientParent) override;
@@ -88,4 +89,4 @@ QT_END_NAMESPACE
}
-#endif // QWAYLANDXDGPOPUP_P_H
+#endif // QWAYLANDXDGPOPUPV5_P_H
diff --git a/src/client/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp
index 9a34e72dd..6a693578c 100644
--- a/src/client/qwaylandxdgshell.cpp
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5.cpp
@@ -37,43 +37,43 @@
**
****************************************************************************/
-#include "qwaylandxdgshell_p.h"
-
-#include "qwaylanddisplay_p.h"
-#include "qwaylandwindow_p.h"
-#include "qwaylandinputdevice_p.h"
-#include "qwaylandscreen_p.h"
-#include "qwaylandxdgpopup_p.h"
-#include "qwaylandxdgsurface_p.h"
+#include "qwaylandxdgshellv5_p.h"
+#include "qwaylandxdgpopupv5_p.h"
+#include "qwaylandxdgsurfacev5_p.h"
#include <QtCore/QDebug>
+#include <QtWaylandClient/private/qwaylanddisplay_p.h>
+#include <QtWaylandClient/private/qwaylandwindow_p.h>
+#include <QtWaylandClient/private/qwaylandinputdevice_p.h>
+#include <QtWaylandClient/private/qwaylandscreen_p.h>
+
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
-QWaylandXdgShell::QWaylandXdgShell(struct ::xdg_shell *shell)
+QWaylandXdgShellV5::QWaylandXdgShellV5(struct ::xdg_shell *shell)
: QtWayland::xdg_shell(shell)
{
}
-QWaylandXdgShell::QWaylandXdgShell(struct ::wl_registry *registry, uint32_t id)
+QWaylandXdgShellV5::QWaylandXdgShellV5(struct ::wl_registry *registry, uint32_t id)
: QtWayland::xdg_shell(registry, id, 1)
{
use_unstable_version(QtWayland::xdg_shell::version_current);
}
-QWaylandXdgShell::~QWaylandXdgShell()
+QWaylandXdgShellV5::~QWaylandXdgShellV5()
{
xdg_shell_destroy(object());
}
-QWaylandXdgSurface *QWaylandXdgShell::createXdgSurface(QWaylandWindow *window)
+QWaylandXdgSurfaceV5 *QWaylandXdgShellV5::createXdgSurface(QWaylandWindow *window)
{
- return new QWaylandXdgSurface(this, window);
+ return new QWaylandXdgSurfaceV5(this, window);
}
-QWaylandXdgPopup *QWaylandXdgShell::createXdgPopup(QWaylandWindow *window, QWaylandInputDevice *inputDevice)
+QWaylandXdgPopupV5 *QWaylandXdgShellV5::createXdgPopup(QWaylandWindow *window, QWaylandInputDevice *inputDevice)
{
QWaylandWindow *parentWindow = m_popups.empty() ? window->transientParent() : m_popups.last();
::wl_surface *parentSurface = parentWindow->object();
@@ -86,9 +86,9 @@ QWaylandXdgPopup *QWaylandXdgShell::createXdgPopup(QWaylandWindow *window, QWayl
int x = position.x() + parentWindow->frameMargins().left();
int y = position.y() + parentWindow->frameMargins().top();
- auto popup = new QWaylandXdgPopup(get_xdg_popup(window->object(), parentSurface, seat, m_popupSerial, x, y), window);
+ auto popup = new QWaylandXdgPopupV5(get_xdg_popup(window->object(), parentSurface, seat, m_popupSerial, x, y), window);
m_popups.append(window);
- QObject::connect(popup, &QWaylandXdgPopup::destroyed, [this, window](){
+ QObject::connect(popup, &QWaylandXdgPopupV5::destroyed, [this, window](){
m_popups.removeOne(window);
if (m_popups.empty())
m_popupSerial = 0;
@@ -96,7 +96,7 @@ QWaylandXdgPopup *QWaylandXdgShell::createXdgPopup(QWaylandWindow *window, QWayl
return popup;
}
-void QWaylandXdgShell::xdg_shell_ping(uint32_t serial)
+void QWaylandXdgShellV5::xdg_shell_ping(uint32_t serial)
{
pong(serial);
}
diff --git a/src/client/qwaylandxdgshell_p.h b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5_p.h
index 761f25218..ec45bb32c 100644
--- a/src/client/qwaylandxdgshell_p.h
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5_p.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QWAYLANDXDGSHELL_H
-#define QWAYLANDXDGSHELL_H
+#ifndef QWAYLANDXDGSHELLV5_H
+#define QWAYLANDXDGSHELLV5_H
//
// W A R N I N G
@@ -51,12 +51,13 @@
// We mean it.
//
+#include "qwayland-xdg-shell-unstable-v5.h"
+
#include <QtCore/QSize>
#include <QtCore/QVector>
#include <wayland-client.h>
-#include <QtWaylandClient/private/qwayland-xdg-shell.h>
#include <QtWaylandClient/qtwaylandclientglobal.h>
#include <QtWaylandClient/private/qwaylandshellsurface_p.h>
@@ -68,18 +69,18 @@ namespace QtWaylandClient {
class QWaylandWindow;
class QWaylandInputDevice;
-class QWaylandXdgSurface;
-class QWaylandXdgPopup;
+class QWaylandXdgSurfaceV5;
+class QWaylandXdgPopupV5;
-class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgShell : public QtWayland::xdg_shell
+class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgShellV5 : public QtWayland::xdg_shell
{
public:
- QWaylandXdgShell(struct ::xdg_shell *shell);
- QWaylandXdgShell(struct ::wl_registry *registry, uint32_t id);
- ~QWaylandXdgShell() override;
+ QWaylandXdgShellV5(struct ::xdg_shell *shell);
+ QWaylandXdgShellV5(struct ::wl_registry *registry, uint32_t id);
+ ~QWaylandXdgShellV5() override;
- QWaylandXdgSurface *createXdgSurface(QWaylandWindow *window);
- QWaylandXdgPopup *createXdgPopup(QWaylandWindow *window, QWaylandInputDevice *inputDevice);
+ QWaylandXdgSurfaceV5 *createXdgSurface(QWaylandWindow *window);
+ QWaylandXdgPopupV5 *createXdgPopup(QWaylandWindow *window, QWaylandInputDevice *inputDevice);
private:
void xdg_shell_ping(uint32_t serial) override;
@@ -92,4 +93,4 @@ QT_END_NAMESPACE
}
-#endif // QWAYLANDXDGSHELL_H
+#endif // QWAYLANDXDGSHELLV5_H
diff --git a/src/client/qwaylandxdgshellintegration.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
index ee72c2d52..47d748b1c 100644
--- a/src/client/qwaylandxdgshellintegration.cpp
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
@@ -37,42 +37,36 @@
**
****************************************************************************/
-#include "qwaylandxdgshellintegration_p.h"
+#include "qwaylandxdgshellv5integration_p.h"
+#include "qwaylandxdgsurfacev5_p.h"
+#include "qwaylandxdgpopupv5_p.h"
+#include "qwaylandxdgshellv5_p.h"
#include <QtWaylandClient/private/qwaylandwindow_p.h>
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
-#include <QtWaylandClient/private/qwaylandxdgsurface_p.h>
-#include <QtWaylandClient/private/qwaylandxdgpopup_p.h>
-#include <QtWaylandClient/private/qwaylandxdgshell_p.h>
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
-QWaylandXdgShellIntegration *QWaylandXdgShellIntegration::create(QWaylandDisplay *display)
-{
- if (display->hasRegistryGlobal(QLatin1String("xdg_shell")))
- return new QWaylandXdgShellIntegration(display);
- return nullptr;
-}
-
-QWaylandXdgShellIntegration::QWaylandXdgShellIntegration(QWaylandDisplay *display)
+bool QWaylandXdgShellV5Integration::initialize(QWaylandDisplay *display)
{
Q_FOREACH (QWaylandDisplay::RegistryGlobal global, display->globals()) {
if (global.interface == QLatin1String("xdg_shell")) {
- m_xdgShell = new QWaylandXdgShell(display->wl_registry(), global.id);
+ m_xdgShell.reset(new QWaylandXdgShellV5(display->wl_registry(), global.id));
break;
}
}
-}
-bool QWaylandXdgShellIntegration::initialize(QWaylandDisplay *display)
-{
- QWaylandShellIntegration::initialize(display);
- return m_xdgShell != nullptr;
+ if (!m_xdgShell) {
+ qWarning() << "Couldn't find global xdg_shell for xdg-shell unstable v5";
+ return false;
+ }
+
+ return QWaylandShellIntegration::initialize(display);
}
-QWaylandShellSurface *QWaylandXdgShellIntegration::createShellSurface(QWaylandWindow *window)
+QWaylandShellSurface *QWaylandXdgShellV5Integration::createShellSurface(QWaylandWindow *window)
{
QWaylandInputDevice *inputDevice = window->display()->lastInputDevice();
if (window->window()->type() == Qt::WindowType::Popup && inputDevice)
@@ -81,10 +75,10 @@ QWaylandShellSurface *QWaylandXdgShellIntegration::createShellSurface(QWaylandWi
return m_xdgShell->createXdgSurface(window);
}
-void QWaylandXdgShellIntegration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) {
- if (newFocus && qobject_cast<QWaylandXdgPopup *>(newFocus->shellSurface()))
+void QWaylandXdgShellV5Integration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) {
+ if (newFocus && qobject_cast<QWaylandXdgPopupV5 *>(newFocus->shellSurface()))
m_display->handleWindowActivated(newFocus);
- if (oldFocus && qobject_cast<QWaylandXdgPopup *>(oldFocus->shellSurface()))
+ if (oldFocus && qobject_cast<QWaylandXdgPopupV5 *>(oldFocus->shellSurface()))
m_display->handleWindowDeactivated(oldFocus);
}
diff --git a/src/client/qwaylandxdgshellintegration_p.h b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
index ed307a5de..ce6bdb9ee 100644
--- a/src/client/qwaylandxdgshellintegration_p.h
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QWAYLANDXDGSHELLINTEGRATION_P_H
-#define QWAYLANDXDGSHELLINTEGRATION_P_H
+#ifndef QWAYLANDXDGSHELLV5INTEGRATION_P_H
+#define QWAYLANDXDGSHELLV5INTEGRATION_P_H
//
// W A R N I N G
@@ -51,7 +51,7 @@
// We mean it.
//
-#include <wayland-client.h>
+#include "qwaylandxdgshellv5_p.h"
#include <QtWaylandClient/private/qwaylandshellintegration_p.h>
@@ -59,24 +59,22 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
-class QWaylandXdgShell;
+class QWaylandXdgShellV5;
-class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgShellIntegration : public QWaylandShellIntegration
+class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgShellV5Integration : public QWaylandShellIntegration
{
public:
- static QWaylandXdgShellIntegration *create(QWaylandDisplay* display);
+ QWaylandXdgShellV5Integration() {}
bool initialize(QWaylandDisplay *display) override;
QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
private:
- QWaylandXdgShellIntegration(QWaylandDisplay *display);
-
- QWaylandXdgShell *m_xdgShell = nullptr;
+ QScopedPointer<QWaylandXdgShellV5> m_xdgShell;
};
}
QT_END_NAMESPACE
-#endif // QWAYLANDXDGSHELLINTEGRATION_P_H
+#endif // QWAYLANDXDGSHELLV5INTEGRATION_P_H
diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp
new file mode 100644
index 000000000..315dc6231
--- /dev/null
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5.cpp
@@ -0,0 +1,241 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the config.tests of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwaylandxdgsurfacev5_p.h"
+#include "qwaylandxdgshellv5_p.h"
+
+#include <QtWaylandClient/private/qwaylanddisplay_p.h>
+#include <QtWaylandClient/private/qwaylanddisplay_p.h>
+#include <QtWaylandClient/private/qwaylandwindow_p.h>
+#include <QtWaylandClient/private/qwaylandinputdevice_p.h>
+#include <QtWaylandClient/private/qwaylandabstractdecoration_p.h>
+#include <QtWaylandClient/private/qwaylandscreen_p.h>
+#include <QtWaylandClient/private/qwaylandextendedsurface_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+QWaylandXdgSurfaceV5::QWaylandXdgSurfaceV5(QWaylandXdgShellV5 *shell, QWaylandWindow *window)
+ : QWaylandShellSurface(window)
+ , QtWayland::xdg_surface(shell->get_xdg_surface(window->object()))
+ , m_window(window)
+ , m_shell(shell)
+{
+ if (window->display()->windowExtension())
+ m_extendedWindow = new QWaylandExtendedSurface(window);
+}
+
+QWaylandXdgSurfaceV5::~QWaylandXdgSurfaceV5()
+{
+ if (m_acked.states & Qt::WindowActive)
+ window()->display()->handleWindowDeactivated(m_window);
+
+ xdg_surface_destroy(object());
+ delete m_extendedWindow;
+}
+
+void QWaylandXdgSurfaceV5::resize(QWaylandInputDevice *inputDevice, enum wl_shell_surface_resize edges)
+{
+ // May need some conversion if types get incompatibles, ATM they're identical
+ enum resize_edge const * const arg = reinterpret_cast<enum resize_edge const * const>(&edges);
+ resize(inputDevice, *arg);
+}
+
+void QWaylandXdgSurfaceV5::resize(QWaylandInputDevice *inputDevice, enum resize_edge edges)
+{
+ resize(inputDevice->wl_seat(),
+ inputDevice->serial(),
+ edges);
+}
+
+bool QWaylandXdgSurfaceV5::move(QWaylandInputDevice *inputDevice)
+{
+ move(inputDevice->wl_seat(),
+ inputDevice->serial());
+ return true;
+}
+
+void QWaylandXdgSurfaceV5::updateTransientParent(QWaylandWindow *parent)
+{
+ if (!parent)
+ return;
+ auto parentXdgSurface = qobject_cast<QWaylandXdgSurfaceV5 *>(parent->shellSurface());
+ Q_ASSERT(parentXdgSurface);
+ set_parent(parentXdgSurface->object());
+}
+
+void QWaylandXdgSurfaceV5::setTitle(const QString & title)
+{
+ return QtWayland::xdg_surface::set_title(title);
+}
+
+void QWaylandXdgSurfaceV5::setAppId(const QString & appId)
+{
+ return QtWayland::xdg_surface::set_app_id(appId);
+}
+
+void QWaylandXdgSurfaceV5::raise()
+{
+ if (m_extendedWindow)
+ m_extendedWindow->raise();
+}
+
+void QWaylandXdgSurfaceV5::lower()
+{
+ if (m_extendedWindow)
+ m_extendedWindow->lower();
+}
+
+void QWaylandXdgSurfaceV5::setContentOrientationMask(Qt::ScreenOrientations orientation)
+{
+ if (m_extendedWindow)
+ m_extendedWindow->setContentOrientationMask(orientation);
+}
+
+void QWaylandXdgSurfaceV5::setWindowFlags(Qt::WindowFlags flags)
+{
+ if (m_extendedWindow)
+ m_extendedWindow->setWindowFlags(flags);
+}
+
+void QWaylandXdgSurfaceV5::sendProperty(const QString &name, const QVariant &value)
+{
+ if (m_extendedWindow)
+ m_extendedWindow->updateGenericProperty(name, value);
+}
+
+void QWaylandXdgSurfaceV5::setType(Qt::WindowType type, QWaylandWindow *transientParent)
+{
+ Q_UNUSED(type)
+ if (transientParent)
+ updateTransientParent(transientParent);
+}
+
+void QWaylandXdgSurfaceV5::applyConfigure()
+{
+ if (m_pending.isResizing)
+ m_normalSize = m_pending.size;
+ else if (!(m_acked.states & (Qt::WindowMaximized|Qt::WindowFullScreen)))
+ m_normalSize = m_window->window()->frameGeometry().size();
+
+ if ((m_pending.states & Qt::WindowActive) && !(m_acked.states & Qt::WindowActive))
+ m_window->display()->handleWindowActivated(m_window);
+
+ if (!(m_pending.states & Qt::WindowActive) && (m_acked.states & Qt::WindowActive))
+ m_window->display()->handleWindowDeactivated(m_window);
+
+ // TODO: none of the other plugins send WindowActive either, but is it on purpose?
+ Qt::WindowStates statesWithoutActive = m_pending.states & ~Qt::WindowActive;
+
+ m_window->handleWindowStatesChanged(statesWithoutActive);
+ if (!m_pending.size.isEmpty())
+ m_window->resizeFromApplyConfigure(m_pending.size);
+ else if (!m_normalSize.isEmpty())
+ m_window->resizeFromApplyConfigure(m_normalSize);
+ ack_configure(m_pending.serial);
+ m_acked = m_pending;
+}
+
+void QWaylandXdgSurfaceV5::requestWindowStates(Qt::WindowStates states)
+{
+ Qt::WindowStates changedStates = m_acked.states ^ states;
+
+ if (changedStates & Qt::WindowMaximized) {
+ if (states & Qt::WindowMaximized)
+ set_maximized();
+ else
+ unset_maximized();
+ }
+
+ if (changedStates & Qt::WindowFullScreen) {
+ if (states & Qt::WindowFullScreen)
+ set_fullscreen(nullptr);
+ else
+ unset_fullscreen();
+ }
+
+ // Minimized state is not reported by the protocol, so always send it
+ if (states & Qt::WindowMinimized) {
+ set_minimized();
+ window()->handleWindowStatesChanged(states & ~Qt::WindowMinimized);
+ }
+}
+
+bool QWaylandXdgSurfaceV5::wantsDecorations() const
+{
+ return !(m_pending.states & Qt::WindowFullScreen);
+}
+
+void QWaylandXdgSurfaceV5::xdg_surface_configure(int32_t width, int32_t height, struct wl_array *states,uint32_t serial)
+{
+ uint32_t *xdgStates = reinterpret_cast<uint32_t*>(states->data);
+ size_t numStates = states->size / sizeof(uint32_t);
+ m_pending.serial = serial;
+ m_pending.size = QSize(width, height);
+ m_pending.isResizing = false;
+ m_pending.states = Qt::WindowNoState;
+ for (size_t i = 0; i < numStates; i++) {
+ switch (xdgStates[i]) {
+ case XDG_SURFACE_STATE_MAXIMIZED:
+ m_pending.states |= Qt::WindowMaximized;
+ break;
+ case XDG_SURFACE_STATE_FULLSCREEN:
+ m_pending.states |= Qt::WindowFullScreen;
+ break;
+ case XDG_SURFACE_STATE_RESIZING:
+ m_pending.isResizing = true;
+ break;
+ case XDG_SURFACE_STATE_ACTIVATED:
+ m_pending.states |= Qt::WindowActive;
+ break;
+ default:
+ break;
+ }
+ }
+ m_window->applyConfigureWhenPossible();
+}
+
+void QWaylandXdgSurfaceV5::xdg_surface_close()
+{
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/client/qwaylandxdgsurface_p.h b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5_p.h
index b8dd93f47..928395779 100644
--- a/src/client/qwaylandxdgsurface_p.h
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgsurfacev5_p.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QWAYLANDXDGSURFACE_H
-#define QWAYLANDXDGSURFACE_H
+#ifndef QWAYLANDXDGSURFACEV5_P_H
+#define QWAYLANDXDGSURFACEV5_P_H
//
// W A R N I N G
@@ -51,15 +51,16 @@
// We mean it.
//
+#include "qwayland-xdg-shell-unstable-v5.h"
+
+#include <QtWaylandClient/qtwaylandclientglobal.h>
+#include <QtWaylandClient/private/qwaylandshellsurface_p.h>
+
#include <QtCore/QSize>
#include <QtCore/QMargins>
#include <wayland-client.h>
-#include <QtWaylandClient/qtwaylandclientglobal.h>
-#include <QtWaylandClient/private/qwayland-xdg-shell.h>
-#include <QtWaylandClient/private/qwaylandshellsurface_p.h>
-
QT_BEGIN_NAMESPACE
class QWindow;
@@ -69,15 +70,15 @@ namespace QtWaylandClient {
class QWaylandWindow;
class QWaylandInputDevice;
class QWaylandExtendedSurface;
-class QWaylandXdgShell;
+class QWaylandXdgShellV5;
-class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgSurface : public QWaylandShellSurface
+class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgSurfaceV5 : public QWaylandShellSurface
, public QtWayland::xdg_surface
{
Q_OBJECT
public:
- QWaylandXdgSurface(QWaylandXdgShell *shell, QWaylandWindow *window);
- ~QWaylandXdgSurface() override;
+ QWaylandXdgSurfaceV5(QWaylandXdgShellV5 *shell, QWaylandWindow *window);
+ ~QWaylandXdgSurfaceV5() override;
using QtWayland::xdg_surface::resize;
void resize(QWaylandInputDevice *inputDevice, enum resize_edge edges);
@@ -96,26 +97,23 @@ public:
void setWindowFlags(Qt::WindowFlags flags) override;
void sendProperty(const QString &name, const QVariant &value) override;
- bool isFullscreen() const { return m_fullscreen; }
- bool isMaximized() const { return m_maximized; }
-
void setType(Qt::WindowType type, QWaylandWindow *transientParent) override;
+ void applyConfigure() override;
+ void requestWindowStates(Qt::WindowStates states) override;
+ bool wantsDecorations() const override;
private:
- void setMaximized() override;
- void setFullscreen() override;
- void setNormal() override;
- void setMinimized() override;
-
void updateTransientParent(QWaylandWindow *parent);
private:
QWaylandWindow *m_window = nullptr;
- QWaylandXdgShell* m_shell = nullptr;
- bool m_maximized = false;
- bool m_minimized = false;
- bool m_fullscreen = false;
- bool m_active = false;
+ QWaylandXdgShellV5* m_shell = nullptr;
+ struct {
+ Qt::WindowStates states = Qt::WindowNoState;
+ bool isResizing = false;
+ QSize size = {0, 0};
+ uint serial = 0;
+ } m_acked, m_pending;
QSize m_normalSize;
QMargins m_margins;
QWaylandExtendedSurface *m_extendedWindow = nullptr;
@@ -133,4 +131,4 @@ QT_END_NAMESPACE
}
-#endif // QWAYLANDXDGSURFACE_H
+#endif // QWAYLANDXDGSURFACEV5_P_H
diff --git a/src/plugins/shellintegration/xdg-shell-v5/xdg-shell-v5.json b/src/plugins/shellintegration/xdg-shell-v5/xdg-shell-v5.json
new file mode 100644
index 000000000..ba1ed4489
--- /dev/null
+++ b/src/plugins/shellintegration/xdg-shell-v5/xdg-shell-v5.json
@@ -0,0 +1,3 @@
+{
+ "Keys":[ "xdg-shell-v5" ]
+}
diff --git a/src/plugins/shellintegration/xdg-shell-v5/xdg-shell-v5.pro b/src/plugins/shellintegration/xdg-shell-v5/xdg-shell-v5.pro
new file mode 100644
index 000000000..0e97832e4
--- /dev/null
+++ b/src/plugins/shellintegration/xdg-shell-v5/xdg-shell-v5.pro
@@ -0,0 +1,30 @@
+QT += gui-private waylandclient-private
+CONFIG += wayland-scanner
+
+QMAKE_USE += wayland-client
+
+qtConfig(xkbcommon-evdev): \
+ QMAKE_USE += xkbcommon_evdev
+
+WAYLANDCLIENTSOURCES += \
+ ../../../3rdparty/protocol/xdg-shell-unstable-v5.xml
+
+HEADERS += \
+ qwaylandxdgpopupv5_p.h \
+ qwaylandxdgshellv5_p.h \
+ qwaylandxdgshellv5integration_p.h \
+ qwaylandxdgsurfacev5_p.h \
+
+SOURCES += \
+ main.cpp \
+ qwaylandxdgpopupv5.cpp \
+ qwaylandxdgshellv5.cpp \
+ qwaylandxdgshellv5integration.cpp \
+ qwaylandxdgsurfacev5.cpp \
+
+OTHER_FILES += \
+ xdg-shell-v5.json
+
+PLUGIN_TYPE = wayland-shell-integration
+PLUGIN_CLASS_NAME = QWaylandXdgShellV5IntegrationPlugin
+load(qt_plugin)
diff --git a/tests/auto/client/client/tst_client.cpp b/tests/auto/client/client/tst_client.cpp
index 978a9d5e6..21f748ecd 100644
--- a/tests/auto/client/client/tst_client.cpp
+++ b/tests/auto/client/client/tst_client.cpp
@@ -172,6 +172,7 @@ private slots:
void windowScreens();
void removePrimaryScreen();
void createDestroyWindow();
+ void activeWindowFollowsKeyboardFocus();
void events();
void backingStore();
void touchDrag();
@@ -307,7 +308,7 @@ void tst_WaylandClient::createDestroyWindow()
QTRY_VERIFY(!compositor->surface());
}
-void tst_WaylandClient::events()
+void tst_WaylandClient::activeWindowFollowsKeyboardFocus()
{
TestWindow window;
window.show();
@@ -318,6 +319,9 @@ void tst_WaylandClient::events()
QTRY_VERIFY(window.isExposed());
+ if (compositor->xdgToplevelV6())
+ QSKIP("On xdg-shell v6 focus is handled by configure events");
+
QCOMPARE(window.focusInEventCount, 0);
compositor->setKeyboardFocus(surface);
QTRY_COMPARE(window.focusInEventCount, 1);
@@ -327,9 +331,21 @@ void tst_WaylandClient::events()
compositor->setKeyboardFocus(QSharedPointer<MockSurface>(nullptr));
QTRY_COMPARE(window.focusOutEventCount, 1);
QTRY_COMPARE(QGuiApplication::focusWindow(), static_cast<QWindow *>(nullptr));
+}
+
+void tst_WaylandClient::events()
+{
+ TestWindow window;
+ window.show();
+
+ QSharedPointer<MockSurface> surface;
+ QTRY_VERIFY(surface = compositor->surface());
+ compositor->sendShellSurfaceConfigure(surface);
+
+ QTRY_VERIFY(window.isExposed());
compositor->setKeyboardFocus(surface);
- QTRY_COMPARE(window.focusInEventCount, 2);
+ QTRY_COMPARE(window.focusInEventCount, 1);
QTRY_COMPARE(QGuiApplication::focusWindow(), &window);
uint keyCode = 80; // arbitrarily chosen
diff --git a/tests/auto/client/shared/mockcompositor.cpp b/tests/auto/client/shared/mockcompositor.cpp
index 9ef08ad95..11b40d9fc 100644
--- a/tests/auto/client/shared/mockcompositor.cpp
+++ b/tests/auto/client/shared/mockcompositor.cpp
@@ -236,11 +236,14 @@ void MockCompositor::sendIviSurfaceConfigure(const QSharedPointer<MockIviSurface
processCommand(command);
}
-void MockCompositor::sendXdgToplevelV6Configure(const QSharedPointer<MockXdgToplevelV6> toplevel, const QSize &size)
+void MockCompositor::sendXdgToplevelV6Configure(const QSharedPointer<MockXdgToplevelV6> toplevel, const QSize &size, const QVector<uint> &states)
{
Command command = makeCommand(Impl::Compositor::sendXdgToplevelV6Configure, m_compositor);
command.parameters << QVariant::fromValue(toplevel);
command.parameters << QVariant::fromValue(size);
+ auto statesBytes = QByteArray::fromRawData(reinterpret_cast<const char *>(states.data()),
+ states.size() * static_cast<int>(sizeof(uint)));
+ command.parameters << statesBytes;
processCommand(command);
}
diff --git a/tests/auto/client/shared/mockcompositor.h b/tests/auto/client/shared/mockcompositor.h
index 34c20943a..d3568c165 100644
--- a/tests/auto/client/shared/mockcompositor.h
+++ b/tests/auto/client/shared/mockcompositor.h
@@ -175,12 +175,21 @@ private:
Q_DECLARE_METATYPE(QSharedPointer<MockIviSurface>)
-class MockXdgToplevelV6
+class MockXdgToplevelV6 : public QObject
{
+ Q_OBJECT
public:
Impl::XdgToplevelV6 *handle() const { return m_toplevel; }
void sendConfigure(const QSharedPointer<MockXdgToplevelV6> toplevel);
+
+signals:
+ uint setMinimizedRequested();
+ uint setMaximizedRequested();
+ uint unsetMaximizedRequested();
+ uint setFullscreenRequested();
+ uint unsetFullscreenRequested();
+
private:
MockXdgToplevelV6(Impl::XdgToplevelV6 *toplevel) : m_toplevel(toplevel) {}
friend class Impl::Compositor;
@@ -234,7 +243,8 @@ public:
void sendSurfaceLeave(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output);
void sendShellSurfaceConfigure(const QSharedPointer<MockSurface> surface, const QSize &size = QSize(0, 0));
void sendIviSurfaceConfigure(const QSharedPointer<MockIviSurface> iviSurface, const QSize &size);
- void sendXdgToplevelV6Configure(const QSharedPointer<MockXdgToplevelV6> toplevel, const QSize &size = QSize(0, 0));
+ void sendXdgToplevelV6Configure(const QSharedPointer<MockXdgToplevelV6> toplevel, const QSize &size = QSize(0, 0),
+ const QVector<uint> &states = { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED });
void waitForStartDrag();
QSharedPointer<MockSurface> surface();
diff --git a/tests/auto/client/shared/mocksurface.cpp b/tests/auto/client/shared/mocksurface.cpp
index 81a865f11..82ce37acb 100644
--- a/tests/auto/client/shared/mocksurface.cpp
+++ b/tests/auto/client/shared/mocksurface.cpp
@@ -70,7 +70,10 @@ void Compositor::sendShellSurfaceConfigure(void *data, const QList<QVariant> &pa
QSize size = parameters.at(1).toSize();
Q_ASSERT(size.isValid());
if (auto toplevel = surface->xdgToplevelV6()) {
- toplevel->send_configure(size.width(), size.height(), QByteArray());
+ QVector<uint> states = { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED };
+ auto statesBytes = QByteArray::fromRawData(reinterpret_cast<const char *>(states.data()),
+ states.size() * static_cast<int>(sizeof(uint)));
+ toplevel->send_configure(size.width(), size.height(), statesBytes);
toplevel->xdgSurface()->send_configure(compositor->nextSerial());
} else if (auto wlShellSurface = surface->wlShellSurface()) {
const uint edges = 0;
diff --git a/tests/auto/client/shared/mockxdgshellv6.cpp b/tests/auto/client/shared/mockxdgshellv6.cpp
index 39e03296d..6f6f0b905 100644
--- a/tests/auto/client/shared/mockxdgshellv6.cpp
+++ b/tests/auto/client/shared/mockxdgshellv6.cpp
@@ -39,8 +39,8 @@ void Compositor::sendXdgToplevelV6Configure(void *data, const QList<QVariant> &p
Q_ASSERT(toplevel && toplevel->resource());
QSize size = parameters.at(1).toSize();
Q_ASSERT(size.isValid());
- QByteArray states;
- toplevel->send_configure(size.width(), size.height(), states);
+ auto statesBytes = parameters.at(2).toByteArray();
+ toplevel->send_configure(size.width(), size.height(), statesBytes);
toplevel->xdgSurface()->send_configure(compositor->nextSerial());
}
@@ -87,6 +87,37 @@ void XdgToplevelV6::zxdg_toplevel_v6_destroy(QtWaylandServer::zxdg_toplevel_v6::
wl_resource_destroy(resource->handle);
}
+void XdgToplevelV6::zxdg_toplevel_v6_set_minimized(QtWaylandServer::zxdg_toplevel_v6::Resource *resource)
+{
+ Q_UNUSED(resource);
+ emit m_mockToplevel->setMinimizedRequested();
+}
+
+void XdgToplevelV6::zxdg_toplevel_v6_set_maximized(QtWaylandServer::zxdg_toplevel_v6::Resource *resource)
+{
+ Q_UNUSED(resource);
+ emit m_mockToplevel->setMaximizedRequested();
+}
+
+void XdgToplevelV6::zxdg_toplevel_v6_unset_maximized(QtWaylandServer::zxdg_toplevel_v6::Resource *resource)
+{
+ Q_UNUSED(resource);
+ emit m_mockToplevel->unsetMaximizedRequested();
+}
+
+void XdgToplevelV6::zxdg_toplevel_v6_set_fullscreen(QtWaylandServer::zxdg_toplevel_v6::Resource *resource, wl_resource *output)
+{
+ Q_UNUSED(resource);
+ Q_UNUSED(output);
+ emit m_mockToplevel->setFullscreenRequested();
+}
+
+void XdgToplevelV6::zxdg_toplevel_v6_unset_fullscreen(QtWaylandServer::zxdg_toplevel_v6::Resource *resource)
+{
+ Q_UNUSED(resource);
+ emit m_mockToplevel->unsetFullscreenRequested();
+}
+
void Impl::XdgShellV6::zxdg_shell_v6_get_xdg_surface(QtWaylandServer::zxdg_shell_v6::Resource *resource, uint32_t id, wl_resource *surface)
{
new XdgSurfaceV6(this, Surface::fromResource(surface), resource->client(), id);
diff --git a/tests/auto/client/shared/mockxdgshellv6.h b/tests/auto/client/shared/mockxdgshellv6.h
index 92b808ba8..faadb785a 100644
--- a/tests/auto/client/shared/mockxdgshellv6.h
+++ b/tests/auto/client/shared/mockxdgshellv6.h
@@ -74,6 +74,11 @@ public:
protected:
void zxdg_toplevel_v6_destroy_resource(Resource *) override { delete this; }
void zxdg_toplevel_v6_destroy(Resource *resource) override;
+ void zxdg_toplevel_v6_set_minimized(Resource *resource) override;
+ void zxdg_toplevel_v6_set_maximized(Resource *resource) override;
+ void zxdg_toplevel_v6_unset_maximized(Resource *resource) override;
+ void zxdg_toplevel_v6_set_fullscreen(Resource *resource, struct ::wl_resource *output) override;
+ void zxdg_toplevel_v6_unset_fullscreen(Resource *resource) override;
private:
XdgSurfaceV6 *m_xdgSurface = nullptr;
diff --git a/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp b/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp
index 364cd1099..0f72f58a9 100644
--- a/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp
+++ b/tests/auto/client/xdgshellv6/tst_xdgshellv6.cpp
@@ -42,6 +42,7 @@ static const QSize screenSize(1600, 1200);
class TestWindow : public QWindow
{
+ Q_OBJECT
public:
TestWindow()
{
@@ -49,6 +50,16 @@ public:
setGeometry(0, 0, 32, 32);
create();
}
+
+ bool event(QEvent *event) override
+ {
+ if (event->type() == QEvent::WindowStateChange)
+ emit windowStateChangeEventReceived(static_cast<QWindowStateChangeEvent *>(event)->oldState());
+ return QWindow::event(event);
+ }
+
+signals:
+ void windowStateChangeEventReceived(uint oldState);
};
class tst_WaylandClientXdgShellV6 : public QObject
@@ -58,6 +69,7 @@ public:
tst_WaylandClientXdgShellV6(MockCompositor *c)
: m_compositor(c)
{
+ qRegisterMetaType<Qt::WindowState>();
QSocketNotifier *notifier = new QSocketNotifier(m_compositor->waylandFileDescriptor(), QSocketNotifier::Read, this);
connect(notifier, &QSocketNotifier::activated, this, &tst_WaylandClientXdgShellV6::processWaylandEvents);
// connect to the event dispatcher to make sure to flush out the outgoing message queue
@@ -82,6 +94,11 @@ public slots:
private slots:
void createDestroyWindow();
void configure();
+ void showMinimized();
+ void setMinimized();
+ void unsetMaximized();
+ void focusWindowFollowsConfigure();
+ void windowStateChangedEvents();
private:
MockCompositor *m_compositor = nullptr;
@@ -118,10 +135,182 @@ void tst_WaylandClientXdgShellV6::configure()
QSharedPointer<MockXdgToplevelV6> toplevel;
QTRY_VERIFY(toplevel = m_compositor->xdgToplevelV6());
+
const QSize newSize(123, 456);
m_compositor->sendXdgToplevelV6Configure(toplevel, newSize);
QTRY_VERIFY(window.isExposed());
+ QTRY_COMPARE(window.visibility(), QWindow::Windowed);
+ QTRY_COMPARE(window.windowStates(), Qt::WindowNoState);
QTRY_COMPARE(window.frameGeometry(), QRect(QPoint(), newSize));
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel, screenSize, { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED, ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED });
+ QTRY_COMPARE(window.visibility(), QWindow::Maximized);
+ QTRY_COMPARE(window.windowStates(), Qt::WindowMaximized);
+ QTRY_COMPARE(window.frameGeometry(), QRect(QPoint(), screenSize));
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel, screenSize, { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED, ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN });
+ QTRY_COMPARE(window.visibility(), QWindow::FullScreen);
+ QTRY_COMPARE(window.windowStates(), Qt::WindowFullScreen);
+ QTRY_COMPARE(window.frameGeometry(), QRect(QPoint(), screenSize));
+
+ //The window should remember it's original size
+ m_compositor->sendXdgToplevelV6Configure(toplevel, QSize(0, 0), { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED });
+ QTRY_COMPARE(window.visibility(), QWindow::Windowed);
+ QTRY_COMPARE(window.windowStates(), Qt::WindowNoState);
+ QTRY_COMPARE(window.frameGeometry(), QRect(QPoint(), newSize));
+}
+
+void tst_WaylandClientXdgShellV6::showMinimized()
+{
+ // On xdg-shell v6 there's really no way for the compositor to tell the window if it's minimized
+ // There are wl_surface.enter events and so on, but there's really no way to differentiate
+ // between a window preview and an unminimized window.
+ TestWindow window;
+ window.showMinimized();
+ QCOMPARE(window.windowStates(), Qt::WindowMinimized); // should return minimized until
+ QTRY_COMPARE(window.windowStates(), Qt::WindowNoState); // rejected by handleWindowStateChanged
+}
+
+void tst_WaylandClientXdgShellV6::setMinimized()
+{
+ TestWindow window;
+ window.show();
+
+ QSharedPointer<MockXdgToplevelV6> toplevel;
+ QTRY_VERIFY(toplevel = m_compositor->xdgToplevelV6());
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel);
+ QTRY_COMPARE(window.visibility(), QWindow::Windowed);
+ QTRY_COMPARE(window.windowStates(), Qt::WindowNoState);
+
+ QSignalSpy setMinimizedSpy(toplevel.data(), SIGNAL(setMinimizedRequested()));
+ QSignalSpy windowStateChangeSpy(&window, SIGNAL(windowStateChangeEventReceived(uint)));
+
+ window.setVisibility(QWindow::Minimized);
+ QCOMPARE(window.visibility(), QWindow::Minimized);
+ QCOMPARE(window.windowStates(), Qt::WindowMinimized);
+ QTRY_COMPARE(setMinimizedSpy.count(), 1);
+ {
+ QTRY_VERIFY(windowStateChangeSpy.count() > 0);
+ Qt::WindowStates oldStates(windowStateChangeSpy.takeFirst().at(0).toUInt());
+ QCOMPARE(oldStates, Qt::WindowNoState);
+ }
+
+ // In the meantime the compositor may minimize, do nothing or reshow the window without
+ // telling us.
+
+ QTRY_COMPARE(window.visibility(), QWindow::Windowed); // verify that we don't know anything
+ QTRY_COMPARE(window.windowStates(), Qt::WindowNoState);
+ {
+ QTRY_COMPARE(windowStateChangeSpy.count(), 1);
+ Qt::WindowStates oldStates(windowStateChangeSpy.takeFirst().at(0).toUInt());
+ QCOMPARE(oldStates, Qt::WindowNoState); // because the window never was minimized
+ }
+
+ // Setting visibility again should send another set_minimized request
+ window.setVisibility(QWindow::Minimized);
+ QTRY_COMPARE(setMinimizedSpy.count(), 2);
+}
+
+void tst_WaylandClientXdgShellV6::unsetMaximized()
+{
+ TestWindow window;
+ window.show();
+
+ QSharedPointer<MockXdgToplevelV6> toplevel;
+ QTRY_VERIFY(toplevel = m_compositor->xdgToplevelV6());
+
+ QSignalSpy unsetMaximizedSpy(toplevel.data(), SIGNAL(unsetMaximizedRequested()));
+
+ QSignalSpy windowStateChangedSpy(&window, SIGNAL(windowStateChanged(Qt::WindowState)));
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel, screenSize, { ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED });
+
+ QTRY_COMPARE(windowStateChangedSpy.count(), 1);
+ QCOMPARE(windowStateChangedSpy.takeFirst().at(0).toUInt(), Qt::WindowMaximized);
+
+ window.setWindowStates(Qt::WindowNoState);
+
+ QTRY_COMPARE(unsetMaximizedSpy.count(), 1);
+ QTRY_COMPARE(windowStateChangedSpy.count(), 1);
+ QCOMPARE(windowStateChangedSpy.takeFirst().at(0).toUInt(), Qt::WindowNoState);
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel, QSize(0, 0), {});
+
+ QTRY_COMPARE(windowStateChangedSpy.count(), 1);
+ QCOMPARE(windowStateChangedSpy.takeFirst().at(0).toUInt(), Qt::WindowNoState);
+}
+
+void tst_WaylandClientXdgShellV6::focusWindowFollowsConfigure()
+{
+ TestWindow window;
+ window.show();
+
+ QSharedPointer<MockXdgToplevelV6> toplevel;
+ QTRY_VERIFY(toplevel = m_compositor->xdgToplevelV6());
+ QTRY_VERIFY(!window.isActive());
+
+ QSignalSpy windowStateChangeSpy(&window, SIGNAL(windowStateChangeEventReceived(uint)));
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel, QSize(0, 0), { ZXDG_TOPLEVEL_V6_STATE_ACTIVATED });
+ QTRY_VERIFY(window.isActive());
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel, QSize(0, 0), {});
+ QTRY_VERIFY(!window.isActive());
+}
+
+void tst_WaylandClientXdgShellV6::windowStateChangedEvents()
+{
+ TestWindow window;
+ window.show();
+
+ QSharedPointer<MockXdgToplevelV6> toplevel;
+ QTRY_VERIFY(toplevel = m_compositor->xdgToplevelV6());
+
+ QSignalSpy eventSpy(&window, SIGNAL(windowStateChangeEventReceived(uint)));
+ QSignalSpy signalSpy(&window, SIGNAL(windowStateChanged(Qt::WindowState)));
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel, screenSize, { ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED });
+
+ QTRY_COMPARE(window.windowStates(), Qt::WindowMaximized);
+ QTRY_COMPARE(window.windowState(), Qt::WindowMaximized);
+ {
+ QTRY_COMPARE(eventSpy.count(), 1);
+ Qt::WindowStates oldStates(eventSpy.takeFirst().at(0).toUInt());
+ QCOMPARE(oldStates, Qt::WindowNoState);
+
+ QTRY_COMPARE(signalSpy.count(), 1);
+ uint newState = signalSpy.takeFirst().at(0).toUInt();
+ QCOMPARE(newState, Qt::WindowMaximized);
+ }
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel, screenSize, { ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN });
+
+ QTRY_COMPARE(window.windowStates(), Qt::WindowFullScreen);
+ QTRY_COMPARE(window.windowState(), Qt::WindowFullScreen);
+ {
+ QTRY_COMPARE(eventSpy.count(), 1);
+ Qt::WindowStates oldStates(eventSpy.takeFirst().at(0).toUInt());
+ QCOMPARE(oldStates, Qt::WindowMaximized);
+
+ QTRY_COMPARE(signalSpy.count(), 1);
+ uint newState = signalSpy.takeFirst().at(0).toUInt();
+ QCOMPARE(newState, Qt::WindowFullScreen);
+ }
+
+ m_compositor->sendXdgToplevelV6Configure(toplevel, QSize(0, 0), {});
+
+ QTRY_COMPARE(window.windowStates(), Qt::WindowNoState);
+ QTRY_COMPARE(window.windowState(), Qt::WindowNoState);
+ {
+ QTRY_COMPARE(eventSpy.count(), 1);
+ Qt::WindowStates oldStates(eventSpy.takeFirst().at(0).toUInt());
+ QCOMPARE(oldStates, Qt::WindowFullScreen);
+
+ QTRY_COMPARE(signalSpy.count(), 1);
+ uint newState = signalSpy.takeFirst().at(0).toUInt();
+ QCOMPARE(newState, Qt::WindowNoState);
+ }
}
int main(int argc, char **argv)
diff --git a/tests/auto/compositor/compositor/compositor.pro b/tests/auto/compositor/compositor/compositor.pro
index 2919fa4bb..d69db4ca5 100644
--- a/tests/auto/compositor/compositor/compositor.pro
+++ b/tests/auto/compositor/compositor/compositor.pro
@@ -11,7 +11,7 @@ qtConfig(xkbcommon-evdev): \
QMAKE_USE += xkbcommon_evdev
WAYLANDCLIENTSOURCES += \
- ../../../../src/3rdparty/protocol/xdg-shell.xml \
+ ../../../../src/3rdparty/protocol/xdg-shell-unstable-v5.xml \
../../../../src/3rdparty/protocol/ivi-application.xml \
SOURCES += \
@@ -21,6 +21,7 @@ SOURCES += \
mockclient.cpp \
mockseat.cpp \
testseat.cpp \
+ mockkeyboard.cpp \
mockpointer.cpp
HEADERS += \
@@ -29,4 +30,5 @@ HEADERS += \
mockclient.h \
mockseat.h \
testseat.h \
+ mockkeyboard.h \
mockpointer.h
diff --git a/tests/auto/compositor/compositor/mockclient.h b/tests/auto/compositor/compositor/mockclient.h
index 6d5bf31df..6bfb652ed 100644
--- a/tests/auto/compositor/compositor/mockclient.h
+++ b/tests/auto/compositor/compositor/mockclient.h
@@ -27,7 +27,7 @@
****************************************************************************/
#include <wayland-client.h>
-#include <wayland-xdg-shell-client-protocol.h>
+#include <qwayland-xdg-shell-unstable-v5.h>
#include <wayland-ivi-application-client-protocol.h>
#include <QObject>
diff --git a/tests/auto/compositor/compositor/mockkeyboard.cpp b/tests/auto/compositor/compositor/mockkeyboard.cpp
new file mode 100644
index 000000000..e5f5f8d36
--- /dev/null
+++ b/tests/auto/compositor/compositor/mockkeyboard.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mockkeyboard.h"
+
+void keyboardKeymap(void *keyboard, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size)
+{
+ Q_UNUSED(keyboard);
+ Q_UNUSED(wl_keyboard);
+ Q_UNUSED(format);
+ Q_UNUSED(fd);
+ Q_UNUSED(size);
+}
+
+void keyboardEnter(void *keyboard, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
+{
+ Q_UNUSED(wl_keyboard);
+ Q_UNUSED(serial);
+ Q_UNUSED(surface);
+ Q_UNUSED(keys);
+
+ static_cast<MockKeyboard *>(keyboard)->m_enteredSurface = surface;
+}
+
+void keyboardLeave(void *keyboard, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface)
+{
+ Q_UNUSED(wl_keyboard);
+ Q_UNUSED(serial);
+ Q_UNUSED(surface);
+
+ static_cast<MockKeyboard *>(keyboard)->m_enteredSurface = nullptr;
+}
+
+void keyboardKey(void *keyboard, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
+{
+ Q_UNUSED(keyboard);
+ Q_UNUSED(wl_keyboard);
+ Q_UNUSED(serial);
+ Q_UNUSED(time);
+ Q_UNUSED(key);
+ Q_UNUSED(state);
+ auto kb = static_cast<MockKeyboard *>(keyboard);
+ kb->m_lastKeyCode = key;
+ kb->m_lastKeyState = state;
+}
+
+void keyboardModifiers(void *keyboard, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
+{
+ Q_UNUSED(keyboard);
+ Q_UNUSED(wl_keyboard);
+ Q_UNUSED(serial);
+ Q_UNUSED(mods_depressed);
+ Q_UNUSED(mods_latched);
+ Q_UNUSED(mods_locked);
+ auto kb = static_cast<MockKeyboard *>(keyboard);
+ kb->m_group = group;
+}
+
+static const struct wl_keyboard_listener keyboardListener = {
+ keyboardKeymap,
+ keyboardEnter,
+ keyboardLeave,
+ keyboardKey,
+ keyboardModifiers
+};
+
+MockKeyboard::MockKeyboard(wl_seat *seat)
+ : m_keyboard(wl_seat_get_keyboard(seat))
+{
+ wl_keyboard_add_listener(m_keyboard, &keyboardListener, this);
+}
+
+MockKeyboard::~MockKeyboard()
+{
+ wl_keyboard_destroy(m_keyboard);
+}
diff --git a/tests/auto/compositor/compositor/mockkeyboard.h b/tests/auto/compositor/compositor/mockkeyboard.h
new file mode 100644
index 000000000..1090db597
--- /dev/null
+++ b/tests/auto/compositor/compositor/mockkeyboard.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MOCKKEYBOARD_H
+#define MOCKKEYBOARD_H
+
+#include <QObject>
+#include <wayland-client.h>
+
+class MockKeyboard : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit MockKeyboard(wl_seat *seat);
+ ~MockKeyboard() override;
+
+ wl_keyboard *m_keyboard = nullptr;
+ wl_surface *m_enteredSurface = nullptr;
+ uint m_lastKeyCode = 0;
+ uint m_lastKeyState = 0;
+ uint m_group = 0;
+};
+
+#endif // MOCKKEYBOARD_H
diff --git a/tests/auto/compositor/compositor/mockseat.cpp b/tests/auto/compositor/compositor/mockseat.cpp
index 052c2f90b..ce873c129 100644
--- a/tests/auto/compositor/compositor/mockseat.cpp
+++ b/tests/auto/compositor/compositor/mockseat.cpp
@@ -31,14 +31,11 @@
MockSeat::MockSeat(wl_seat *seat)
: m_seat(seat)
, m_pointer(new MockPointer(seat))
+ , m_keyboard(new MockKeyboard(seat))
{
- // Bind to the keyboard interface so that the compositor has
- // the right resource associations
- m_keyboard = wl_seat_get_keyboard(seat);
}
MockSeat::~MockSeat()
{
- wl_keyboard_destroy(m_keyboard);
wl_seat_destroy(m_seat);
}
diff --git a/tests/auto/compositor/compositor/mockseat.h b/tests/auto/compositor/compositor/mockseat.h
index 73d289281..f8c103ed4 100644
--- a/tests/auto/compositor/compositor/mockseat.h
+++ b/tests/auto/compositor/compositor/mockseat.h
@@ -29,6 +29,7 @@
#define MOCKSEAT
#include "mockpointer.h"
+#include "mockkeyboard.h"
#include <QObject>
#include <wayland-client.h>
@@ -41,12 +42,13 @@ public:
MockSeat(wl_seat *seat);
~MockSeat() override;
MockPointer *pointer() const { return m_pointer.data(); }
+ MockKeyboard *keyboard() const { return m_keyboard.data(); }
wl_seat *m_seat = nullptr;
- wl_keyboard *m_keyboard = nullptr;
private:
QScopedPointer<MockPointer> m_pointer;
+ QScopedPointer<MockKeyboard> m_keyboard;
};
#endif
diff --git a/tests/auto/compositor/compositor/tst_compositor.cpp b/tests/auto/compositor/compositor/tst_compositor.cpp
index ae5ea927d..e3c4daccc 100644
--- a/tests/auto/compositor/compositor/tst_compositor.cpp
+++ b/tests/auto/compositor/compositor/tst_compositor.cpp
@@ -40,11 +40,13 @@
#include <QtGui/QScreen>
#include <QtWaylandCompositor/QWaylandXdgShellV5>
#include <QtWaylandCompositor/private/qwaylandxdgshellv6_p.h>
+#include <QtWaylandCompositor/private/qwaylandkeyboard_p.h>
#include <QtWaylandCompositor/QWaylandIviApplication>
#include <QtWaylandCompositor/QWaylandIviSurface>
#include <QtWaylandCompositor/QWaylandSurface>
#include <QtWaylandCompositor/QWaylandResource>
-#include <qwayland-xdg-shell.h>
+#include <QtWaylandCompositor/QWaylandKeymap>
+#include <qwayland-xdg-shell-unstable-v5.h>
#include <qwayland-ivi-application.h>
#include <QtTest/QtTest>
@@ -56,6 +58,11 @@ class tst_WaylandCompositor : public QObject
private slots:
void init();
void seatCapabilities();
+#if QT_CONFIG(xkbcommon_evdev)
+ void simpleKeyboard();
+ void keyboardKeymaps();
+ void keyboardLayoutSwitching();
+#endif
void keyboardGrab();
void seatCreation();
void seatKeyboardFocus();
@@ -160,6 +167,121 @@ void tst_WaylandCompositor::multipleClients()
QTRY_COMPARE(compositor.surfaces.size(), 0);
}
+#if QT_CONFIG(xkbcommon_evdev)
+
+void tst_WaylandCompositor::simpleKeyboard()
+{
+ TestCompositor compositor;
+ compositor.create();
+
+ QWaylandSeat* seat = compositor.defaultSeat();
+ seat->keymap()->setLayout("us");
+
+ MockClient client;
+
+ QTRY_COMPARE(client.m_seats.size(), 1);
+ MockKeyboard *mockKeyboard = client.m_seats.at(0)->keyboard();
+
+ wl_surface *mockSurface = client.createSurface();
+ QTRY_COMPARE(compositor.surfaces.size(), 1);
+ seat->setKeyboardFocus(compositor.surfaces.at(0));
+
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_enteredSurface, mockSurface);
+
+ seat->sendKeyEvent(Qt::Key_A, true);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_lastKeyState, 1u);
+ QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 30u); // 30 is the scan code for A on us keyboard layouts
+
+ seat->sendKeyEvent(Qt::Key_A, false);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_lastKeyState, 0u);
+ QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 30u);
+
+ seat->sendKeyEvent(Qt::Key_Super_L, true);
+ seat->sendKeyEvent(Qt::Key_Super_L, false);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 125u);
+}
+
+void tst_WaylandCompositor::keyboardKeymaps()
+{
+ TestCompositor compositor;
+ compositor.create();
+ QWaylandSeat* seat = compositor.defaultSeat();
+ MockClient client;
+ QTRY_COMPARE(client.m_seats.size(), 1);
+ MockKeyboard *mockKeyboard = client.m_seats.at(0)->keyboard();
+ client.createSurface();
+ QTRY_COMPARE(compositor.surfaces.size(), 1);
+ seat->setKeyboardFocus(compositor.surfaces.at(0));
+
+ seat->keymap()->setLayout("us");
+
+ seat->sendKeyEvent(Qt::Key_Y, true);
+ seat->sendKeyEvent(Qt::Key_Y, false);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 21u);
+
+ seat->sendKeyEvent(Qt::Key_Z, true);
+ seat->sendKeyEvent(Qt::Key_Z, false);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 44u);
+
+ seat->keymap()->setLayout("de"); // In the German layout y and z have changed places
+
+ seat->sendKeyEvent(Qt::Key_Y, true);
+ seat->sendKeyEvent(Qt::Key_Y, false);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 44u);
+
+ seat->sendKeyEvent(Qt::Key_Z, true);
+ seat->sendKeyEvent(Qt::Key_Z, false);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 21u);
+}
+
+void tst_WaylandCompositor::keyboardLayoutSwitching()
+{
+ TestCompositor compositor;
+ compositor.create();
+ QWaylandSeat* seat = compositor.defaultSeat();
+ MockClient client;
+ QTRY_COMPARE(client.m_seats.size(), 1);
+ MockKeyboard *mockKeyboard = client.m_seats.at(0)->keyboard();
+ client.createSurface();
+ QTRY_COMPARE(compositor.surfaces.size(), 1);
+ seat->setKeyboardFocus(compositor.surfaces.at(0));
+
+ seat->keymap()->setLayout("us,de");
+ seat->keymap()->setOptions("grp:lalt_toggle"); //toggle keyboard layout with left alt
+
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_group, 0u);
+
+ seat->sendKeyEvent(Qt::Key_Y, true);
+ seat->sendKeyEvent(Qt::Key_Y, false);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 21u);
+
+ // It's not currently possible to switch layouts programmatically with the public APIs
+ // We will just fake it with the private APIs here.
+ auto keyboardPrivate = QWaylandKeyboardPrivate::get(seat->keyboard());
+ const uint leftAltCode = 64;
+ keyboardPrivate->updateModifierState(leftAltCode, WL_KEYBOARD_KEY_STATE_PRESSED);
+ keyboardPrivate->updateModifierState(leftAltCode, WL_KEYBOARD_KEY_STATE_RELEASED);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_group, 1u);
+
+ seat->sendKeyEvent(Qt::Key_Y, true);
+ seat->sendKeyEvent(Qt::Key_Y, false);
+ compositor.flushClients();
+ QTRY_COMPARE(mockKeyboard->m_lastKeyCode, 44u);
+}
+
+#endif // QT_CONFIG(xkbcommon_evdev)
+
void tst_WaylandCompositor::keyboardGrab()
{
TestCompositor compositor;
@@ -450,13 +572,24 @@ void tst_WaylandCompositor::seatKeyboardFocus()
// Create client after all the input devices have been set up as the mock client
// does not dynamically listen to new seats
MockClient client;
+
+ QTRY_COMPARE(client.m_seats.size(), 1);
+ MockKeyboard *mockKeyboard = client.m_seats.first()->keyboard();
+ QVERIFY(mockKeyboard);
+ QCOMPARE(mockKeyboard->m_enteredSurface, nullptr);
+
wl_surface *surface = client.createSurface();
QTRY_COMPARE(compositor.surfaces.size(), 1);
QWaylandSurface *waylandSurface = compositor.surfaces.at(0);
- QWaylandSeat* dev = compositor.defaultSeat();
- dev->setKeyboardFocus(waylandSurface);
- QTRY_COMPARE(compositor.defaultSeat()->keyboardFocus(), waylandSurface);
+ QWaylandSeat* seat = compositor.defaultSeat();
+ QVERIFY(seat->setKeyboardFocus(waylandSurface));
+ QCOMPARE(compositor.defaultSeat()->keyboardFocus(), waylandSurface);
+
+ compositor.flushClients();
+
+ qDebug() << mockKeyboard->m_enteredSurface;
+ QTRY_COMPARE(mockKeyboard->m_enteredSurface, surface);
wl_surface_destroy(surface);
QTRY_VERIFY(compositor.surfaces.size() == 0);