summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.cmake.conf5
-rw-r--r--.gitignore2
-rw-r--r--CMakeLists.txt6
-rw-r--r--cmake/FindWaylandkms.cmake3
-rw-r--r--coin/axivion/ci_config_linux.json44
-rw-r--r--coin/module_config.yaml6
-rw-r--r--coin/qt-installer-package-config.json3
-rw-r--r--conanfile.py37
-rw-r--r--config.tests/wayland_scanner/CMakeLists.txt3
-rw-r--r--config.tests/wayland_scanner/main.cpp2
-rw-r--r--configure.cmake3
-rw-r--r--dependencies.yaml7
-rw-r--r--examples/CMakeLists.txt3
-rw-r--r--examples/wayland/CMakeLists.txt13
-rw-r--r--examples/wayland/custom-extension/CMakeLists.txt12
-rw-r--r--examples/wayland/custom-extension/client-common/customextension.cpp13
-rw-r--r--examples/wayland/custom-extension/client-common/customextension.h6
-rw-r--r--examples/wayland/custom-extension/compositor/CMakeLists.txt9
-rw-r--r--examples/wayland/custom-extension/compositor/compositor.pro4
-rw-r--r--examples/wayland/custom-extension/compositor/customextension.cpp8
-rw-r--r--examples/wayland/custom-extension/compositor/customextension.h8
-rw-r--r--examples/wayland/custom-extension/compositor/main.cpp9
-rw-r--r--examples/wayland/custom-extension/compositor/qml/CompositorScreen.qml12
-rw-r--r--examples/wayland/custom-extension/compositor/qml/main.qml63
-rw-r--r--examples/wayland/custom-extension/cpp-client/CMakeLists.txt3
-rw-r--r--examples/wayland/custom-extension/cpp-client/main.cpp26
-rw-r--r--examples/wayland/custom-extension/doc/images/custom-extension.pngbin0 -> 64841 bytes
-rw-r--r--examples/wayland/custom-extension/doc/src/custom-extension.qdoc148
-rw-r--r--examples/wayland/custom-extension/qml-client/CMakeLists.txt11
-rw-r--r--examples/wayland/custom-extension/qml-client/main.cpp7
-rw-r--r--examples/wayland/custom-extension/qml-client/main.qml91
-rw-r--r--examples/wayland/custom-extension/qml-client/qml-client.pro6
-rw-r--r--examples/wayland/custom-shell/CMakeLists.txt7
-rw-r--r--examples/wayland/custom-shell/client-plugin/CMakeLists.txt3
-rw-r--r--examples/wayland/custom-shell/compositor/CMakeLists.txt3
-rw-r--r--examples/wayland/custom-shell/compositor/main.cpp3
-rw-r--r--examples/wayland/custom-shell/doc/images/custom-shell.jpgbin0 -> 47699 bytes
-rw-r--r--examples/wayland/custom-shell/doc/src/custom-shell.qdoc15
-rw-r--r--examples/wayland/fancy-compositor/CMakeLists.txt (renamed from examples/wayland/pure-qml/CMakeLists.txt)21
-rw-r--r--examples/wayland/fancy-compositor/doc/src/fancy-compositor.qdoc (renamed from examples/wayland/pure-qml/doc/src/pure-qml.qdoc)57
-rw-r--r--examples/wayland/fancy-compositor/fancy-compositor.pro18
-rw-r--r--examples/wayland/fancy-compositor/fancy-compositor.qrc (renamed from examples/wayland/pure-qml/pure-qml.qrc)0
-rw-r--r--examples/wayland/fancy-compositor/images/background.jpg (renamed from examples/wayland/pure-qml/images/background.jpg)bin30730 -> 30730 bytes
-rw-r--r--examples/wayland/fancy-compositor/main.cpp (renamed from examples/wayland/pure-qml/main.cpp)0
-rw-r--r--examples/wayland/fancy-compositor/qml/Chrome.qml (renamed from examples/wayland/pure-qml/qml/Chrome.qml)0
-rw-r--r--examples/wayland/fancy-compositor/qml/CompositorScreen.qml (renamed from examples/wayland/pure-qml/qml/CompositorScreen.qml)0
-rw-r--r--examples/wayland/fancy-compositor/qml/Keyboard.qml (renamed from examples/wayland/pure-qml/qml/Keyboard.qml)0
-rw-r--r--examples/wayland/fancy-compositor/qml/main.qml (renamed from examples/wayland/pure-qml/qml/main.qml)6
-rw-r--r--examples/wayland/ivi-compositor/CMakeLists.txt3
-rw-r--r--examples/wayland/ivi-compositor/doc/src/ivi-compositor.qdoc7
-rw-r--r--examples/wayland/ivi-compositor/main.qml5
-rw-r--r--examples/wayland/minimal-cpp/CMakeLists.txt3
-rw-r--r--examples/wayland/minimal-cpp/compositor.cpp20
-rw-r--r--examples/wayland/minimal-cpp/compositor.h2
-rw-r--r--examples/wayland/minimal-cpp/doc/images/minimal-cpp.jpgbin0 -> 34734 bytes
-rw-r--r--examples/wayland/minimal-cpp/doc/src/minimal-cpp.qdoc67
-rw-r--r--examples/wayland/minimal-cpp/window.cpp6
-rw-r--r--examples/wayland/minimal-qml/CMakeLists.txt3
-rw-r--r--examples/wayland/minimal-qml/doc/src/minimal-qml.qdoc7
-rw-r--r--examples/wayland/minimal-qml/main.qml10
-rw-r--r--examples/wayland/multi-output/CMakeLists.txt3
-rw-r--r--examples/wayland/multi-output/doc/src/multi-output.qdoc8
-rw-r--r--examples/wayland/multi-output/qml/ShellScreen.qml2
-rw-r--r--examples/wayland/multi-output/qml/main.qml5
-rw-r--r--examples/wayland/multi-screen/CMakeLists.txt3
-rw-r--r--examples/wayland/multi-screen/doc/images/multi-screen.jpgbin0 -> 61459 bytes
-rw-r--r--examples/wayland/multi-screen/doc/src/multi-screen.qdoc11
-rw-r--r--examples/wayland/multi-screen/qml/Chrome.qml1
-rw-r--r--examples/wayland/multi-screen/qml/CompositorScreen.qml2
-rw-r--r--examples/wayland/multi-screen/qml/main.qml7
-rw-r--r--examples/wayland/overview-compositor/CMakeLists.txt3
-rw-r--r--examples/wayland/overview-compositor/doc/src/overview-compositor.qdoc8
-rw-r--r--examples/wayland/overview-compositor/main.qml4
-rw-r--r--examples/wayland/pure-qml/pure-qml.pro18
-rw-r--r--examples/wayland/qtshell/CMakeLists.txt3
-rw-r--r--examples/wayland/qtshell/doc/images/qtshell.jpgbin0 -> 148259 bytes
-rw-r--r--examples/wayland/qtshell/doc/src/qtshell.qdoc7
-rw-r--r--examples/wayland/qtshell/qml/main.qml2
-rw-r--r--examples/wayland/server-buffer/CMakeLists.txt2
-rw-r--r--examples/wayland/server-side-decoration/CMakeLists.txt3
-rw-r--r--examples/wayland/server-side-decoration/doc/src/server-side-decoration.qdoc5
-rw-r--r--examples/wayland/server-side-decoration/main.qml2
-rw-r--r--examples/wayland/spanning-screens/CMakeLists.txt3
-rw-r--r--examples/wayland/spanning-screens/doc/src/spanning-screens.qdoc12
-rw-r--r--examples/wayland/spanning-screens/main.qml2
-rw-r--r--examples/wayland/wayland.pro8
-rw-r--r--qt_cmdline.cmake3
-rw-r--r--src/3rdparty/protocol/cursor-shape-v1.xml146
-rw-r--r--src/3rdparty/protocol/fractional-scale-v1.xml102
-rw-r--r--src/3rdparty/protocol/qt_attribution.json70
-rw-r--r--src/3rdparty/protocol/text-input-unstable-v3.xml (renamed from src/3rdparty/protocol/text-input-unstable-v4-wip.xml)90
-rw-r--r--src/3rdparty/protocol/wayland.xml367
-rw-r--r--src/3rdparty/protocol/xdg-dialog-v1.xml110
-rw-r--r--src/3rdparty/protocol/xdg-foreign-unstable-v2.xml200
-rw-r--r--src/3rdparty/protocol/xdg-shell.xml347
-rw-r--r--src/3rdparty/protocol/xdg-toplevel-drag-v1.xml141
-rw-r--r--src/CMakeLists.txt34
-rw-r--r--src/client/CMakeLists.txt26
-rw-r--r--src/client/Qt6WaylandClientMacros.cmake38
-rw-r--r--src/client/configure.cmake3
-rw-r--r--src/client/doc/qtwaylandclient.qdocconf31
-rw-r--r--src/client/doc/src/cmake/qt_generate_wayland_protocol_client_sources.qdoc50
-rw-r--r--src/client/doc/src/qtwaylandclient-overview.qdoc36
-rw-r--r--src/client/global/qwaylandclientextension.cpp9
-rw-r--r--src/client/global/qwaylandclientextension.h25
-rw-r--r--src/client/hardwareintegration/qwaylandclientbufferintegrationfactory.cpp6
-rw-r--r--src/client/hardwareintegration/qwaylandserverbufferintegrationfactory.cpp6
-rw-r--r--src/client/inputdeviceintegration/qwaylandinputdeviceintegrationfactory.cpp6
-rw-r--r--src/client/qwaylandbuffer_p.h2
-rw-r--r--src/client/qwaylandclipboard.cpp27
-rw-r--r--src/client/qwaylandclipboard_p.h1
-rw-r--r--src/client/qwaylandcursor.cpp98
-rw-r--r--src/client/qwaylandcursor_p.h11
-rw-r--r--src/client/qwaylanddatadevice.cpp71
-rw-r--r--src/client/qwaylanddatadevice_p.h6
-rw-r--r--src/client/qwaylanddataoffer.cpp91
-rw-r--r--src/client/qwaylanddatasource.cpp13
-rw-r--r--src/client/qwaylanddatasource_p.h2
-rw-r--r--src/client/qwaylanddecorationfactory.cpp6
-rw-r--r--src/client/qwaylanddisplay.cpp439
-rw-r--r--src/client/qwaylanddisplay_p.h177
-rw-r--r--src/client/qwaylanddnd.cpp5
-rw-r--r--src/client/qwaylandfractionalscale.cpp31
-rw-r--r--src/client/qwaylandfractionalscale_p.h52
-rw-r--r--src/client/qwaylandinputcontext.cpp78
-rw-r--r--src/client/qwaylandinputdevice.cpp234
-rw-r--r--src/client/qwaylandinputdevice_p.h39
-rw-r--r--src/client/qwaylandinputmethodcontext.cpp8
-rw-r--r--src/client/qwaylandintegration.cpp96
-rw-r--r--src/client/qwaylandintegration_p.h10
-rw-r--r--src/client/qwaylandnativeinterface.cpp95
-rw-r--r--src/client/qwaylandnativeinterface_p.h25
-rw-r--r--src/client/qwaylandpointergestures.cpp31
-rw-r--r--src/client/qwaylandpointergestures_p.h1
-rw-r--r--src/client/qwaylandprimaryselectionv1.cpp10
-rw-r--r--src/client/qwaylandprimaryselectionv1_p.h3
-rw-r--r--src/client/qwaylandqtkey.cpp5
-rw-r--r--src/client/qwaylandqtkey_p.h1
-rw-r--r--src/client/qwaylandscreen.cpp109
-rw-r--r--src/client/qwaylandscreen_p.h20
-rw-r--r--src/client/qwaylandshellsurface_p.h13
-rw-r--r--src/client/qwaylandshm.cpp2
-rw-r--r--src/client/qwaylandshmbackingstore.cpp114
-rw-r--r--src/client/qwaylandshmbackingstore_p.h9
-rw-r--r--src/client/qwaylandsurface.cpp16
-rw-r--r--src/client/qwaylandsurface_p.h12
-rw-r--r--src/client/qwaylandtabletv2.cpp22
-rw-r--r--src/client/qwaylandtabletv2_p.h7
-rw-r--r--src/client/qwaylandtextinputv1.cpp11
-rw-r--r--src/client/qwaylandtextinputv2.cpp22
-rw-r--r--src/client/qwaylandtextinputv3.cpp (renamed from src/client/qwaylandtextinputv4.cpp)88
-rw-r--r--src/client/qwaylandtextinputv3_p.h (renamed from src/client/qwaylandtextinputv4_p.h)34
-rw-r--r--src/client/qwaylandtouch.cpp13
-rw-r--r--src/client/qwaylandtouch_p.h1
-rw-r--r--src/client/qwaylandviewport.cpp35
-rw-r--r--src/client/qwaylandviewport_p.h42
-rw-r--r--src/client/qwaylandvulkaninstance.cpp20
-rw-r--r--src/client/qwaylandvulkaninstance_p.h3
-rw-r--r--src/client/qwaylandvulkanwindow.cpp19
-rw-r--r--src/client/qwaylandvulkanwindow_p.h3
-rw-r--r--src/client/qwaylandwindow.cpp687
-rw-r--r--src/client/qwaylandwindow_p.h96
-rw-r--r--src/client/qwaylandwindowmanagerintegration.cpp16
-rw-r--r--src/client/qwaylandwindowmanagerintegration_p.h1
-rw-r--r--src/client/shellintegration/qwaylandshellintegrationfactory.cpp6
-rw-r--r--src/compositor/CMakeLists.txt23
-rw-r--r--src/compositor/Qt6WaylandCompositorMacros.cmake11
-rw-r--r--src/compositor/compositor_api/qwaylandbufferref.h2
-rw-r--r--src/compositor/compositor_api/qwaylandclient.cpp12
-rw-r--r--src/compositor/compositor_api/qwaylandclient.h6
-rw-r--r--src/compositor/compositor_api/qwaylandcompositor.cpp49
-rw-r--r--src/compositor/compositor_api/qwaylandcompositor.h9
-rw-r--r--src/compositor/compositor_api/qwaylandcompositor_p.h2
-rw-r--r--src/compositor/compositor_api/qwaylandcompositorquickextensions_p.h8
-rw-r--r--src/compositor/compositor_api/qwaylandinputmethodcontrol.cpp64
-rw-r--r--src/compositor/compositor_api/qwaylandinputmethodcontrol.h2
-rw-r--r--src/compositor/compositor_api/qwaylandinputmethodcontrol_p.h8
-rw-r--r--src/compositor/compositor_api/qwaylandkeyboard.cpp2
-rw-r--r--src/compositor/compositor_api/qwaylandkeymap.h4
-rw-r--r--src/compositor/compositor_api/qwaylandmousetracker_p.h2
-rw-r--r--src/compositor/compositor_api/qwaylandoutput.cpp24
-rw-r--r--src/compositor/compositor_api/qwaylandoutput.h6
-rw-r--r--src/compositor/compositor_api/qwaylandoutput_p.h1
-rw-r--r--src/compositor/compositor_api/qwaylandpointer_p.h2
-rw-r--r--src/compositor/compositor_api/qwaylandquickcompositor.cpp2
-rw-r--r--src/compositor/compositor_api/qwaylandquickhardwarelayer.cpp2
-rw-r--r--src/compositor/compositor_api/qwaylandquickitem.cpp110
-rw-r--r--src/compositor/compositor_api/qwaylandquickitem.h1
-rw-r--r--src/compositor/compositor_api/qwaylandquickitem_p.h3
-rw-r--r--src/compositor/compositor_api/qwaylandquickoutput.cpp2
-rw-r--r--src/compositor/compositor_api/qwaylandquicksurface.cpp2
-rw-r--r--src/compositor/compositor_api/qwaylandresource.cpp2
-rw-r--r--src/compositor/compositor_api/qwaylandseat.cpp138
-rw-r--r--src/compositor/compositor_api/qwaylandseat.h5
-rw-r--r--src/compositor/compositor_api/qwaylandsurface.cpp87
-rw-r--r--src/compositor/compositor_api/qwaylandsurface_p.h6
-rw-r--r--src/compositor/compositor_api/qwaylandtouch.cpp4
-rw-r--r--src/compositor/compositor_api/qwaylandview.cpp9
-rw-r--r--src/compositor/configure.cmake3
-rw-r--r--src/compositor/doc/qtwaylandcompositor.qdocconf21
-rw-r--r--src/compositor/doc/src/cmake/qt_generate_wayland_protocol_server_sources.qdoc47
-rw-r--r--src/compositor/doc/src/qtwaylandcompositor-cpp.qdoc18
-rw-r--r--src/compositor/doc/src/qtwaylandcompositor-overview.qdoc9
-rw-r--r--src/compositor/doc/src/qtwaylandcompositor-qmltypes.qdoc24
-rw-r--r--src/compositor/doc/src/qtwaylandcompositor-shellextensions.qdoc7
-rw-r--r--src/compositor/extensions/qwaylandidleinhibitv1_p.h2
-rw-r--r--src/compositor/extensions/qwaylandiviapplication.cpp4
-rw-r--r--src/compositor/extensions/qwaylandivisurface.cpp8
-rw-r--r--src/compositor/extensions/qwaylandivisurface.h4
-rw-r--r--src/compositor/extensions/qwaylandivisurface_p.h4
-rw-r--r--src/compositor/extensions/qwaylandpresentationtime.cpp2
-rw-r--r--src/compositor/extensions/qwaylandpresentationtime_p.h13
-rw-r--r--src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp55
-rw-r--r--src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h2
-rw-r--r--src/compositor/extensions/qwaylandshell.cpp2
-rw-r--r--src/compositor/extensions/qwaylandshellsurface.cpp50
-rw-r--r--src/compositor/extensions/qwaylandshellsurface.h18
-rw-r--r--src/compositor/extensions/qwaylandshellsurface_p.h32
-rw-r--r--src/compositor/extensions/qwaylandtextinput.cpp6
-rw-r--r--src/compositor/extensions/qwaylandtextinputmanagerv3.cpp (renamed from src/compositor/extensions/qwaylandtextinputmanagerv4.cpp)56
-rw-r--r--src/compositor/extensions/qwaylandtextinputmanagerv3.h (renamed from src/compositor/extensions/qwaylandtextinputmanagerv4.h)18
-rw-r--r--src/compositor/extensions/qwaylandtextinputmanagerv3_p.h (renamed from src/compositor/extensions/qwaylandtextinputmanagerv4_p.h)16
-rw-r--r--src/compositor/extensions/qwaylandtextinputv3.cpp (renamed from src/compositor/extensions/qwaylandtextinputv4.cpp)129
-rw-r--r--src/compositor/extensions/qwaylandtextinputv3.h (renamed from src/compositor/extensions/qwaylandtextinputv4.h)16
-rw-r--r--src/compositor/extensions/qwaylandtextinputv3_p.h (renamed from src/compositor/extensions/qwaylandtextinputv4_p.h)53
-rw-r--r--src/compositor/extensions/qwaylandviewporter_p.h2
-rw-r--r--src/compositor/extensions/qwaylandwlshell.cpp20
-rw-r--r--src/compositor/extensions/qwaylandwlshell.h4
-rw-r--r--src/compositor/extensions/qwaylandwlshell_p.h6
-rw-r--r--src/compositor/extensions/qwaylandwlshellintegration_p.h2
-rw-r--r--src/compositor/extensions/qwaylandxdgdecorationv1.cpp5
-rw-r--r--src/compositor/extensions/qwaylandxdgdialogv1.cpp64
-rw-r--r--src/compositor/extensions/qwaylandxdgdialogv1_p.h57
-rw-r--r--src/compositor/extensions/qwaylandxdgoutputv1.cpp14
-rw-r--r--src/compositor/extensions/qwaylandxdgoutputv1.h7
-rw-r--r--src/compositor/extensions/qwaylandxdgshell.cpp127
-rw-r--r--src/compositor/extensions/qwaylandxdgshell.h17
-rw-r--r--src/compositor/extensions/qwaylandxdgshell_p.h5
-rw-r--r--src/compositor/extensions/qwaylandxdgshellintegration.cpp42
-rw-r--r--src/compositor/extensions/qwaylandxdgshellintegration_p.h4
-rw-r--r--src/compositor/extensions/qwlqttouch.cpp4
-rw-r--r--src/compositor/extensions/qwltexturesharingextension.cpp12
-rw-r--r--src/compositor/extensions/qwltexturesharingextension_p.h6
-rw-r--r--src/compositor/global/qwaylandcompositorextension.cpp8
-rw-r--r--src/compositor/global/qwaylandquickextension.h4
-rw-r--r--src/compositor/global/qwaylandquickextension.qdoc4
-rw-r--r--src/compositor/hardware_integration/qwlclientbufferintegrationfactory.cpp6
-rw-r--r--src/compositor/hardware_integration/qwlhardwarelayerintegrationfactory.cpp6
-rw-r--r--src/compositor/hardware_integration/qwlserverbufferintegrationfactory.cpp6
-rw-r--r--src/compositor/hardware_integration/qwltextureorphanage.cpp108
-rw-r--r--src/compositor/hardware_integration/qwltextureorphanage_p.h64
-rw-r--r--src/compositor/qmlfiles/WaylandCursorItem.qml6
-rw-r--r--src/compositor/shaders/surface.vert3
-rw-r--r--src/compositor/shaders/surface_oes_external.frag3
-rw-r--r--src/compositor/shaders/surface_rgba.frag3
-rw-r--r--src/compositor/shaders/surface_rgbx.frag3
-rw-r--r--src/compositor/shaders/surface_y_u_v.frag3
-rw-r--r--src/compositor/shaders/surface_y_uv.frag3
-rw-r--r--src/compositor/shaders/surface_y_xuxv.frag3
-rw-r--r--src/compositor/wayland_wrapper/qwldatadevicemanager.cpp4
-rw-r--r--src/configure.cmake37
-rw-r--r--src/hardwareintegration/CMakeLists.txt3
-rw-r--r--src/hardwareintegration/client/CMakeLists.txt3
-rw-r--r--src/hardwareintegration/client/shm-emulation-server/shmserverbufferintegration.cpp2
-rw-r--r--src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.cpp20
-rw-r--r--src/hardwareintegration/client/wayland-egl/CMakeLists.txt4
-rw-r--r--src/hardwareintegration/client/wayland-egl/qwaylandeglclientbufferintegration.cpp7
-rw-r--r--src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp18
-rw-r--r--src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp23
-rw-r--r--src/hardwareintegration/client/wayland-egl/qwaylandglcontext_p.h1
-rw-r--r--src/hardwareintegration/compositor/CMakeLists.txt3
-rw-r--r--src/hardwareintegration/compositor/dmabuf-server/dmabufserverbufferintegration.cpp2
-rw-r--r--src/hardwareintegration/compositor/drm-egl-server/drmeglserverbufferintegration.cpp2
-rw-r--r--src/hardwareintegration/compositor/hardwarelayer/vsp2/vsp2hardwarelayerintegration.cpp4
-rw-r--r--src/hardwareintegration/compositor/hardwarelayer/vsp2/vsp2hardwarelayerintegration.h2
-rw-r--r--src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.cpp45
-rw-r--r--src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.h6
-rw-r--r--src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp10
-rw-r--r--src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.h5
-rw-r--r--src/hardwareintegration/compositor/shm-emulation-server/shmserverbufferintegration.cpp8
-rw-r--r--src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.cpp16
-rw-r--r--src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp34
-rw-r--r--src/hardwareintegration/compositor/wayland-egl/CMakeLists.txt4
-rw-r--r--src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp98
-rw-r--r--src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.cpp90
-rw-r--r--src/imports/CMakeLists.txt3
-rw-r--r--src/imports/compositor-extensions/CMakeLists.txt3
-rw-r--r--src/imports/compositor-extensions/iviapplication/CMakeLists.txt6
-rw-r--r--src/imports/compositor-extensions/presentationtime/CMakeLists.txt7
-rw-r--r--src/imports/compositor-extensions/qtshell/CMakeLists.txt6
-rw-r--r--src/imports/compositor-extensions/qtshell/qwaylandqtshell.cpp42
-rw-r--r--src/imports/compositor-extensions/qtshell/qwaylandqtshell_p.h4
-rw-r--r--src/imports/compositor-extensions/qtshell/qwaylandqtshellchrome.cpp52
-rw-r--r--src/imports/compositor-extensions/wlshell/CMakeLists.txt6
-rw-r--r--src/imports/compositor-extensions/xdgshell/CMakeLists.txt6
-rw-r--r--src/imports/texture-sharing-extension/CMakeLists.txt5
-rw-r--r--src/imports/texture-sharing/CMakeLists.txt8
-rw-r--r--src/imports/texture-sharing/sharedtextureprovider.cpp3
-rw-r--r--src/imports/texture-sharing/sharedtextureprovider_p.h6
-rw-r--r--src/imports/texture-sharing/texturesharingextension_p.h4
-rw-r--r--src/plugins/CMakeLists.txt3
-rw-r--r--src/plugins/decorations/CMakeLists.txt6
-rw-r--r--src/plugins/decorations/adwaita/CMakeLists.txt25
-rw-r--r--src/plugins/decorations/adwaita/adwaita.json3
-rw-r--r--src/plugins/decorations/adwaita/main.cpp36
-rw-r--r--src/plugins/decorations/adwaita/qwaylandadwaitadecoration.cpp731
-rw-r--r--src/plugins/decorations/adwaita/qwaylandadwaitadecoration_p.h155
-rw-r--r--src/plugins/decorations/bradient/CMakeLists.txt3
-rw-r--r--src/plugins/decorations/bradient/main.cpp181
-rw-r--r--src/plugins/hardwareintegration/CMakeLists.txt9
-rw-r--r--src/plugins/hardwareintegration/client/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/client/brcm-egl/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/client/dmabuf-server/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/client/drm-egl-server/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/client/libhybris-egl-server/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/client/shm-emulation-server/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/client/vulkan-server/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/client/wayland-egl/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/compositor/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/compositor/brcm-egl/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/compositor/dmabuf-server/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/compositor/drm-egl-server/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/compositor/hardwarelayer/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/compositor/hardwarelayer/vsp2/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/compositor/libhybris-egl-server/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/compositor/shm-emulation-server/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/compositor/vulkan-server/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/compositor/wayland-egl/CMakeLists.txt3
-rw-r--r--src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/CMakeLists.txt3
-rw-r--r--src/plugins/platforms/CMakeLists.txt3
-rw-r--r--src/plugins/platforms/qwayland-brcm-egl/CMakeLists.txt3
-rw-r--r--src/plugins/platforms/qwayland-brcm-egl/main.cpp2
-rw-r--r--src/plugins/platforms/qwayland-egl/CMakeLists.txt3
-rw-r--r--src/plugins/platforms/qwayland-egl/main.cpp2
-rw-r--r--src/plugins/platforms/qwayland-generic/CMakeLists.txt3
-rw-r--r--src/plugins/platforms/qwayland-generic/main.cpp2
-rw-r--r--src/plugins/shellintegration/CMakeLists.txt3
-rw-r--r--src/plugins/shellintegration/fullscreen-shell-v1/CMakeLists.txt3
-rw-r--r--src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.cpp24
-rw-r--r--src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.h10
-rw-r--r--src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.h1
-rw-r--r--src/plugins/shellintegration/ivi-shell/CMakeLists.txt3
-rw-r--r--src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.cpp31
-rw-r--r--src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.h8
-rw-r--r--src/plugins/shellintegration/ivi-shell/qwaylandivisurface_p.h3
-rw-r--r--src/plugins/shellintegration/qt-shell/CMakeLists.txt3
-rw-r--r--src/plugins/shellintegration/qt-shell/qwaylandqtsurface_p.h3
-rw-r--r--src/plugins/shellintegration/wl-shell/CMakeLists.txt6
-rw-r--r--src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration.cpp23
-rw-r--r--src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration_p.h9
-rw-r--r--src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface_p.h2
-rw-r--r--src/plugins/shellintegration/xdg-shell/CMakeLists.txt7
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgactivationv1.cpp11
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgactivationv1_p.h4
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgdialogv1.cpp33
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgdialogv1_p.h32
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgexporterv2.cpp41
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgexporterv2_p.h49
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp422
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h44
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp37
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h19
-rw-r--r--src/qtwaylandscanner/CMakeLists.txt3
-rw-r--r--src/qtwaylandscanner/qtwaylandscanner.cpp46
-rw-r--r--src/shared/qwaylandinputmethodeventbuilder.cpp64
-rw-r--r--src/shared/qwaylandinputmethodeventbuilder_p.h2
-rw-r--r--src/shared/qwaylandmimehelper.cpp4
-rw-r--r--src/shared/qwaylandsharedmemoryformathelper_p.h9
-rw-r--r--sync.profile108
-rw-r--r--tests/CMakeLists.txt3
-rw-r--r--tests/auto/CMakeLists.txt5
-rw-r--r--tests/auto/client/CMakeLists.txt44
-rw-r--r--tests/auto/client/client/CMakeLists.txt5
-rw-r--r--tests/auto/client/client/tst_client.cpp40
-rw-r--r--tests/auto/client/clientextension/CMakeLists.txt5
-rw-r--r--tests/auto/client/clientextension/tst_clientextension.cpp41
-rw-r--r--tests/auto/client/cursor/CMakeLists.txt11
-rw-r--r--tests/auto/client/cursor/cursorshapev1.cpp47
-rw-r--r--tests/auto/client/cursor/cursorshapev1.h44
-rw-r--r--tests/auto/client/cursor/tst_cursor.cpp103
-rw-r--r--tests/auto/client/datadevicev1/CMakeLists.txt5
-rw-r--r--tests/auto/client/datadevicev1/tst_datadevicev1.cpp99
-rw-r--r--tests/auto/client/fullscreenshellv1/CMakeLists.txt5
-rw-r--r--tests/auto/client/fullscreenshellv1/tst_fullscreenshellv1.cpp4
-rw-r--r--tests/auto/client/inputcontext/CMakeLists.txt5
-rw-r--r--tests/auto/client/inputcontext/tst_inputcontext.cpp13
-rw-r--r--tests/auto/client/iviapplication/CMakeLists.txt5
-rw-r--r--tests/auto/client/iviapplication/tst_iviapplication.cpp6
-rw-r--r--tests/auto/client/multithreaded/CMakeLists.txt5
-rw-r--r--tests/auto/client/multithreaded/tst_multithreaded.cpp2
-rw-r--r--tests/auto/client/nooutput/CMakeLists.txt5
-rw-r--r--tests/auto/client/nooutput/tst_nooutput.cpp4
-rw-r--r--tests/auto/client/output/CMakeLists.txt5
-rw-r--r--tests/auto/client/output/tst_output.cpp30
-rw-r--r--tests/auto/client/primaryselectionv1/CMakeLists.txt5
-rw-r--r--tests/auto/client/primaryselectionv1/tst_primaryselectionv1.cpp28
-rw-r--r--tests/auto/client/reconnect/CMakeLists.txt11
-rw-r--r--tests/auto/client/reconnect/tst_reconnect.cpp253
-rw-r--r--tests/auto/client/reconnect/wl-socket.c166
-rw-r--r--tests/auto/client/reconnect/wl-socket.h34
-rw-r--r--tests/auto/client/scaling/CMakeLists.txt10
-rw-r--r--tests/auto/client/scaling/tst_scaling.cpp134
-rw-r--r--tests/auto/client/seat/CMakeLists.txt5
-rw-r--r--tests/auto/client/seat/tst_seat.cpp170
-rw-r--r--tests/auto/client/seatv4/BLACKLIST3
-rw-r--r--tests/auto/client/seatv4/CMakeLists.txt7
-rw-r--r--tests/auto/client/seatv4/tst_seatv4.cpp25
-rw-r--r--tests/auto/client/seatv7/CMakeLists.txt13
-rw-r--r--tests/auto/client/seatv7/tst_seatv7.cpp129
-rw-r--r--tests/auto/client/shared/CMakeLists.txt19
-rw-r--r--tests/auto/client/shared/corecompositor.cpp18
-rw-r--r--tests/auto/client/shared/corecompositor.h12
-rw-r--r--tests/auto/client/shared/coreprotocol.cpp53
-rw-r--r--tests/auto/client/shared/coreprotocol.h17
-rw-r--r--tests/auto/client/shared/datadevice.cpp15
-rw-r--r--tests/auto/client/shared/datadevice.h4
-rw-r--r--tests/auto/client/shared/fractionalscalev1.cpp40
-rw-r--r--tests/auto/client/shared/fractionalscalev1.h39
-rw-r--r--tests/auto/client/shared/fullscreenshellv1.cpp2
-rw-r--r--tests/auto/client/shared/fullscreenshellv1.h2
-rw-r--r--tests/auto/client/shared/iviapplication.cpp4
-rw-r--r--tests/auto/client/shared/iviapplication.h2
-rw-r--r--tests/auto/client/shared/mockcompositor.cpp25
-rw-r--r--tests/auto/client/shared/mockcompositor.h11
-rw-r--r--tests/auto/client/shared/qttextinput.cpp2
-rw-r--r--tests/auto/client/shared/qttextinput.h2
-rw-r--r--tests/auto/client/shared/textinput.cpp5
-rw-r--r--tests/auto/client/shared/textinput.h2
-rw-r--r--tests/auto/client/shared/viewport.cpp58
-rw-r--r--tests/auto/client/shared/viewport.h50
-rw-r--r--tests/auto/client/shared/xdgdialog.cpp59
-rw-r--r--tests/auto/client/shared/xdgdialog.h49
-rw-r--r--tests/auto/client/shared/xdgoutputv1.cpp2
-rw-r--r--tests/auto/client/shared/xdgoutputv1.h2
-rw-r--r--tests/auto/client/shared/xdgshell.cpp11
-rw-r--r--tests/auto/client/shared/xdgshell.h5
-rw-r--r--tests/auto/client/surface/CMakeLists.txt5
-rw-r--r--tests/auto/client/surface/tst_surface.cpp49
-rw-r--r--tests/auto/client/tabletv2/CMakeLists.txt5
-rw-r--r--tests/auto/client/tabletv2/tst_tabletv2.cpp2
-rw-r--r--tests/auto/client/wl_connect/CMakeLists.txt5
-rw-r--r--tests/auto/client/wl_connect/tst_wlconnect.cpp2
-rw-r--r--tests/auto/client/xdgdecorationv1/CMakeLists.txt5
-rw-r--r--tests/auto/client/xdgdecorationv1/tst_xdgdecorationv1.cpp9
-rw-r--r--tests/auto/client/xdgoutput/CMakeLists.txt5
-rw-r--r--tests/auto/client/xdgoutput/tst_xdgoutput.cpp56
-rw-r--r--tests/auto/client/xdgshell/CMakeLists.txt5
-rw-r--r--tests/auto/client/xdgshell/tst_xdgshell.cpp351
-rw-r--r--tests/auto/cmake/CMakeLists.txt17
-rw-r--r--tests/auto/cmake/test_waylandclient/CMakeLists.txt11
-rw-r--r--tests/auto/compositor/CMakeLists.txt3
-rw-r--r--tests/auto/compositor/compositor/CMakeLists.txt7
-rw-r--r--tests/auto/compositor/compositor/mockclient.cpp16
-rw-r--r--tests/auto/compositor/compositor/mockclient.h4
-rw-r--r--tests/auto/compositor/compositor/mockkeyboard.cpp5
-rw-r--r--tests/auto/compositor/compositor/mockkeyboard.h2
-rw-r--r--tests/auto/compositor/compositor/mockpointer.cpp5
-rw-r--r--tests/auto/compositor/compositor/mockpointer.h2
-rw-r--r--tests/auto/compositor/compositor/mockseat.cpp2
-rw-r--r--tests/auto/compositor/compositor/mockseat.h2
-rw-r--r--tests/auto/compositor/compositor/mockxdgoutputv1.cpp2
-rw-r--r--tests/auto/compositor/compositor/mockxdgoutputv1.h2
-rw-r--r--tests/auto/compositor/compositor/testcompositor.cpp2
-rw-r--r--tests/auto/compositor/compositor/testcompositor.h2
-rw-r--r--tests/auto/compositor/compositor/testkeyboardgrabber.cpp2
-rw-r--r--tests/auto/compositor/compositor/testkeyboardgrabber.h2
-rw-r--r--tests/auto/compositor/compositor/testseat.cpp2
-rw-r--r--tests/auto/compositor/compositor/testseat.h2
-rw-r--r--tests/auto/compositor/compositor/tst_compositor.cpp119
-rw-r--r--tests/manual/CMakeLists.txt8
-rw-r--r--tests/manual/hwlayer-compositor/.gitignore (renamed from examples/wayland/hwlayer-compositor/.gitignore)0
-rw-r--r--tests/manual/hwlayer-compositor/CMakeLists.txt (renamed from examples/wayland/hwlayer-compositor/CMakeLists.txt)3
-rw-r--r--tests/manual/hwlayer-compositor/hwlayer-compositor.pro (renamed from examples/wayland/hwlayer-compositor/hwlayer-compositor.pro)0
-rw-r--r--tests/manual/hwlayer-compositor/hwlayer-compositor.qrc (renamed from examples/wayland/hwlayer-compositor/hwlayer-compositor.qrc)0
-rw-r--r--tests/manual/hwlayer-compositor/main.cpp (renamed from examples/wayland/hwlayer-compositor/main.cpp)2
-rw-r--r--tests/manual/hwlayer-compositor/main.qml (renamed from examples/wayland/hwlayer-compositor/main.qml)68
-rw-r--r--tests/manual/keymap/keymapcompositor.qml2
-rw-r--r--tests/manual/qmlclient/CMakeLists.txt5
-rw-r--r--tests/manual/qmlclient/main.cpp2
-rw-r--r--tests/manual/qmlclient/main.qml2
-rw-r--r--tests/manual/qt-shell/CMakeLists.txt3
-rw-r--r--tests/manual/qt-shell/main.cpp2
-rw-r--r--tests/manual/qt-shell/qml/Chrome.qml2
-rw-r--r--tests/manual/qt-shell/qml/CompositorScreen.qml2
-rw-r--r--tests/manual/qt-shell/qml/HandleHandler.qml2
-rw-r--r--tests/manual/qt-shell/qml/Keyboard.qml2
-rw-r--r--tests/manual/qt-shell/qml/main.qml2
-rw-r--r--tests/manual/scaling-compositor/CMakeLists.txt5
-rw-r--r--tests/manual/scaling-compositor/main.cpp2
-rw-r--r--tests/manual/scaling-compositor/main.qml2
-rw-r--r--tests/manual/server-buffer/CMakeLists.txt5
-rw-r--r--tests/manual/server-buffer/README (renamed from examples/wayland/server-buffer/README)2
-rw-r--r--tests/manual/server-buffer/compositor/CMakeLists.txt (renamed from examples/wayland/server-buffer/compositor/CMakeLists.txt)3
-rw-r--r--tests/manual/server-buffer/compositor/compositor.pro (renamed from examples/wayland/server-buffer/compositor/compositor.pro)0
-rw-r--r--tests/manual/server-buffer/compositor/compositor.qrc (renamed from examples/wayland/server-buffer/compositor/compositor.qrc)0
-rw-r--r--tests/manual/server-buffer/compositor/images/Siberischer_tiger_de_edit02.jpg (renamed from examples/wayland/server-buffer/compositor/images/Siberischer_tiger_de_edit02.jpg)bin21801 -> 21801 bytes
-rw-r--r--tests/manual/server-buffer/compositor/images/Siberischer_tiger_de_edit02.txt (renamed from examples/wayland/server-buffer/compositor/images/Siberischer_tiger_de_edit02.txt)0
-rw-r--r--tests/manual/server-buffer/compositor/images/background.png (renamed from examples/wayland/server-buffer/compositor/images/background.png)bin9528 -> 9528 bytes
-rw-r--r--tests/manual/server-buffer/compositor/main.cpp (renamed from examples/wayland/server-buffer/compositor/main.cpp)2
-rw-r--r--tests/manual/server-buffer/compositor/qml/main.qml (renamed from examples/wayland/server-buffer/compositor/qml/main.qml)7
-rw-r--r--tests/manual/server-buffer/compositor/sharebufferextension.cpp (renamed from examples/wayland/server-buffer/compositor/sharebufferextension.cpp)4
-rw-r--r--tests/manual/server-buffer/compositor/sharebufferextension.h (renamed from examples/wayland/server-buffer/compositor/sharebufferextension.h)2
-rw-r--r--tests/manual/server-buffer/cpp-client/CMakeLists.txt (renamed from examples/wayland/server-buffer/cpp-client/CMakeLists.txt)3
-rw-r--r--tests/manual/server-buffer/cpp-client/cpp-client.pro (renamed from examples/wayland/server-buffer/cpp-client/cpp-client.pro)0
-rw-r--r--tests/manual/server-buffer/cpp-client/main.cpp (renamed from examples/wayland/server-buffer/cpp-client/main.cpp)2
-rw-r--r--tests/manual/server-buffer/cpp-client/sharebufferextension.cpp (renamed from examples/wayland/server-buffer/cpp-client/sharebufferextension.cpp)2
-rw-r--r--tests/manual/server-buffer/cpp-client/sharebufferextension.h (renamed from examples/wayland/server-buffer/cpp-client/sharebufferextension.h)2
-rw-r--r--tests/manual/server-buffer/server-buffer.pro (renamed from examples/wayland/server-buffer/server-buffer.pro)0
-rw-r--r--tests/manual/server-buffer/share-buffer.xml (renamed from examples/wayland/server-buffer/share-buffer.xml)2
-rw-r--r--tests/manual/subsurface/CMakeLists.txt5
-rw-r--r--tests/manual/subsurface/child.qml2
-rw-r--r--tests/manual/subsurface/main.cpp2
-rw-r--r--tests/manual/subsurface/main.qml2
-rw-r--r--tests/manual/subsurface/shmwindow.cpp2
-rw-r--r--tests/manual/subsurface/shmwindow.h2
-rw-r--r--tests/manual/texture-sharing-2/CMakeLists.txt3
-rw-r--r--tests/manual/texture-sharing-2/custom-compositor/CMakeLists.txt52
-rw-r--r--tests/manual/texture-sharing-2/custom-compositor/main.cpp2
-rw-r--r--tests/manual/texture-sharing-2/custom-compositor/qml/main.qml2
-rw-r--r--tests/manual/texture-sharing-2/minimal-compositor.qml2
-rw-r--r--tests/manual/texture-sharing-2/qml-client/CMakeLists.txt50
-rw-r--r--tests/manual/texture-sharing-2/qml-client/main.cpp2
-rw-r--r--tests/manual/texture-sharing-2/qml-client/main.qml2
-rw-r--r--tests/manual/texture-sharing/cpp-client/CMakeLists.txt8
-rw-r--r--tests/manual/texture-sharing/cpp-client/main.cpp4
-rw-r--r--tests/manual/wip-cpp-compositor/CMakeLists.txt5
-rw-r--r--tests/manual/wip-cpp-compositor/compositor.cpp2
-rw-r--r--tests/manual/wip-cpp-compositor/compositor.h2
-rw-r--r--tests/manual/wip-cpp-compositor/main.cpp2
-rw-r--r--tests/manual/wip-cpp-compositor/window.cpp2
-rw-r--r--tests/manual/wip-cpp-compositor/window.h2
532 files changed, 10683 insertions, 3047 deletions
diff --git a/.cmake.conf b/.cmake.conf
index 02aefcb27..dc1d7a924 100644
--- a/.cmake.conf
+++ b/.cmake.conf
@@ -1,2 +1,5 @@
-set(QT_REPO_MODULE_VERSION "6.5.0")
+set(QT_REPO_MODULE_VERSION "6.8.0")
set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1")
+set(QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_AS_CONST=1")
+list(APPEND QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_FOREACH=1")
+list(APPEND QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_CONTEXTLESS_CONNECT=1")
diff --git a/.gitignore b/.gitignore
index ecaf47a3b..4262e83ac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,7 +40,7 @@ examples/wayland/custom-extension/testapp/testapp
examples/wayland/minimal-cpp/minimal-cpp
examples/wayland/minimal-qml/minimal-qml
examples/wayland/multi-output/multi-output
-examples/wayland/pure-qml/pure-qml
+examples/wayland/fancy-compositor/fancy-compositor
examples/wayland/server-buffer/client/client
examples/wayland/server-buffer/compositor/compositor
examples/wayland/server-side-decoration/server-side-decoration
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0007697b9..c498e15b3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qtwayland.pro.
cmake_minimum_required(VERSION 3.16)
@@ -13,6 +16,7 @@ project(QtWayland # special case
find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS
BuildInternals
)
+qt_internal_project_setup()
if(NOT MACOS AND NOT QNX AND (ANDROID OR NOT LINUX))
message(NOTICE "Skipping the build as the condition \"LINUX OR MACOS OR QNX\" is not met.")
@@ -24,9 +28,11 @@ find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS
)
find_package(Qt6 ${PROJECT_VERSION} QUIET CONFIG OPTIONAL_COMPONENTS
+ DBus
Gui
OpenGL
Quick
+ Svg
)
# special case begin
diff --git a/cmake/FindWaylandkms.cmake b/cmake/FindWaylandkms.cmake
index 5eba3a047..280c0134f 100644
--- a/cmake/FindWaylandkms.cmake
+++ b/cmake/FindWaylandkms.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
if (TARGET PkgConfig::Waylandkms)
set(Waylandkms_FOUND 1)
return()
diff --git a/coin/axivion/ci_config_linux.json b/coin/axivion/ci_config_linux.json
new file mode 100644
index 000000000..d58bf1fff
--- /dev/null
+++ b/coin/axivion/ci_config_linux.json
@@ -0,0 +1,44 @@
+{
+ "Project": {
+ "BuildSystemIntegration": {
+ "child_order": [
+ "GCCSetup",
+ "CMake",
+ "LinkLibraries"
+ ]
+ },
+ "CMake": {
+ "_active": true,
+ "_copy_from": "CMakeIntegration",
+ "build_environment": {},
+ "build_options": "-j4",
+ "generate_options": "--fresh",
+ "generator": "Ninja"
+ },
+ "GCCSetup": {
+ "_active": true,
+ "_copy_from": "Command",
+ "build_command": "gccsetup --cc gcc --cxx g++ --config ../../../axivion/"
+ },
+ "LinkLibraries": {
+ "_active": true,
+ "_copy_from": "AxivionLinker",
+ "input_files": [
+ "build/lib/lib*.so*.ir",
+ "build/qml/*/*/*/lib*.so*.ir"
+ ],
+ "ir": "build/$(env:TESTED_MODULE_COIN).ir",
+ "plugin_files": [
+ "build/plugins/*/lib*.so*.ir"
+ ]
+ }
+ },
+ "_Format": "1.0",
+ "_Version": "7.6.2",
+ "_VersionNum": [
+ 7,
+ 6,
+ 2,
+ 12725
+ ]
+}
diff --git a/coin/module_config.yaml b/coin/module_config.yaml
index ab895bf39..6ec20569e 100644
--- a/coin/module_config.yaml
+++ b/coin/module_config.yaml
@@ -21,8 +21,4 @@ instructions:
in_values: ["Windows", "MacOS"]
- condition: property
property: target.os
- in_values: ["IOS", "Android", "WebAssembly"]
- - type: EnvironmentVariable
- variableName: Dummy
- variableValue: dummy
-
+ in_values: ["QNX", "IOS", "Android", "WebAssembly"]
diff --git a/coin/qt-installer-package-config.json b/coin/qt-installer-package-config.json
index 2737a1947..89beb4b43 100644
--- a/coin/qt-installer-package-config.json
+++ b/coin/qt-installer-package-config.json
@@ -6,7 +6,8 @@
"**/*Compositor*/**/*",
"**/*Compositor*",
"**/wayland-graphics-integration-server/*",
- "**/wayland-hardware-layer-integration/*"
+ "**/wayland-hardware-layer-integration/*",
+ "**/QmlPlugins/Qt6WaylandTextureSharing*.cmake"
]
}
}
diff --git a/conanfile.py b/conanfile.py
deleted file mode 100644
index 78e6058fb..000000000
--- a/conanfile.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright (C) 2021 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-from conans import ConanFile
-import re
-from pathlib import Path
-
-
-def _parse_qt_version_by_key(key: str) -> str:
- with open(Path(__file__).parent.resolve() / ".cmake.conf") as f:
- m = re.search(fr'{key} .*"(.*)"', f.read())
- return m.group(1) if m else ""
-
-
-def _get_qt_minor_version() -> str:
- return ".".join(_parse_qt_version_by_key("QT_REPO_MODULE_VERSION").split(".")[:2])
-
-
-class QtWayland(ConanFile):
- name = "qtwayland"
- license = "LGPL-3.0, GPL-2.0+, Commercial Qt License Agreement"
- author = "The Qt Company <https://www.qt.io/contact-us>"
- url = "https://code.qt.io/cgit/qt/qtwayland.git"
- description = (
- "QtWayland is a Qt module that wraps the functionality of Wayland. "
- "QtWayland is separated into a client and server side. The client side "
- "is the wayland platform plugin, and provides a way to run Qt applications "
- "as Wayland clients. The server side is the Qt Wayland Compositor API, "
- "and allows users to write their own Wayland compositors."
- )
- topics = "qt", "qt6", "wayland"
- settings = "os", "compiler", "arch", "build_type"
- # for referencing the version number and prerelease tag and dependencies info
- exports = ".cmake.conf", "dependencies.yaml"
- exports_sources = "*", "!conan*.*"
- python_requires = f"qt-conan-common/{_get_qt_minor_version()}@qt/everywhere"
- python_requires_extend = "qt-conan-common.QtLeafModule"
diff --git a/config.tests/wayland_scanner/CMakeLists.txt b/config.tests/wayland_scanner/CMakeLists.txt
index d444aa9c4..31a8086b8 100644
--- a/config.tests/wayland_scanner/CMakeLists.txt
+++ b/config.tests/wayland_scanner/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from wayland_scanner.pro.
cmake_minimum_required(VERSION 3.16)
diff --git a/config.tests/wayland_scanner/main.cpp b/config.tests/wayland_scanner/main.cpp
index 8dad73c33..b1f21db25 100644
--- a/config.tests/wayland_scanner/main.cpp
+++ b/config.tests/wayland_scanner/main.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: BSD-3-Clause
//If wayland-scanner is available, the following file should exist
#include "wayland-scanner-test-client-protocol.h"
diff --git a/configure.cmake b/configure.cmake
index 53e3f1109..68f54ce72 100644
--- a/configure.cmake
+++ b/configure.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#### Inputs
diff --git a/dependencies.yaml b/dependencies.yaml
index 06e252980..24a608217 100644
--- a/dependencies.yaml
+++ b/dependencies.yaml
@@ -1,7 +1,10 @@
dependencies:
../qtbase:
- ref: b885820c395a0bbfb0ff55ab0ee47a4703aa6b59
+ ref: e7362764d4931f255d2377462df8ac7a0d4e7c84
required: true
../qtdeclarative:
- ref: 34e40275acd87e2d6cbcb28d5288074184cbe98f
+ ref: 330fa93d6e9003c0ea188b9e703f2b3f0448f8c8
+ required: false
+ ../qtsvg:
+ ref: b5a9711109774baed6ea14079ff87802d191d2a9
required: false
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 5f219b0cd..f2354f266 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
qt_examples_build_begin(EXTERNAL_BUILD)
add_subdirectory(wayland)
diff --git a/examples/wayland/CMakeLists.txt b/examples/wayland/CMakeLists.txt
index 20ee212cb..24abe5236 100644
--- a/examples/wayland/CMakeLists.txt
+++ b/examples/wayland/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
if(QT_FEATURE_wayland_server)
if(QT_FEATURE_opengl)
qt_internal_add_example(minimal-cpp)
@@ -5,20 +8,16 @@ endif()
if(TARGET Qt::Quick)
qt_internal_add_example(minimal-qml)
qt_internal_add_example(spanning-screens)
- qt_internal_add_example(pure-qml)
+ qt_internal_add_example(fancy-compositor)
qt_internal_add_example(multi-output)
qt_internal_add_example(multi-screen)
qt_internal_add_example(overview-compositor)
qt_internal_add_example(ivi-compositor)
qt_internal_add_example(server-side-decoration)
- qt_internal_add_example(hwlayer-compositor)
qt_internal_add_example(qtshell)
endif()
if(TARGET Qt::Quick AND TARGET Qt::WaylandClient)
- add_subdirectory(custom-extension)
- add_subdirectory(custom-shell)
-endif()
-if(QT_FEATURE_opengl AND TARGET Qt::Quick AND TARGET Qt::WaylandClient)
- add_subdirectory(server-buffer)
+ qt_internal_add_example(custom-extension)
+ qt_internal_add_example(custom-shell)
endif()
endif()
diff --git a/examples/wayland/custom-extension/CMakeLists.txt b/examples/wayland/custom-extension/CMakeLists.txt
index 99f12303f..af6e7febd 100644
--- a/examples/wayland/custom-extension/CMakeLists.txt
+++ b/examples/wayland/custom-extension/CMakeLists.txt
@@ -1,3 +1,9 @@
-qt_internal_add_example(qml-client)
-qt_internal_add_example(compositor)
-qt_internal_add_example(cpp-client)
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(custom-extension)
+
+add_subdirectory(qml-client)
+add_subdirectory(compositor)
+add_subdirectory(cpp-client)
diff --git a/examples/wayland/custom-extension/client-common/customextension.cpp b/examples/wayland/custom-extension/client-common/customextension.cpp
index b07df27fc..4f898ea9b 100644
--- a/examples/wayland/custom-extension/client-common/customextension.cpp
+++ b/examples/wayland/custom-extension/client-common/customextension.cpp
@@ -25,7 +25,7 @@ static inline struct ::wl_surface *getWlSurface(QWindow *window)
QWindow *CustomExtension::windowForSurface(struct ::wl_surface *surface)
{
- for (QWindow *w : qAsConst(m_windows)) {
+ for (QWindow *w : std::as_const(m_windows)) {
if (getWlSurface(w) == surface)
return w;
}
@@ -56,8 +56,10 @@ void CustomExtension::sendWindowRegistration(QWindow *window)
void CustomExtension::registerWindow(QWindow *window)
{
m_windows << window;
- if (isActive())
+ if (isActive()) {
+ m_activated = true;
sendWindowRegistration(window);
+ }
}
CustomExtensionObject *CustomExtension::createCustomObject(const QString &color, const QString &text)
@@ -66,10 +68,12 @@ CustomExtensionObject *CustomExtension::createCustomObject(const QString &color,
return new CustomExtensionObject(obj, text);
}
+//! [sendBounce]
void CustomExtension::sendBounce(QWindow *window, uint ms)
{
QtWayland::qt_example_extension::bounce(getWlSurface(window), ms);
}
+//! [sendBounce]
void CustomExtension::sendSpin(QWindow *window, uint ms)
{
@@ -79,7 +83,8 @@ void CustomExtension::sendSpin(QWindow *window, uint ms)
void CustomExtension::handleExtensionActive()
{
if (isActive() && !m_activated) {
- for (QWindow *w : qAsConst(m_windows))
+ m_activated = true;
+ for (QWindow *w : std::as_const(m_windows))
sendWindowRegistration(w);
}
}
@@ -99,7 +104,7 @@ void CustomExtension::example_extension_set_font_size(wl_surface *surface, uint3
void CustomExtension::example_extension_set_window_decoration(uint32_t state)
{
bool shown = state;
- for (QWindow *w : qAsConst(m_windows)) {
+ for (QWindow *w : std::as_const(m_windows)) {
Qt::WindowFlags f = w->flags();
if (shown)
f &= ~Qt::FramelessWindowHint;
diff --git a/examples/wayland/custom-extension/client-common/customextension.h b/examples/wayland/custom-extension/client-common/customextension.h
index c3a9a4939..5dd770199 100644
--- a/examples/wayland/custom-extension/client-common/customextension.h
+++ b/examples/wayland/custom-extension/client-common/customextension.h
@@ -6,16 +6,21 @@
#include <QtWaylandClient/QWaylandClientExtension>
#include <QtGui/QWindow>
+#include <QtQml/QQmlEngine>
+
#include "qwayland-custom.h"
QT_BEGIN_NAMESPACE
class CustomExtensionObject;
+//! [CustomExtension]
class CustomExtension : public QWaylandClientExtensionTemplate<CustomExtension>
, public QtWayland::qt_example_extension
+//! [CustomExtension]
{
Q_OBJECT
+ QML_ELEMENT
public:
CustomExtension();
Q_INVOKABLE void registerWindow(QWindow *window);
@@ -67,7 +72,6 @@ protected:
public slots:
void setText(const QString &text);
-
signals:
void textChanged(const QString &text);
void clicked();
diff --git a/examples/wayland/custom-extension/compositor/CMakeLists.txt b/examples/wayland/custom-extension/compositor/CMakeLists.txt
index 8692dd6c9..200e7766d 100644
--- a/examples/wayland/custom-extension/compositor/CMakeLists.txt
+++ b/examples/wayland/custom-extension/compositor/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(custom-extension-compositor)
@@ -11,6 +14,7 @@ set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/wayland/custom-extension/composit
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml WaylandCompositor)
+qt6_policy(SET QTP0001 NEW)
qt_add_executable(custom-extension-compositor
customextension.cpp customextension.h
main.cpp
@@ -47,6 +51,11 @@ qt6_add_resources(custom-extension-compositor "compositor"
${compositor_resource_files}
)
+qt6_add_qml_module(custom-extension-compositor
+ URI io.qt.examples.customextension
+ VERSION 1.0
+)
+
install(TARGETS custom-extension-compositor
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
diff --git a/examples/wayland/custom-extension/compositor/compositor.pro b/examples/wayland/custom-extension/compositor/compositor.pro
index 283ccdf4b..263b9fbdd 100644
--- a/examples/wayland/custom-extension/compositor/compositor.pro
+++ b/examples/wayland/custom-extension/compositor/compositor.pro
@@ -2,6 +2,10 @@ QT += core gui qml
QT += waylandcompositor
+CONFIG += qmltypes
+QML_IMPORT_NAME = io.qt.examples.customextension
+QML_IMPORT_MAJOR_VERSION = 1
+
CONFIG += wayland-scanner
CONFIG += c++11
SOURCES += \
diff --git a/examples/wayland/custom-extension/compositor/customextension.cpp b/examples/wayland/custom-extension/compositor/customextension.cpp
index e6968adc6..0d19a62e2 100644
--- a/examples/wayland/custom-extension/compositor/customextension.cpp
+++ b/examples/wayland/custom-extension/compositor/customextension.cpp
@@ -8,7 +8,7 @@
#include <QDebug>
CustomExtension::CustomExtension(QWaylandCompositor *compositor)
- :QWaylandCompositorExtensionTemplate(compositor)
+ : QWaylandCompositorExtensionTemplate(compositor)
{
}
@@ -19,6 +19,7 @@ void CustomExtension::initialize()
init(compositor->display(), 1);
}
+//! [setFontSize]
void CustomExtension::setFontSize(QWaylandSurface *surface, uint pixelSize)
{
if (surface) {
@@ -29,6 +30,7 @@ void CustomExtension::setFontSize(QWaylandSurface *surface, uint pixelSize)
}
}
}
+//! [setFontSize]
void CustomExtension::showDecorations(QWaylandClient *client, bool shown)
{
@@ -39,7 +41,6 @@ void CustomExtension::showDecorations(QWaylandClient *client, bool shown)
send_set_window_decoration(target->handle, shown);
}
}
-
}
void CustomExtension::close(QWaylandSurface *surface)
@@ -53,6 +54,7 @@ void CustomExtension::close(QWaylandSurface *surface)
}
}
+//! [example_extension_bounce]
void CustomExtension::example_extension_bounce(QtWaylandServer::qt_example_extension::Resource *resource, wl_resource *wl_surface, uint32_t duration)
{
Q_UNUSED(resource);
@@ -60,6 +62,7 @@ void CustomExtension::example_extension_bounce(QtWaylandServer::qt_example_exten
qDebug() << "server received bounce" << surface << duration;
emit bounce(surface, duration);
}
+//! [example_extension_bounce]
void CustomExtension::example_extension_spin(QtWaylandServer::qt_example_extension::Resource *resource, wl_resource *wl_surface, uint32_t duration)
{
@@ -90,7 +93,6 @@ CustomExtensionObject::CustomExtensionObject(const QString &color, const QString
, m_color(color)
, m_text(text)
{
-
}
void CustomExtensionObject::sendClicked()
diff --git a/examples/wayland/custom-extension/compositor/customextension.h b/examples/wayland/custom-extension/compositor/customextension.h
index 330199697..e377d5f57 100644
--- a/examples/wayland/custom-extension/compositor/customextension.h
+++ b/examples/wayland/custom-extension/compositor/customextension.h
@@ -9,14 +9,18 @@
#include <QtWaylandCompositor/QWaylandCompositorExtensionTemplate>
#include <QtWaylandCompositor/QWaylandQuickExtension>
#include <QtWaylandCompositor/QWaylandCompositor>
+#include <QtWaylandCompositor/QWaylandSurface>
#include "qwayland-server-custom.h"
class CustomExtensionObject;
+//! [CustomExtension]
class CustomExtension : public QWaylandCompositorExtensionTemplate<CustomExtension>
, public QtWaylandServer::qt_example_extension
{
Q_OBJECT
+ QML_ELEMENT
+//! [CustomExtension]
public:
CustomExtension(QWaylandCompositor *compositor = nullptr);
void initialize() override;
@@ -25,7 +29,6 @@ signals:
void surfaceAdded(QWaylandSurface *surface);
void bounce(QWaylandSurface *surface, uint ms);
void spin(QWaylandSurface *surface, uint ms);
-
void customObjectCreated(CustomExtensionObject *obj);
public slots:
@@ -33,11 +36,12 @@ public slots:
void showDecorations(QWaylandClient *client, bool);
void close(QWaylandSurface *surface);
+//! [example_extension_bounce]
protected:
void example_extension_bounce(Resource *resource, wl_resource *surface, uint32_t duration) override;
+//! [example_extension_bounce]
void example_extension_spin(Resource *resource, wl_resource *surface, uint32_t duration) override;
void example_extension_register_surface(Resource *resource, wl_resource *surface) override;
-
void example_extension_create_local_object(Resource *resource, uint32_t id, const QString &color, const QString &text) override;
};
diff --git a/examples/wayland/custom-extension/compositor/main.cpp b/examples/wayland/custom-extension/compositor/main.cpp
index a44027229..69e34d2dc 100644
--- a/examples/wayland/custom-extension/compositor/main.cpp
+++ b/examples/wayland/custom-extension/compositor/main.cpp
@@ -11,15 +11,12 @@
#include "customextension.h"
-static void registerTypes()
-{
- qmlRegisterType<CustomExtensionQuickExtension>("io.qt.examples.customextension", 1, 0, "CustomExtension");
-}
-
int main(int argc, char *argv[])
{
+ // ShareOpenGLContexts is needed for using the threaded renderer
+ // on Nvidia EGLStreams
+ QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
QGuiApplication app(argc, argv);
- registerTypes();
QQmlApplicationEngine appEngine(QUrl("qrc:///qml/main.qml"));
return app.exec();
diff --git a/examples/wayland/custom-extension/compositor/qml/CompositorScreen.qml b/examples/wayland/custom-extension/compositor/qml/CompositorScreen.qml
index 724c0975a..ea2cb9b16 100644
--- a/examples/wayland/custom-extension/compositor/qml/CompositorScreen.qml
+++ b/examples/wayland/custom-extension/compositor/qml/CompositorScreen.qml
@@ -9,6 +9,7 @@ WaylandOutput {
id: output
property alias surfaceArea: background
sizeFollowsWindow: true
+
window: Window {
id: screen
@@ -20,7 +21,7 @@ WaylandOutput {
Rectangle {
id: sidebar
- width: 150
+ width: 250
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
@@ -34,19 +35,20 @@ WaylandOutput {
Repeater {
model: comp.itemList
Rectangle {
- height: 36
+ height: 54
width: sidebar.width - 5
color: "white"
radius: 5
Text {
- text: "window: " + modelData.shellSurface.title + "[" + modelData.shellSurface.className
- + (modelData.isCustom ? "]\nfont size: " + modelData.fontSize :"]\n No extension")
+ text: "window: " + modelData.shellSurface.toplevel.title + "\n["
+ + modelData.shellSurface.toplevel.appId
+ + (modelData.isCustom ? "]\nfont size: " + modelData.fontSize : "]\nNo extension")
color: modelData.isCustom ? "black" : "darkgray"
}
MouseArea {
enabled: modelData.isCustom
anchors.fill: parent
- onWheel: {
+ onWheel: (wheel) => {
if (wheel.angleDelta.y > 0)
modelData.fontSize++
else if (wheel.angleDelta.y < 0 && modelData.fontSize > 3)
diff --git a/examples/wayland/custom-extension/compositor/qml/main.qml b/examples/wayland/custom-extension/compositor/qml/main.qml
index d9b57e7cf..9907263da 100644
--- a/examples/wayland/custom-extension/compositor/qml/main.qml
+++ b/examples/wayland/custom-extension/compositor/qml/main.qml
@@ -3,7 +3,7 @@
import QtQuick
import QtWayland.Compositor
-import QtWayland.Compositor.WlShell
+import QtWayland.Compositor.XdgShell
import io.qt.examples.customextension 1.0
@@ -34,36 +34,38 @@ WaylandCompositor {
property int fontSize: 12
onSurfaceDestroyed: {
- var index = itemList.indexOf(chrome);
+ var index = itemList.indexOf(chrome)
if (index > -1) {
var listCopy = itemList
- listCopy.splice(index, 1);
+ listCopy.splice(index, 1)
itemList = listCopy
}
chrome.destroy()
}
+
transform: [
Rotation {
id: xRot
- origin.x: chrome.width/2; origin.y: chrome.height/2;
+ origin.x: chrome.width / 2; origin.y: chrome.height / 2
angle: 0
axis { x: 1; y: 0; z: 0 }
},
Rotation {
id: yRot
- origin.x: chrome.width/2; origin.y: chrome.height/2;
+ origin.x: chrome.width / 2; origin.y: chrome.height / 2
angle: 0
axis { x: 0; y: 1; z: 0 }
}
]
+
NumberAnimation {
id: spinAnimation
running: false
loops: 2
- target: yRot;
- property: "angle";
- from: 0; to: 360;
- duration: 400;
+ target: yRot
+ property: "angle"
+ from: 0; to: 360
+ duration: 400
}
function doSpin(ms) {
@@ -82,18 +84,21 @@ WaylandCompositor {
easing.type: Easing.OutBounce
duration: 1000
}
+
function doBounce(ms) {
console.log("bounce " + ms)
// using the 'ms' argument is left as an exercise for the reader...
bounceAnimation.start()
}
+
+//! [setFontSize]
onFontSizeChanged: {
custom.setFontSize(surface, fontSize)
}
+//! [setFontSize]
}
}
-
Component {
id: customObjectComponent
Rectangle {
@@ -103,7 +108,7 @@ WaylandCompositor {
width: 100
height: 100
- radius: width/2
+ radius: width / 2
x: Math.random() * (defaultOutput.surfaceArea.width - 100)
y: Math.random() * (defaultOutput.surfaceArea.height - 100)
@@ -120,53 +125,59 @@ WaylandCompositor {
Connections {
target: obj
- onResourceDestroyed: {
+ function onResourceDestroyed() {
customItem.destroy()
}
}
}
}
- WlShell {
- id: defaultShell
- onWlShellSurfaceCreated: {
- var item = chromeComponent.createObject(defaultOutput.surfaceArea, { "shellSurface": shellSurface } );
- var w = defaultOutput.surfaceArea.width/2
- var h = defaultOutput.surfaceArea.height/2
- item.x = Math.random()*w
- item.y = Math.random()*h
+ XdgShell {
+ onToplevelCreated: (toplevel, xdgSurface) => {
+ var item = chromeComponent.createObject(defaultOutput.surfaceArea, { "shellSurface": xdgSurface } )
+ var w = defaultOutput.surfaceArea.width / 2
+ var h = defaultOutput.surfaceArea.height / 2
+ item.x = Math.random() * w
+ item.y = Math.random() * h
var listCopy = itemList // List properties cannot be modified through Javascript operations
listCopy.push(item)
itemList = listCopy
}
}
+//! [CustomExtension]
CustomExtension {
id: custom
- onSurfaceAdded: {
+ onSurfaceAdded: (surface) => {
var item = itemForSurface(surface)
item.isCustom = true
}
- onBounce: {
+
+ onBounce: (surface, ms) => {
var item = itemForSurface(surface)
item.doBounce(ms)
}
- onSpin: {
+
+ onSpin: (surface, ms) => {
var item = itemForSurface(surface)
item.doSpin(ms)
}
- onCustomObjectCreated: {
- var item = customObjectComponent.createObject(defaultOutput.surfaceArea, { "color": obj.color, "text": obj.text, "obj": obj } );
+
+ onCustomObjectCreated: (obj) => {
+ var item = customObjectComponent.createObject(defaultOutput.surfaceArea,
+ { "color": obj.color,
+ "text": obj.text,
+ "obj": obj } )
}
}
function setDecorations(shown) {
var n = itemList.length
for (var i = 0; i < n; i++) {
- // TODO: we only need to do it once for each client
if (itemList[i].isCustom)
custom.showDecorations(itemList[i].surface.client, shown)
}
}
+//! [CustomExtension]
}
diff --git a/examples/wayland/custom-extension/cpp-client/CMakeLists.txt b/examples/wayland/custom-extension/cpp-client/CMakeLists.txt
index eeacfd296..1687ade05 100644
--- a/examples/wayland/custom-extension/cpp-client/CMakeLists.txt
+++ b/examples/wayland/custom-extension/cpp-client/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(custom-extension-cpp-client)
diff --git a/examples/wayland/custom-extension/cpp-client/main.cpp b/examples/wayland/custom-extension/cpp-client/main.cpp
index 6b6fa7069..c3951ea9d 100644
--- a/examples/wayland/custom-extension/cpp-client/main.cpp
+++ b/examples/wayland/custom-extension/cpp-client/main.cpp
@@ -6,17 +6,14 @@
#include <QPainter>
#include <QMouseEvent>
#include <QPlatformSurfaceEvent>
-
-#include "../client-common/customextension.h"
-
#include <QDebug>
-#include <QtGui/qpa/qplatformnativeinterface.h>
#include <QTimer>
+#include "../client-common/customextension.h"
+
class TestWindow : public QRasterWindow
{
Q_OBJECT
-
public:
TestWindow(CustomExtension *customExtension)
: m_extension(customExtension)
@@ -25,8 +22,12 @@ public:
, rect3(50, 350, 100, 100)
, rect4(200,350, 100, 100)
{
+ setTitle(tr("C++ Client"));
m_extension->registerWindow(this);
+
+//! [connection]
connect(m_extension, &CustomExtension::fontSize, this, &TestWindow::handleSetFontSize);
+//! [connection]
}
public slots:
@@ -39,6 +40,7 @@ public slots:
qDebug() << "sending spin...";
m_extension->sendSpin(this, 500);
}
+
void doBounce()
{
if (!m_extension->isActive()) {
@@ -58,7 +60,7 @@ public slots:
CustomExtensionObject *newObject()
{
m_objectCount++;
- QColor col = QColor::fromHsv(0, 511/(m_objectCount+1), 255);
+ QColor col = QColor::fromHsv(0, 511 / (m_objectCount + 1), 255);
return m_extension->createCustomObject(col.name(), QString::number(m_objectCount));
}
@@ -76,18 +78,19 @@ protected:
{
QPainter p(this);
p.setFont(m_font);
- p.fillRect(QRect(0,0,width(),height()),Qt::gray);
- p.fillRect(rect1, QColor("#C0FFEE"));
+ p.fillRect(QRect(0, 0, width(), height()), Qt::gray);
+ p.fillRect(rect1, QColor::fromString("#C0FFEE"));
p.drawText(rect1, Qt::TextWordWrap, "Press here to send spin request.");
- p.fillRect(rect2, QColor("#decaff"));
+ p.fillRect(rect2, QColor::fromString("#decaff"));
p.drawText(rect2, Qt::TextWordWrap, "Press here to send bounce request.");
- p.fillRect(rect3, QColor("#7EA"));
+ p.fillRect(rect3, QColor::fromString("#7EA"));
p.drawText(rect3, Qt::TextWordWrap, "Create new window.");
- p.fillRect(rect4, QColor("#7EABA6"));
+ p.fillRect(rect4, QColor::fromString("#7EABA6"));
p.drawText(rect4, Qt::TextWordWrap, "Create custom object.");
}
+//! [mousePressEvent]
void mousePressEvent(QMouseEvent *ev) override
{
if (rect1.contains(ev->position()))
@@ -99,6 +102,7 @@ protected:
else if (rect4.contains(ev->position()))
newObject();
}
+//! [mousePressEvent]
private:
CustomExtension *m_extension = nullptr;
diff --git a/examples/wayland/custom-extension/doc/images/custom-extension.png b/examples/wayland/custom-extension/doc/images/custom-extension.png
new file mode 100644
index 000000000..95cddad12
--- /dev/null
+++ b/examples/wayland/custom-extension/doc/images/custom-extension.png
Binary files differ
diff --git a/examples/wayland/custom-extension/doc/src/custom-extension.qdoc b/examples/wayland/custom-extension/doc/src/custom-extension.qdoc
new file mode 100644
index 000000000..7b2cb0802
--- /dev/null
+++ b/examples/wayland/custom-extension/doc/src/custom-extension.qdoc
@@ -0,0 +1,148 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ * \title Custom Extension
+ * \example custom-extension
+ * \examplecategory {Embedded}
+ * \brief Custom Extension shows how to implement a custom Wayland extension.
+ * \ingroup qtwaylandcompositor-examples
+ *
+ * It's easy to write new extensions for Wayland. They are defined using a XML-based format and
+ * the \c wayland-scanner tool converts this to glue code in C. Qt expands on this with the
+ * \c qtwaylandscanner, which generates additional glue code in Qt and C++.
+ *
+ * \image custom-extension.png
+ *
+ * The Custom Extension example shows how to use these tools to extend the Wayland protocol and
+ * send custom requests and events between a Wayland client and a server.
+ *
+ * The example consists of four items:
+ * \list
+ * \li The definition of the protocol itself.
+ * \li A compositor that supports the extension.
+ * \li A C++-based client that supports the extension.
+ * \li A QML-based client that supports the extension.
+ * \endlist
+ *
+ * \section1 The Protocol Definition
+ *
+ * The XML file \c custom.xml defines the protocol. It contains an interface called
+ * "qt_example_extension". This is the name which will be broadcast from the server and which the
+ * client will attach to in order to send requests and receive events. This name should be unique,
+ * so it is good to use a prefix that sets it apart from official interfaces.
+ *
+ * An interface typically consists of two types of remote procedure calls:
+ * \e requests and \e events. "Requests" are calls the client makes on the server-side, and
+ * "events" are calls the server makes on the client-side.
+ *
+ * The example extension contains a set of \e requests which instructs the server to apply certain
+ * transforms to the client window. For instance, if the client sends a "bounce" request, then the
+ * server should respond to this by making the window bounce on the screen.
+ *
+ * Similarly, it has a set of \e events which the server can use to provide instructions for the
+ * client. For instance, the "set_font_size" event is an instruction for the client to set its
+ * default font size to a specific size.
+ *
+ * The protocol defines the existence of requests and events, as well as the arguments they
+ * take. When \c qtwaylandscanner is run on it, it will generate the code needed to marshall the
+ * procedure call and its arguments and to transmit this over the connection. On the other end, this
+ * becomes a call to a virtual function which can be implemented to provide the actual response.
+ *
+ * In order to have \c qtwaylandscanner run automatically as part of the build, we use the
+ * CMake functions \l{qt_generate_wayland_protocol_server_sources}{qt_generate_wayland_protocol_server_sources()} and
+ * \l{qt_generate_wayland_protocol_client_sources}{qt_generate_wayland_protocol_client_sources()} for generating the server-side and
+ * client-side glue code, respectively. (When using \c qmake, the \c WAYLANDSERVERSOURCES and
+ * \c WAYLANDCLIENTSOURCES variables achieve the same.)
+ *
+ * \section1 The Compositor Implementation
+ *
+ * The Compositor application itself is implemented using QML and Qt Quick, but the extension is
+ * implemented in C++.
+ *
+ * The first step is to create a subclass of the glue code generated by \c qtwaylandscanner so
+ * that we can access its functionality. We add the \l QML_ELEMENT macro to the class in order to
+ * make it accessible from QML.
+ *
+ * \snippet custom-extension/compositor/customextension.h CustomExtension
+ *
+ * In addition to inheriting from the generated class, we also inherit the class
+ * \l QWaylandCompositorExtensionTemplate which provides some additional convenience when dealing
+ * with extensions, using the
+ * \l{https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern}{Curiously Recurring Template Pattern}.
+ *
+ * Note that the \l QWaylandCompositorExtensionTemplate must be first in the inheritance list, since
+ * it is a \l{QObject}-based class.
+ *
+ * The subclass has re-implementations of virtual functions in the generated base class, where
+ * we can handle requests issued by a client.
+ *
+ * \snippet custom-extension/compositor/customextension.h example_extension_bounce
+ *
+ * In these re-implementations, we simply translate the request to a \e signal emission, so that we
+ * can handle it in the actual QML code of the compositor.
+ *
+ * \snippet custom-extension/compositor/customextension.cpp example_extension_bounce
+ *
+ * In addition, the subclass defines \e slots for each of the events, so that these can be either
+ * called from QML or be connected to signals. The slots simply call the generated functions which
+ * send the events to the client.
+ *
+ * \snippet custom-extension/compositor/customextension.cpp setFontSize
+ *
+ * Since we added the \l QML_ELEMENT macro to the class definition (and added the corresponding
+ * build steps to the build system files), it can be instantiated in QML.
+ *
+ * We make it a direct child of the \l WaylandCompositor object in order for the compositor to
+ * register it as an extension.
+ *
+ * \snippet custom-extension/compositor/qml/main.qml CustomExtension
+ *
+ * The object has signal handlers for the requests it may get from the client and reacts to them
+ * accordingly. In addition, we can call its slots to send events.
+ *
+ * \snippet custom-extension/compositor/qml/main.qml setFontSize
+ *
+ * \section1 The C++ Client Implementation
+ *
+ * Both clients share the C++ implementation of the interface. Like in the compositor, we make
+ * a subclass of the generated code which also inherits from a template class. In this case,
+ * we inherit QWaylandClientExtensionTemplate.
+ *
+ * \snippet custom-extension/client-common/customextension.h CustomExtension
+ *
+ * The approach is very similar to that of the compositor, except inverted: Requests are implemented
+ * as slots which call the generated functions, and events virtual functions which we re-implement
+ * to emit signals.
+ *
+ * \snippet custom-extension/client-common/customextension.cpp sendBounce
+ *
+ * The client code itself is very simple and only intended to show how to trigger the behavior. In
+ * a custom paint event, it draws a set of rectangles and labels. When any of these are clicked, it
+ * issues requests to the server.
+ *
+ * \snippet custom-extension/cpp-client/main.cpp mousePressEvent
+ *
+ * To update the font size when the \c set_font_size event is received, the signal in our extension
+ * class is connected to a slot.
+ *
+ * \snippet custom-extension/cpp-client/main.cpp connection
+ *
+ * The slot will update the font size and repaint the window.
+ *
+ * \section1 The QML Client Implementation
+ *
+ * The QML client is similar to the C++ client. It relies on the same implementation of the custom
+ * extension as the C++ client, and instantiates this in QML to enable it.
+ *
+ * \snippet custom-extension/qml-client/main.qml CustomExtension
+ *
+ * The UI consists of some clickable rectangles, and uses \l TapHandler to send the corresponding
+ * requests when a rectangle is clicked.
+ *
+ * \snippet custom-extension/qml-client/main.qml sendBounce
+ *
+ * For simplicity, the example has been limited to only demonstrate the \c bounce and \c spin
+ * requests as well as the \c set_font_size event. Adding support for the additional features is
+ * left as an exercise for the reader.
+ */
diff --git a/examples/wayland/custom-extension/qml-client/CMakeLists.txt b/examples/wayland/custom-extension/qml-client/CMakeLists.txt
index 256ade9b3..13798b96b 100644
--- a/examples/wayland/custom-extension/qml-client/CMakeLists.txt
+++ b/examples/wayland/custom-extension/qml-client/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(custom-extension-qml-client)
@@ -11,6 +14,7 @@ set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/wayland/custom-extension/qml-clie
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick WaylandClient)
+qt6_policy(SET QTP0001 NEW)
qt_add_executable(custom-extension-qml-client
../client-common/customextension.cpp ../client-common/customextension.h
main.cpp
@@ -47,6 +51,13 @@ qt6_add_resources(custom-extension-qml-client "qml"
${qml_resource_files}
)
+target_include_directories(custom-extension-qml-client PUBLIC ../client-common/)
+
+qt6_add_qml_module(custom-extension-qml-client
+ URI io.qt.examples.customextension
+ VERSION 1.0
+)
+
install(TARGETS custom-extension-qml-client
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
diff --git a/examples/wayland/custom-extension/qml-client/main.cpp b/examples/wayland/custom-extension/qml-client/main.cpp
index 3fcc05fad..126c6b915 100644
--- a/examples/wayland/custom-extension/qml-client/main.cpp
+++ b/examples/wayland/custom-extension/qml-client/main.cpp
@@ -1,19 +1,16 @@
// Copyright (C) 2017 Erik Larsson.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-#include <QGuiApplication>
+#include <QtGui/QGuiApplication>
#include <QtQml/QQmlApplicationEngine>
-
-#include <QtQml/qqml.h>
#include <QtQml/QQmlEngine>
+
#include "../client-common/customextension.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
- qmlRegisterType<CustomExtension>("io.qt.examples.customextension", 1, 0, "CustomExtension");
-
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
diff --git a/examples/wayland/custom-extension/qml-client/main.qml b/examples/wayland/custom-extension/qml-client/main.qml
index 3b0515781..da81055bc 100644
--- a/examples/wayland/custom-extension/qml-client/main.qml
+++ b/examples/wayland/custom-extension/qml-client/main.qml
@@ -1,4 +1,5 @@
// Copyright (C) 2017 Erik Larsson.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
@@ -7,54 +8,84 @@ import io.qt.examples.customextension
Window {
id: topLevelWindow
+ title: "QML Client"
visible: true
- Rectangle {
- anchors.fill: parent
- color: "#f1eece"
- }
- property alias textItem: bounceText
- Text {
- id: bounceText
- text: "press here to bounce"
- }
+ width: 800
+ height: 600
- MouseArea {
- anchors.fill: parent
- onClicked: {
- if (customExtension.active)
- customExtension.sendBounce(topLevelWindow, 1000)
- }
- }
+ property real fontSize: height / 50
- MouseArea {
+ Column {
anchors.centerIn: parent
- width: 100; height: 100
- onClicked: {
- if (customExtension.active)
- customExtension.sendSpin(topLevelWindow, 500)
+ width: topLevelWindow.width / 4
+ height: 2 * (width + topLevelWindow.height / 12)
+ spacing: topLevelWindow.height / 12
+
+ Rectangle {
+ id: rect1
+ color: "#C0FFEE"
+ width: parent.width
+ height: width
+ clip: true
+
+ Text {
+ anchors.centerIn: parent
+ text: "Press here to send spin request."
+ font.pixelSize: fontSize
+ width: parent.width
+ height: parent.height
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
+ }
+
+ TapHandler {
+ onTapped: {
+ if (customExtension.active)
+ customExtension.sendSpin(topLevelWindow, 500)
+ }
+ }
}
Rectangle {
- anchors.fill: parent
- color: "#fab1ed"
+ id: rect2
+ color: "#decaff"
+ width: parent.width
+ height: parent.height / 2
+ clip: true
+
Text {
- text: "spin"
+ anchors.centerIn: parent
+ text: "Press here to send bounce request."
+ font.pixelSize: fontSize
+ width: parent.width
+ height: parent.height
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
+ }
+
+//! [sendBounce]
+ TapHandler {
+ onTapped: {
+ if (customExtension.active)
+ customExtension.sendBounce(topLevelWindow, 1000)
+ }
}
+//! [sendBounce]
}
}
+//! [CustomExtension]
CustomExtension {
id: customExtension
onActiveChanged: {
- console.log("Custom extension is active:", active)
registerWindow(topLevelWindow)
}
- onFontSize: {
- // signal arguments: window and pixelSize
- // we are free to interpret the protocol as we want, so
- // let's change the font size of just one of the text items
- window.textItem.font.pixelSize = pixelSize
+ onFontSize: (window, pixelSize) => {
+ topLevelWindow.fontSize = pixelSize
}
}
+//! [CustomExtension]
}
diff --git a/examples/wayland/custom-extension/qml-client/qml-client.pro b/examples/wayland/custom-extension/qml-client/qml-client.pro
index bad4af2db..8bddb730b 100644
--- a/examples/wayland/custom-extension/qml-client/qml-client.pro
+++ b/examples/wayland/custom-extension/qml-client/qml-client.pro
@@ -2,6 +2,12 @@ TEMPLATE = app
QT += qml quick waylandclient gui-private
CONFIG += wayland-scanner
+CONFIG += qmltypes
+QML_IMPORT_NAME = io.qt.examples.customextension
+QML_IMPORT_MAJOR_VERSION = 1
+
+INCLUDEPATH += $$PWD/../client-common
+
WAYLANDCLIENTSOURCES += ../protocol/custom.xml
SOURCES += main.cpp \
diff --git a/examples/wayland/custom-shell/CMakeLists.txt b/examples/wayland/custom-shell/CMakeLists.txt
index 7158582ec..1b0fe1653 100644
--- a/examples/wayland/custom-shell/CMakeLists.txt
+++ b/examples/wayland/custom-shell/CMakeLists.txt
@@ -1,2 +1,5 @@
-qt_internal_add_example(client-plugin)
-qt_internal_add_example(compositor)
+cmake_minimum_required(VERSION 3.16)
+project(custom-shell)
+
+add_subdirectory(client-plugin)
+add_subdirectory(compositor)
diff --git a/examples/wayland/custom-shell/client-plugin/CMakeLists.txt b/examples/wayland/custom-shell/client-plugin/CMakeLists.txt
index 1004a664e..39569b80f 100644
--- a/examples/wayland/custom-shell/client-plugin/CMakeLists.txt
+++ b/examples/wayland/custom-shell/client-plugin/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cmake_minimum_required(VERSION 3.14)
project(exampleshellplugin LANGUAGES CXX)
diff --git a/examples/wayland/custom-shell/compositor/CMakeLists.txt b/examples/wayland/custom-shell/compositor/CMakeLists.txt
index a6a7ced9c..be1d7f623 100644
--- a/examples/wayland/custom-shell/compositor/CMakeLists.txt
+++ b/examples/wayland/custom-shell/compositor/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cmake_minimum_required(VERSION 3.14)
project(custom-shell-compositor)
diff --git a/examples/wayland/custom-shell/compositor/main.cpp b/examples/wayland/custom-shell/compositor/main.cpp
index 17ab3a03d..72f233e8e 100644
--- a/examples/wayland/custom-shell/compositor/main.cpp
+++ b/examples/wayland/custom-shell/compositor/main.cpp
@@ -18,6 +18,9 @@ static void registerTypes()
int main(int argc, char *argv[])
{
+ // ShareOpenGLContexts is needed for using the threaded renderer
+ // on Nvidia EGLStreams
+ QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
QGuiApplication app(argc, argv);
registerTypes();
QQmlApplicationEngine appEngine(QUrl("qrc:///qml/main.qml"));
diff --git a/examples/wayland/custom-shell/doc/images/custom-shell.jpg b/examples/wayland/custom-shell/doc/images/custom-shell.jpg
new file mode 100644
index 000000000..81f1ed205
--- /dev/null
+++ b/examples/wayland/custom-shell/doc/images/custom-shell.jpg
Binary files differ
diff --git a/examples/wayland/custom-shell/doc/src/custom-shell.qdoc b/examples/wayland/custom-shell/doc/src/custom-shell.qdoc
index 75f88fd25..ba0fd8bf7 100644
--- a/examples/wayland/custom-shell/doc/src/custom-shell.qdoc
+++ b/examples/wayland/custom-shell/doc/src/custom-shell.qdoc
@@ -2,8 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
- * \title Qt Wayland Compositor Examples - Custom Shell
+ * \title Custom Shell
* \example custom-shell
+ * \examplecategory {Embedded}
* \brief Custom Shell shows how to implement a custom shell extension.
* \ingroup qtwaylandcompositor-examples
*
@@ -12,6 +13,8 @@
* extensions, but in some circumstances it can be useful to be able to write a custom one which
* contains the exact features your applications need.
*
+ * \image custom-shell.jpg
+ *
* This requires that you implement the shell extension on both the server-side and client-side
* of the Wayland connection, so it is mainly useful when you are building a platform and are in
* control of both the compositor and its client applications.
@@ -35,6 +38,12 @@
* \li An event informing the client of the shell surface's current minimized state.
* \endlist
*
+ * In order to have \c qtwaylandscanner run automatically as part of the build, we use the
+ * CMake functions \l{qt_generate_wayland_protocol_server_sources}{qt_generate_wayland_protocol_server_sources()} and
+ * \l{qt_generate_wayland_protocol_client_sources}{qt_generate_wayland_protocol_client_sources()} for generating the server-side and
+ * client-side glue code, respectively. (When using \c qmake, the \c WAYLANDSERVERSOURCES and
+ * \c WAYLANDCLIENTSOURCES variables achieve the same.)
+ *
* \section1 The Client Plugin
*
* In order for the shell integration to be discovered by a Qt client, we must reimplement
@@ -122,11 +131,11 @@
*
* The final part of the example is the compositor itself. This has the same general structure as
* the other compositor examples. See the
- * \l{Qt Wayland Compositor Examples - Minimal QML}{Minimal QML example} for more details on
+ * \l{Minimal QML}{Minimal QML example} for more details on
* the building blocks of a \l{Qt Wayland Compositor}.
*
* One notable difference in the Custom Shell compositor is the instantiation of the shell
- * extension. Where the \l{Qt Wayland Compositor Examples - Minimal QML}{the Minimal QML example}
+ * extension. Where the \l{Minimal QML}{the Minimal QML example}
* instantiates the shell extensions \l{IviApplication}, \l{XdgShell} and \l{WlShell}, the
* Custom Shell example only creates an instance of the \c ExampleShell extension.
*
diff --git a/examples/wayland/pure-qml/CMakeLists.txt b/examples/wayland/fancy-compositor/CMakeLists.txt
index f008086de..437542331 100644
--- a/examples/wayland/pure-qml/CMakeLists.txt
+++ b/examples/wayland/fancy-compositor/CMakeLists.txt
@@ -1,5 +1,8 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
-project(pure-qml LANGUAGES CXX)
+project(fancy-compositor LANGUAGES CXX)
set(CMAKE_AUTOMOC ON)
@@ -7,27 +10,27 @@ if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/wayland/pure-qml")
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/wayland/fancy-compositor")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml)
-qt_add_executable(pure-qml
+qt_add_executable(fancy-compositor
main.cpp
)
-set_target_properties(pure-qml PROPERTIES
+set_target_properties(fancy-compositor PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
-target_link_libraries(pure-qml PUBLIC
+target_link_libraries(fancy-compositor PUBLIC
Qt::Core
Qt::Gui
Qt::Qml
)
# Resources:
-set(pure-qml_resource_files
+set(fancy-compositor_resource_files
"images/background.jpg"
"qml/Chrome.qml"
"qml/CompositorScreen.qml"
@@ -35,14 +38,14 @@ set(pure-qml_resource_files
"qml/main.qml"
)
-qt6_add_resources(pure-qml "pure-qml"
+qt6_add_resources(fancy-compositor "fancy-compositor"
PREFIX
"/"
FILES
- ${pure-qml_resource_files}
+ ${fancy-compositor_resource_files}
)
-install(TARGETS pure-qml
+install(TARGETS fancy-compositor
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
diff --git a/examples/wayland/pure-qml/doc/src/pure-qml.qdoc b/examples/wayland/fancy-compositor/doc/src/fancy-compositor.qdoc
index b083c5d6d..4d256d2af 100644
--- a/examples/wayland/pure-qml/doc/src/pure-qml.qdoc
+++ b/examples/wayland/fancy-compositor/doc/src/fancy-compositor.qdoc
@@ -2,27 +2,26 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
- \title Qt Wayland Compositor Examples - Pure QML
- \example pure-qml
- \brief Pure QML is an example that demonstrates how to write a Wayland compositor in pure QML.
+ \title Fancy Compositor
+ \example fancy-compositor
+ \examplecategory {Embedded}
+ \brief Fancy Compositor is an example that demonstrates how to write a fancy Wayland compositor in pure QML.
\ingroup qtwaylandcompositor-examples
\section1 Introduction
- Pure QML is a small desktop-style Wayland compositor example that demonstrates the power and
+ Fancy Compositor is a small desktop-style Wayland compositor example that demonstrates the power and
ease of the \l{Qt Wayland Compositor} QML APIs.
- The Pure QML example is similar to the
- \l{Qt Wayland Compositor Examples - Minimal QML}{Minimal QML example}, in that it is a
+ The Fancy Compositor example is similar to the \l{Minimal QML}{Minimal QML example}, in that it is a
full-blown Wayland compositor, implemented only using QML code.
\section1 Initializing the Compositor
- Like the \l{Qt Wayland Compositor Examples - Minimal QML}{Minimal QML example}, Pure QML
- supports the main \l{Shell Extensions - Qt Wayland Compositor}{shell extensions} that are
- supported by Qt.
+ Like the \l{Minimal QML}{Minimal QML example}, Fancy Compositor supports the main
+ \l{Shell Extensions - Qt Wayland Compositor}{shell extensions} that are supported by Qt.
- \snippet pure-qml/qml/main.qml shell extensions
+ \snippet fancy-compositor/qml/main.qml shell extensions
These are instantiated as children of the \l{WaylandCompositor} which automatically adds
them to the list of supported interfaces which is broadcasted to clients from the server.
@@ -31,7 +30,7 @@
corresponding signal is emitted. This then calls a method inside our custom \l WaylandOutput
class, which appends the \l ShellSurface to a \l{ListModel}.
- \snippet pure-qml/qml/CompositorScreen.qml handleShellSurface
+ \snippet fancy-compositor/qml/CompositorScreen.qml handleShellSurface
This model is used as the source for a \l Repeater which creates
\l{ShellSurfaceItem}{ShellSurfaceItems} inside the compositor's \l WaylandOutput. This adds a
@@ -39,20 +38,20 @@
certain interaction options for the user of the compositor, depending on which shell extension
is in use.
- \snippet pure-qml/qml/CompositorScreen.qml repeater
+ \snippet fancy-compositor/qml/CompositorScreen.qml repeater
\section1 Keyboard
- In addition to the basic windowing system functions, the Pure QML compositor also supports an
+ In addition to the basic windowing system functions, the Fancy Compositor also supports an
optional on-screen keyboard running in-process. This uses the \l{Qt Virtual Keyboard} module,
and will be enabled if the module is available.
- \snippet pure-qml/qml/Keyboard.qml keyboard
+ \snippet fancy-compositor/qml/Keyboard.qml keyboard
The code is simple. We instantiate an \l InputPanel in the bottom of the output, and make sure
it is visible if and only if it is currently active.
- \snippet pure-qml/qml/CompositorScreen.qml keyboard
+ \snippet fancy-compositor/qml/CompositorScreen.qml keyboard
The keyboard is then added to the \l WaylandOutput using a \l Loader element. The \l Loader is
used here to avoid having a hard dependency on the \l{Qt Virtual Keyboard} module. If loading
@@ -60,39 +59,37 @@
on-screen keyboard.
Finally, we need a way for the compositor to communicate the text input to its clients. This
- is done via a \c{text-input} extension. The Pure QML example only supports the
- \c{qt_text_input_method_unstable_v1} protocol.
+ is done via a \c{text-input} extension. The Fancy Compositor example supports both the
+ \c{text_input_unstable_v2} protocol as well as Qt's \c{qt_text_input_method_unstable_v1}
+ protocol.
- \snippet pure-qml/qml/main.qml text input
+ \snippet fancy-compositor/qml/main.qml text input
- The extension is added to the compositor by instantiating the \l QtTextInputMethodManager as
- a child of the \l{WaylandCompositor}.
+ The \c{qt_text_input_method_unstable_v1} extension is added to the compositor by instantiating
+ the \l QtTextInputMethodManager as a child of the \l{WaylandCompositor}, and
+ \l{TextInputManager} adds \c{text_input_unstable_v2}.
- In order for the on-screen keyboard to work, this protocol must also be supported by the client.
- Therefore, the \l QtTextInputMethodManager is most useful if the clients are also Qt
- applications.
-
- \note Qt also supports \l{TextInputManager}, which is an implementation of the
- \c{text_input_unstable_v2} protocol.
+ Newer Qt applications will pick \c{qt_text_input_method_unstable_v1} when it is available,
+ while other clients can use \c{text_input_unstable_v2}.
\section1 Transitions
- In addition to the basic functionality, the Pure QML example also demonstrates animated
+ In addition to the basic functionality, the Fancy Compositor example also demonstrates animated
transitions between states.
The first of these is the \e{activation} transition. This is only supported on the \l{XdgShell},
since this is the only shell extension which has an \l{XdgToplevel::}{activated} state.
- \snippet pure-qml/qml/Chrome.qml activation
+ \snippet fancy-compositor/qml/Chrome.qml activation
When a client window becomes activated under the \l XdgShell protocol, we trigger an animation
which makes the window "pop out" for 200 ms.
- The Pure QML compositor also supports a \e{destruction} animation. This triggers whenever the
+ The Fancy Compositor also supports a \e{destruction} animation. This triggers whenever the
window closes and surface is destroyed, whether this was because the client gracefully closed
its window, or even if it crashes.
- \snippet pure-qml/qml/Chrome.qml destruction
+ \snippet fancy-compositor/qml/Chrome.qml destruction
To ensure that the content exists for the duration of the animation, we start by locking the
buffer. This means the final frame rendered by the client will remain in memory until we are
diff --git a/examples/wayland/fancy-compositor/fancy-compositor.pro b/examples/wayland/fancy-compositor/fancy-compositor.pro
new file mode 100644
index 000000000..bd6a2923f
--- /dev/null
+++ b/examples/wayland/fancy-compositor/fancy-compositor.pro
@@ -0,0 +1,18 @@
+QT += gui qml
+
+SOURCES += \
+ main.cpp
+
+OTHER_FILES = \
+ qml/main.qml \
+ qml/CompositorScreen.qml \
+ qml/Chrome.qml \
+ qml/Keyboard.qml \
+ images/background.jpg \
+
+RESOURCES += fancy-compositor.qrc
+
+target.path = $$[QT_INSTALL_EXAMPLES]/wayland/fancy-compositor
+sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS fancy-compositor.pro
+sources.path = $$[QT_INSTALL_EXAMPLES]/wayland/fancy-compositor
+INSTALLS += target sources
diff --git a/examples/wayland/pure-qml/pure-qml.qrc b/examples/wayland/fancy-compositor/fancy-compositor.qrc
index 145b3f250..145b3f250 100644
--- a/examples/wayland/pure-qml/pure-qml.qrc
+++ b/examples/wayland/fancy-compositor/fancy-compositor.qrc
diff --git a/examples/wayland/pure-qml/images/background.jpg b/examples/wayland/fancy-compositor/images/background.jpg
index 445567fbd..445567fbd 100644
--- a/examples/wayland/pure-qml/images/background.jpg
+++ b/examples/wayland/fancy-compositor/images/background.jpg
Binary files differ
diff --git a/examples/wayland/pure-qml/main.cpp b/examples/wayland/fancy-compositor/main.cpp
index dca8dfe01..dca8dfe01 100644
--- a/examples/wayland/pure-qml/main.cpp
+++ b/examples/wayland/fancy-compositor/main.cpp
diff --git a/examples/wayland/pure-qml/qml/Chrome.qml b/examples/wayland/fancy-compositor/qml/Chrome.qml
index b8d71c756..b8d71c756 100644
--- a/examples/wayland/pure-qml/qml/Chrome.qml
+++ b/examples/wayland/fancy-compositor/qml/Chrome.qml
diff --git a/examples/wayland/pure-qml/qml/CompositorScreen.qml b/examples/wayland/fancy-compositor/qml/CompositorScreen.qml
index 4b2ba36d6..4b2ba36d6 100644
--- a/examples/wayland/pure-qml/qml/CompositorScreen.qml
+++ b/examples/wayland/fancy-compositor/qml/CompositorScreen.qml
diff --git a/examples/wayland/pure-qml/qml/Keyboard.qml b/examples/wayland/fancy-compositor/qml/Keyboard.qml
index 2985ffcbd..2985ffcbd 100644
--- a/examples/wayland/pure-qml/qml/Keyboard.qml
+++ b/examples/wayland/fancy-compositor/qml/Keyboard.qml
diff --git a/examples/wayland/pure-qml/qml/main.qml b/examples/wayland/fancy-compositor/qml/main.qml
index 80faa80dd..87feedf14 100644
--- a/examples/wayland/pure-qml/qml/main.qml
+++ b/examples/wayland/fancy-compositor/qml/main.qml
@@ -16,17 +16,17 @@ WaylandCompositor {
// Shell surface extension. Needed to provide a window concept for Wayland clients.
// I.e. requests and events for maximization, minimization, resizing, closing etc.
XdgShell {
- onToplevelCreated: screen.handleShellSurface(xdgSurface)
+ onToplevelCreated: (toplevel, xdgSurface) => screen.handleShellSurface(xdgSurface)
}
// Minimalistic shell extension. Mainly used for embedded applications.
IviApplication {
- onIviSurfaceCreated: screen.handleShellSurface(iviSurface)
+ onIviSurfaceCreated: (iviSurface) => screen.handleShellSurface(iviSurface)
}
// Deprecated shell extension, still used by some clients
WlShell {
- onWlShellSurfaceCreated: screen.handleShellSurface(shellSurface)
+ onWlShellSurfaceCreated: (shellSurface) => screen.handleShellSurface(shellSurface)
}
// ![shell extensions]
diff --git a/examples/wayland/ivi-compositor/CMakeLists.txt b/examples/wayland/ivi-compositor/CMakeLists.txt
index b78728eea..abab05231 100644
--- a/examples/wayland/ivi-compositor/CMakeLists.txt
+++ b/examples/wayland/ivi-compositor/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(ivi-compositor LANGUAGES CXX)
diff --git a/examples/wayland/ivi-compositor/doc/src/ivi-compositor.qdoc b/examples/wayland/ivi-compositor/doc/src/ivi-compositor.qdoc
index fdae636d5..9412cca7b 100644
--- a/examples/wayland/ivi-compositor/doc/src/ivi-compositor.qdoc
+++ b/examples/wayland/ivi-compositor/doc/src/ivi-compositor.qdoc
@@ -2,8 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
- * \title Qt Wayland Compositor Examples - IVI Compositor
+ * \title IVI Compositor
* \example ivi-compositor
+ * \examplecategory {Embedded}
* \brief IVI Compositor is an example that demonstrates how to use the IviApplication extension.
* \ingroup qtwaylandcompositor-examples
*
@@ -13,7 +14,7 @@
* server (also known as a Wayland compositor).
*
* For an introduction to the basic principles of creating a \l{Qt Wayland Compositor} with Qt,
- * see the \l{Qt Wayland Compositor Examples - Minimal QML}{Minimal QML example}.
+ * see the \l{Minimal QML}{Minimal QML example}.
*
* \section1 The Protocol
*
@@ -70,7 +71,7 @@
* \section2 Connecting Clients
*
* If no additional configuration has been done, a Qt application will connect with an \e{IVI-id}
- * equal to its process ID. For instance, if we run the \l{Wiggly Example} with
+ * equal to its process ID. For instance, if we run another Qt example application with
* \c{-platform wayland}, it will be delegated to the right-hand side of the layout, granted that
* its ID is different from "1337".
*
diff --git a/examples/wayland/ivi-compositor/main.qml b/examples/wayland/ivi-compositor/main.qml
index 055d10d30..555f6467c 100644
--- a/examples/wayland/ivi-compositor/main.qml
+++ b/examples/wayland/ivi-compositor/main.qml
@@ -48,14 +48,15 @@ WaylandCompositor {
onWidthChanged: handleResized()
onHeightChanged: handleResized()
function handleResized() {
- shellSurface.sendConfigure(Qt.size(width, height));
+ if (width > 0 && height > 0)
+ shellSurface.sendConfigure(Qt.size(width, height));
}
//! [resizing]
}
}
//! [connecting]
IviApplication {
- onIviSurfaceCreated: {
+ onIviSurfaceCreated: (iviSurface) => {
var surfaceArea = iviSurface.iviId === 1337 ? leftArea : rightArea;
var item = chromeComponent.createObject(surfaceArea, { "shellSurface": iviSurface } );
item.handleResized();
diff --git a/examples/wayland/minimal-cpp/CMakeLists.txt b/examples/wayland/minimal-cpp/CMakeLists.txt
index e8d4efdd6..36fea7ab2 100644
--- a/examples/wayland/minimal-cpp/CMakeLists.txt
+++ b/examples/wayland/minimal-cpp/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(minimal-cpp LANGUAGES CXX)
diff --git a/examples/wayland/minimal-cpp/compositor.cpp b/examples/wayland/minimal-cpp/compositor.cpp
index c07068db6..83b773b28 100644
--- a/examples/wayland/minimal-cpp/compositor.cpp
+++ b/examples/wayland/minimal-cpp/compositor.cpp
@@ -12,11 +12,13 @@
#include <QRandomGenerator>
#include <QOpenGLFunctions>
+//! [getTexture]
QOpenGLTexture *View::getTexture() {
if (advance())
m_texture = currentBuffer().toOpenGLTexture();
return m_texture;
}
+//! [getTexture]
QPoint View::mapToLocal(const QPoint &globalPos) const
{
@@ -48,6 +50,7 @@ Compositor::~Compositor()
{
}
+//! [create]
void Compositor::create()
{
QWaylandOutput *output = new QWaylandOutput(this, m_window);
@@ -59,6 +62,7 @@ void Compositor::create()
m_iviApplication = new QWaylandIviApplication(this);
connect(m_iviApplication, &QWaylandIviApplication::iviSurfaceCreated, this, &Compositor::onIviSurfaceCreated);
}
+//! [create]
View *Compositor::viewAt(const QPoint &position)
{
@@ -85,17 +89,20 @@ static inline QPoint mapToView(const View *view, const QPoint &position)
return view ? view->mapToLocal(position) : position;
}
+//! [handleMousePress]
void Compositor::handleMousePress(const QPoint &position, Qt::MouseButton button)
{
if (!m_mouseView) {
- if (m_mouseView = viewAt(position))
+ if ((m_mouseView = viewAt(position)))
raise(m_mouseView);
}
auto *seat = defaultSeat();
seat->sendMouseMoveEvent(m_mouseView, mapToView(m_mouseView, position));
seat->sendMousePressEvent(button);
}
+//! [handleMousePress]
+//! [handleMouseRelease]
void Compositor::handleMouseRelease(const QPoint &position, Qt::MouseButton button, Qt::MouseButtons buttons)
{
auto *seat = defaultSeat();
@@ -109,6 +116,7 @@ void Compositor::handleMouseRelease(const QPoint &position, Qt::MouseButton butt
m_mouseView = nullptr;
}
}
+//! [handleMouseRelease]
void Compositor::handleMouseMove(const QPoint &position)
{
@@ -135,7 +143,7 @@ void Compositor::handleKeyRelease(quint32 nativeScanCode)
defaultSeat()->sendKeyReleaseEvent(nativeScanCode);
}
-
+//! [surfaceCreated]
void Compositor::onIviSurfaceCreated(QWaylandIviSurface *iviSurface)
{
View *view = new View(iviSurface->iviId());
@@ -146,12 +154,9 @@ void Compositor::onIviSurfaceCreated(QWaylandIviSurface *iviSurface)
connect(view, &QWaylandView::surfaceDestroyed, this, &Compositor::viewSurfaceDestroyed);
connect(iviSurface->surface(), &QWaylandSurface::redraw, this, &Compositor::triggerRender);
}
+//! [surfaceCreated]
-void Compositor::onSurfaceDestroyed()
-{
- triggerRender();
-}
-
+//! [surfaceDestroyed]
void Compositor::viewSurfaceDestroyed()
{
View *view = qobject_cast<View*>(sender());
@@ -159,6 +164,7 @@ void Compositor::viewSurfaceDestroyed()
delete view;
triggerRender();
}
+//! [surfaceDestroyed]
void Compositor::triggerRender()
{
diff --git a/examples/wayland/minimal-cpp/compositor.h b/examples/wayland/minimal-cpp/compositor.h
index c010a7966..8ba6c8d1b 100644
--- a/examples/wayland/minimal-cpp/compositor.h
+++ b/examples/wayland/minimal-cpp/compositor.h
@@ -33,7 +33,6 @@ public:
void initPosition(const QSize &screenSize, const QSize &surfaceSize);
private:
- friend class Compositor;
QOpenGLTexture *m_texture = nullptr;
bool m_positionSet = false;
QPoint m_pos;
@@ -65,7 +64,6 @@ public:
private slots:
void onIviSurfaceCreated(QWaylandIviSurface *iviSurface);
- void onSurfaceDestroyed();
void triggerRender();
void viewSurfaceDestroyed();
diff --git a/examples/wayland/minimal-cpp/doc/images/minimal-cpp.jpg b/examples/wayland/minimal-cpp/doc/images/minimal-cpp.jpg
new file mode 100644
index 000000000..d7c8a1cf8
--- /dev/null
+++ b/examples/wayland/minimal-cpp/doc/images/minimal-cpp.jpg
Binary files differ
diff --git a/examples/wayland/minimal-cpp/doc/src/minimal-cpp.qdoc b/examples/wayland/minimal-cpp/doc/src/minimal-cpp.qdoc
new file mode 100644
index 000000000..3d6894de4
--- /dev/null
+++ b/examples/wayland/minimal-cpp/doc/src/minimal-cpp.qdoc
@@ -0,0 +1,67 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \title Minimal CPP
+ \example minimal-cpp
+ \examplecategory {Embedded}
+ \brief Minimal CPP is an example that demonstrates how to write a Wayland compositor in C++.
+ \ingroup qtwaylandcompositor-examples
+
+ Minimal CPP is a minimalistic compositor example implementing a complete Qt Wayland Compositor
+ using C++. The C++ API of QtWaylandCompositor is low-level and intended for specialized
+ applications, such as supporting hardware features, or if Qt Quick is not available. The QML API
+ offers more convenience and functionality. For comparison, the
+ \l{Minimal QML}{Minimal QML example} implements more functionality with 30 lines of QML than this
+ example does in 300+ lines.
+
+ \image minimal-cpp.jpg
+
+ This example is split in two parts. The Wayland logic is contained in the \c Compositor class,
+ and the user interface is in the \c Window class.
+
+ \section1 Window
+
+ The \c Window class is fairly straight-forward. To display the Wayland surfaces, it iterates
+ through the compositor's views and renders them on the screen using \l QOpenGLTextureBlitter:
+
+ \snippet minimal-cpp/window.cpp paintGL
+
+ All keyboard and mouse events are delivered to the compositor. For example:
+
+ \snippet minimal-cpp/window.cpp mousePressEvent
+
+ \section1 Compositor
+
+ The \c Compositor class is more complex, since it has to implement much of the logic that would
+ be handled by \l[QML]{WaylandCompositor} and \l[QML]{WaylandQuickItem} in a QML-based compositor.
+
+ The \c create function sets up the compositor, using the IviApplication, which is the most basic
+ shell extension. The function is called after the OpenGL context has been initialized:
+
+ \snippet minimal-cpp/compositor.cpp create
+
+ All the logic for mouse events and keyboard focus has to be implemented manually, including
+ implicit mouse grabs (sending all mouse moves to the surface that received the initial mouse
+ press). Note that mouse press events in the Wayland protocol do not contain the mouse position,
+ so we always have to send a mouse move when we reveive a mouse press:
+
+ \snippet minimal-cpp/compositor.cpp handleMousePress
+
+ For a mouse release, we end the implicit grab and notify the surface at the current mouse position:
+
+ \snippet minimal-cpp/compositor.cpp handleMousePress
+
+ When we are notified of a new surface, we create a \c View to keep track of it, and connect
+ signals so we can handle updates.
+
+ \snippet minimal-cpp/compositor.cpp surfaceCreated
+
+ The \c View class subclasses QWaylandView, which represents a specific view of a surface. The
+ \l {QWaylandView::advance}{advance} function updates the view's current buffer and returns true
+ if there is new content. The \c getTexture function makes the buffer contents available as an
+ OpenGL texture for the benefit of the \c Window class:
+
+ \snippet minimal-cpp/compositor.cpp getTexture
+
+*/
diff --git a/examples/wayland/minimal-cpp/window.cpp b/examples/wayland/minimal-cpp/window.cpp
index 4c39505db..68f0a25d8 100644
--- a/examples/wayland/minimal-cpp/window.cpp
+++ b/examples/wayland/minimal-cpp/window.cpp
@@ -24,6 +24,7 @@ void Window::initializeGL()
emit glReady();
}
+//! [paintGL]
void Window::paintGL()
{
m_compositor->startRender();
@@ -64,11 +65,14 @@ void Window::paintGL()
m_textureBlitter.release();
m_compositor->endRender();
}
+//! [paintGL]
+//! [mousePressEvent]
void Window::mousePressEvent(QMouseEvent *event)
{
m_compositor->handleMousePress(event->position().toPoint(), event->button());
}
+//! [mousePressEvent]
void Window::mouseReleaseEvent(QMouseEvent *event)
{
@@ -85,10 +89,12 @@ void Window::wheelEvent(QWheelEvent *event)
m_compositor->handleMouseWheel(event->angleDelta());
}
+//! [keyPressEvent]
void Window::keyPressEvent(QKeyEvent *e)
{
m_compositor->handleKeyPress(e->nativeScanCode());
}
+//! [keyPressEvent]
void Window::keyReleaseEvent(QKeyEvent *e)
{
diff --git a/examples/wayland/minimal-qml/CMakeLists.txt b/examples/wayland/minimal-qml/CMakeLists.txt
index c960e9665..6834cd92f 100644
--- a/examples/wayland/minimal-qml/CMakeLists.txt
+++ b/examples/wayland/minimal-qml/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(minimal-qml LANGUAGES CXX)
diff --git a/examples/wayland/minimal-qml/doc/src/minimal-qml.qdoc b/examples/wayland/minimal-qml/doc/src/minimal-qml.qdoc
index 66b4773ff..2150fece3 100644
--- a/examples/wayland/minimal-qml/doc/src/minimal-qml.qdoc
+++ b/examples/wayland/minimal-qml/doc/src/minimal-qml.qdoc
@@ -2,8 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
- * \title Qt Wayland Compositor Examples - Minimal QML
+ * \title Minimal QML
* \example minimal-qml
+ * \examplecategory {Embedded}
* \brief Minimal QML is a simple example that demonstrates how to write a Wayland compositor in QML.
* \ingroup qtwaylandcompositor-examples
*
@@ -64,7 +65,7 @@
* a \l WaylandOutput object as the direct child of the \l WaylandCompositor. If there is only
* a single output, this will represent the primary screen on the system. (You may also create
* multiple \l WaylandOutput objects to address multiple screens if they are available. See
- * the \l{Qt Wayland Compositor Examples - Multi Screen}{Multi Screen example} for more details
+ * the \l{Multi Screen}{Multi Screen example} for more details
* about this.)
*
* \snippet minimal-qml/main.qml output
@@ -88,5 +89,5 @@
*
* And this is all the code needed to create a functional Wayland compositor using Qt Quick and
* QML. For another example of a compositor written in QML but which has a few more features, take
- * a look at the \l{Qt Wayland Compositor Examples - Pure QML}{Pure QML example}.
+ * a look at the \l{Fancy Compositor}{Fancy Compositor example}.
*/
diff --git a/examples/wayland/minimal-qml/main.qml b/examples/wayland/minimal-qml/main.qml
index b7bcc4ca5..e1e1c18d3 100644
--- a/examples/wayland/minimal-qml/main.qml
+++ b/examples/wayland/minimal-qml/main.qml
@@ -46,17 +46,13 @@ WaylandCompositor {
//! [shells]
WlShell {
- onWlShellSurfaceCreated:
- shellSurfaces.append({shellSurface: shellSurface});
+ onWlShellSurfaceCreated: (shellSurface) => shellSurfaces.append({shellSurface: shellSurface});
}
XdgShell {
- onToplevelCreated:
- shellSurfaces.append({shellSurface: xdgSurface});
+ onToplevelCreated: (toplevel, xdgSurface) => shellSurfaces.append({shellSurface: xdgSurface});
}
IviApplication {
- onIviSurfaceCreated: {
- shellSurfaces.append({shellSurface: iviSurface});
- }
+ onIviSurfaceCreated: (iviSurface) => shellSurfaces.append({shellSurface: iviSurface});
}
//! [shells]
diff --git a/examples/wayland/multi-output/CMakeLists.txt b/examples/wayland/multi-output/CMakeLists.txt
index c24b9e5d7..8e59f977a 100644
--- a/examples/wayland/multi-output/CMakeLists.txt
+++ b/examples/wayland/multi-output/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(multi-output LANGUAGES CXX)
diff --git a/examples/wayland/multi-output/doc/src/multi-output.qdoc b/examples/wayland/multi-output/doc/src/multi-output.qdoc
index ee5a3c29d..5614099e9 100644
--- a/examples/wayland/multi-output/doc/src/multi-output.qdoc
+++ b/examples/wayland/multi-output/doc/src/multi-output.qdoc
@@ -2,8 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
- \title Qt Wayland Compositor Examples - Multi Output
+ \title Multi Output
\example multi-output
+ \examplecategory {Embedded}
\brief Multi Output is an example that demonstrates a compositor with multiple outputs.
\ingroup qtwaylandcompositor-examples
@@ -17,7 +18,7 @@
\image multi-output.jpg
For an introduction to the basic principles of creating a \l{Qt Wayland Compositor} with Qt,
- see the \l{Qt Wayland Compositor Examples - Minimal QML}{Minimal QML example}.
+ see the \l{Minimal QML}{Minimal QML example}.
\section1 Multiple Outputs
@@ -49,6 +50,5 @@
\l Qt::AA_ShareOpenGLContexts attribute must be set before the \l QGuiApplication
object is constructed.
- \sa {Qt Wayland Compositor Examples - Multi Screen},
- {Qt Wayland Compositor Examples - Overview Compositor}
+ \sa {Multi Screen}, {Overview Compositor}
*/
diff --git a/examples/wayland/multi-output/qml/ShellScreen.qml b/examples/wayland/multi-output/qml/ShellScreen.qml
index ae4092594..ffbb9f520 100644
--- a/examples/wayland/multi-output/qml/ShellScreen.qml
+++ b/examples/wayland/multi-output/qml/ShellScreen.qml
@@ -32,7 +32,7 @@ WaylandOutput {
id: clientCursor
x: mouseTracker.mouseX
y: mouseTracker.mouseY
- visible: surface !== null && mouseTracker.containsMouse
+ visible: surface != null && mouseTracker.containsMouse
seat : output.compositor.defaultSeat
}
}
diff --git a/examples/wayland/multi-output/qml/main.qml b/examples/wayland/multi-output/qml/main.qml
index 65b343ae4..26e227bcf 100644
--- a/examples/wayland/multi-output/qml/main.qml
+++ b/examples/wayland/multi-output/qml/main.qml
@@ -4,7 +4,6 @@
import QtQuick
import QtWayland.Compositor
import QtWayland.Compositor.XdgShell
-import QtWayland.Compositor.WlShell
WaylandCompositor {
id: comp
@@ -50,7 +49,7 @@ WaylandCompositor {
// ![xdgshell]
XdgShell {
- onToplevelCreated: {
+ onToplevelCreated: (toplevel, xdgSurface) => {
var item = chromeComponent.createObject(defaultOutput.surfaceArea, { "shellSurface": xdgSurface } );
item.surface.activated.connect(item.raise);
}
@@ -58,7 +57,7 @@ WaylandCompositor {
// ![xdgshell]
// ![onSurfaceRequested]
- onSurfaceRequested: {
+ onSurfaceRequested: (client, id, version) => {
var surface = surfaceComponent.createObject(comp, { } );
surface.initialize(comp, client, id, version);
}
diff --git a/examples/wayland/multi-screen/CMakeLists.txt b/examples/wayland/multi-screen/CMakeLists.txt
index f23f890bd..2d5ac21cb 100644
--- a/examples/wayland/multi-screen/CMakeLists.txt
+++ b/examples/wayland/multi-screen/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(multi-screen LANGUAGES CXX)
diff --git a/examples/wayland/multi-screen/doc/images/multi-screen.jpg b/examples/wayland/multi-screen/doc/images/multi-screen.jpg
new file mode 100644
index 000000000..f43aca07c
--- /dev/null
+++ b/examples/wayland/multi-screen/doc/images/multi-screen.jpg
Binary files differ
diff --git a/examples/wayland/multi-screen/doc/src/multi-screen.qdoc b/examples/wayland/multi-screen/doc/src/multi-screen.qdoc
index 9573cedfe..b8113e02f 100644
--- a/examples/wayland/multi-screen/doc/src/multi-screen.qdoc
+++ b/examples/wayland/multi-screen/doc/src/multi-screen.qdoc
@@ -2,8 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
- * \title Qt Wayland Compositor Examples - Multi Screen
+ * \title Multi Screen
* \example multi-screen
+ * \examplecategory {Embedded}
* \brief Multi Screen is a desktop-style Wayland compositor for multiple screens.
* \ingroup qtwaylandcompositor-examples
*
@@ -12,8 +13,10 @@
* Multi-screen is a desktop-style Wayland compositor example for multiple
* screens.
*
+ * \image multi-screen.jpg
+ *
* For an introduction to the basic principles of creating a \l{Qt Wayland Compositor} with Qt,
- * see the \l{Qt Wayland Compositor Examples - Minimal QML}{Minimal QML example}.
+ * see the \l{Minimal QML}{Minimal QML example}.
*
* \section1 Supporting multiple screens
*
@@ -45,7 +48,7 @@
* screens. The global position of the client is stored in a shared
* \l{ShellSurfaceItem::moveItem}{moveItem} and relative position of each screen's
* \l ShellSurfaceItem is calculated based on this. If the \c moveItem is currently outside the
- * bounds of one screen, its coordinates will reflect this, and it will be not be visible on that
+ * bounds of one screen, its coordinates will reflect this, and it will not be visible on that
* screen.
*
* \snippet multi-screen/qml/Chrome.qml position sync
@@ -61,5 +64,5 @@
*
* \snippet multi-screen/main.cpp share context
*
- * \sa {Qt Wayland Compositor Examples - Multi Output}
+ * \sa {Multi Output}
*/
diff --git a/examples/wayland/multi-screen/qml/Chrome.qml b/examples/wayland/multi-screen/qml/Chrome.qml
index 33e147870..d3485e81f 100644
--- a/examples/wayland/multi-screen/qml/Chrome.qml
+++ b/examples/wayland/multi-screen/qml/Chrome.qml
@@ -10,6 +10,7 @@ Item {
property alias shellSurface: surfaceItem.shellSurface
property alias surfaceItem: surfaceItem
property alias moveItem: surfaceItem.moveItem
+ property alias output: surfaceItem.output
//! [position sync]
x: surfaceItem.moveItem.x - surfaceItem.output.geometry.x
diff --git a/examples/wayland/multi-screen/qml/CompositorScreen.qml b/examples/wayland/multi-screen/qml/CompositorScreen.qml
index 5f1b34472..e449d6fa8 100644
--- a/examples/wayland/multi-screen/qml/CompositorScreen.qml
+++ b/examples/wayland/multi-screen/qml/CompositorScreen.qml
@@ -46,7 +46,7 @@ WaylandOutput {
x: mouseTracker.mouseX
y: mouseTracker.mouseY
seat: comp.defaultSeat
- visible: surface !== null && mouseTracker.containsMouse
+ visible: surface != null && mouseTracker.containsMouse
}
}
Shortcut {
diff --git a/examples/wayland/multi-screen/qml/main.qml b/examples/wayland/multi-screen/qml/main.qml
index dc2807c3c..1180d30b4 100644
--- a/examples/wayland/multi-screen/qml/main.qml
+++ b/examples/wayland/multi-screen/qml/main.qml
@@ -4,7 +4,6 @@
import QtQml
import QtQuick
-import QtQuick.Window as Window
import QtWayland.Compositor
import QtWayland.Compositor.XdgShell
import QtWayland.Compositor.WlShell
@@ -31,7 +30,7 @@ WaylandCompositor {
surfaceArea.color: "lightsteelblue"
text: name
compositor: comp
- screen: modelData
+ screen: emulated ? Qt.application.screens[0] : modelData
Component.onCompleted: if (!comp.defaultOutput) comp.defaultOutput = this
position: Qt.point(virtualX, virtualY)
windowed: emulated
@@ -54,11 +53,11 @@ WaylandCompositor {
}
WlShell {
- onWlShellSurfaceCreated: handleShellSurfaceCreated(shellSurface)
+ onWlShellSurfaceCreated: (shellSurface) => handleShellSurfaceCreated(shellSurface)
}
XdgShell {
- onToplevelCreated: handleShellSurfaceCreated(xdgSurface)
+ onToplevelCreated: (toplevel, xdgSurface) => handleShellSurfaceCreated(xdgSurface)
}
function createShellSurfaceItem(shellSurface, moveItem, output) {
diff --git a/examples/wayland/overview-compositor/CMakeLists.txt b/examples/wayland/overview-compositor/CMakeLists.txt
index 712d2feb6..7afe52982 100644
--- a/examples/wayland/overview-compositor/CMakeLists.txt
+++ b/examples/wayland/overview-compositor/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(overview-compositor LANGUAGES CXX)
diff --git a/examples/wayland/overview-compositor/doc/src/overview-compositor.qdoc b/examples/wayland/overview-compositor/doc/src/overview-compositor.qdoc
index d8408570c..8ac3dfae0 100644
--- a/examples/wayland/overview-compositor/doc/src/overview-compositor.qdoc
+++ b/examples/wayland/overview-compositor/doc/src/overview-compositor.qdoc
@@ -2,8 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
- * \title Qt Wayland Compositor Examples - Overview Compositor
+ * \title Overview Compositor
* \example overview-compositor
+ * \examplecategory {Embedded}
* \brief Overview Compositor shows how to switch between clients in a grid.
*
* \section1 Introduction
@@ -14,7 +15,7 @@
* \image overview-compositor.jpg
*
* For an introduction to the basic principles of creating a \l{Qt Wayland Compositor} with Qt,
- * see the \l{Qt Wayland Compositor Examples - Minimal QML}{Minimal QML example}.
+ * see the \l{Minimal QML}{Minimal QML example}.
*
* \section1 Application Grid
*
@@ -58,8 +59,7 @@
*
* This example shows one way to have the compositor visualize clients in different modes. Another
* way to achieve similar effects is to create multiple Qt Quick items that refer to the same
- * surface. See \l{Qt Wayland Compositor Examples - Multi Output}{the Multi Output example} for a
- * demonstration.
+ * surface. See \l{Multi Output}{the Multi Output example} for a demonstration.
*
* \ingroup qtwaylandcompositor-examples
*/
diff --git a/examples/wayland/overview-compositor/main.qml b/examples/wayland/overview-compositor/main.qml
index 5e6930d20..3d6f35aac 100644
--- a/examples/wayland/overview-compositor/main.qml
+++ b/examples/wayland/overview-compositor/main.qml
@@ -5,7 +5,7 @@ import QtQuick
import QtWayland.Compositor
import QtWayland.Compositor.XdgShell
import QtQuick.Window
-import QtQuick.Controls 2.0
+import QtQuick.Controls
WaylandCompositor {
WaylandOutput {
@@ -90,7 +90,7 @@ WaylandCompositor {
// ![XdgShell]
XdgShell {
- onToplevelCreated: {
+ onToplevelCreated: (toplevel, xdgSurface) => {
toplevels.append({xdgSurface});
toplevel.sendFullscreen(Qt.size(win.pixelWidth, win.pixelHeight));
}
diff --git a/examples/wayland/pure-qml/pure-qml.pro b/examples/wayland/pure-qml/pure-qml.pro
deleted file mode 100644
index 2214922e8..000000000
--- a/examples/wayland/pure-qml/pure-qml.pro
+++ /dev/null
@@ -1,18 +0,0 @@
-QT += gui qml
-
-SOURCES += \
- main.cpp
-
-OTHER_FILES = \
- qml/main.qml \
- qml/CompositorScreen.qml \
- qml/Chrome.qml \
- qml/Keyboard.qml \
- images/background.jpg \
-
-RESOURCES += pure-qml.qrc
-
-target.path = $$[QT_INSTALL_EXAMPLES]/wayland/pure-qml
-sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS pure-qml.pro
-sources.path = $$[QT_INSTALL_EXAMPLES]/wayland/pure-qml
-INSTALLS += target sources
diff --git a/examples/wayland/qtshell/CMakeLists.txt b/examples/wayland/qtshell/CMakeLists.txt
index 763dc2dc0..64db8a672 100644
--- a/examples/wayland/qtshell/CMakeLists.txt
+++ b/examples/wayland/qtshell/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cmake_minimum_required(VERSION 3.14)
project(qtshell LANGUAGES CXX)
diff --git a/examples/wayland/qtshell/doc/images/qtshell.jpg b/examples/wayland/qtshell/doc/images/qtshell.jpg
new file mode 100644
index 000000000..53b9aa189
--- /dev/null
+++ b/examples/wayland/qtshell/doc/images/qtshell.jpg
Binary files differ
diff --git a/examples/wayland/qtshell/doc/src/qtshell.qdoc b/examples/wayland/qtshell/doc/src/qtshell.qdoc
index 457bd92d0..2da1c1874 100644
--- a/examples/wayland/qtshell/doc/src/qtshell.qdoc
+++ b/examples/wayland/qtshell/doc/src/qtshell.qdoc
@@ -2,8 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
- * \title Qt Wayland Compositor Examples - QtShell Compositor
+ * \title QtShell Compositor
* \example qtshell
+ * \examplecategory {Embedded}
* \brief QtShell Compositor shows how to use the QtShell shell extension.
* \ingroup qtwaylandcompositor-examples
*
@@ -11,6 +12,8 @@
* complete Qt Wayland Compositor which uses the specialized
* \l{Shell Extensions - Qt Wayland Compositor}{shell extension protocol} called \l{QtShell}.
*
+ * \image qtshell.jpg
+ *
* The compositor is implemented with Qt Quick and QML.
*
* \section1 Making the Connection
@@ -23,7 +26,7 @@
*
* When a client connects to the QtShell interface, it creates a \l{QtShellSurface}. The compositor
* is notified of this by the emission of the
- * \l{QtWaylandCompositor::QtShell::qtShellSurfaceCreated()}{qtShellSurfaceCreated} signal. The
+ * \l [QML] {QtShell::}{qtShellSurfaceCreated} signal. The
* example then adds the shell surface to a ListModel for easy access later.
*
* \snippet qtshell/qml/CompositorScreen.qml handleShellSurface
diff --git a/examples/wayland/qtshell/qml/main.qml b/examples/wayland/qtshell/qml/main.qml
index 99813b576..7a4f505d5 100644
--- a/examples/wayland/qtshell/qml/main.qml
+++ b/examples/wayland/qtshell/qml/main.qml
@@ -15,7 +15,7 @@ WaylandCompositor {
//! [shell]
QtShell {
- onQtShellSurfaceCreated: screen.handleShellSurface(qtShellSurface)
+ onQtShellSurfaceCreated: (qtShellSurface) => screen.handleShellSurface(qtShellSurface)
}
//! [shell]
}
diff --git a/examples/wayland/server-buffer/CMakeLists.txt b/examples/wayland/server-buffer/CMakeLists.txt
deleted file mode 100644
index 48a68e96b..000000000
--- a/examples/wayland/server-buffer/CMakeLists.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-qt_internal_add_example(cpp-client)
-qt_internal_add_example(compositor)
diff --git a/examples/wayland/server-side-decoration/CMakeLists.txt b/examples/wayland/server-side-decoration/CMakeLists.txt
index 391fd5f9c..b56e96947 100644
--- a/examples/wayland/server-side-decoration/CMakeLists.txt
+++ b/examples/wayland/server-side-decoration/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(server-side-decoration LANGUAGES CXX)
diff --git a/examples/wayland/server-side-decoration/doc/src/server-side-decoration.qdoc b/examples/wayland/server-side-decoration/doc/src/server-side-decoration.qdoc
index 48a84609a..ebbd1b145 100644
--- a/examples/wayland/server-side-decoration/doc/src/server-side-decoration.qdoc
+++ b/examples/wayland/server-side-decoration/doc/src/server-side-decoration.qdoc
@@ -2,8 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
- * \title Qt Wayland Compositor Examples - Server Side Decoration Compositor
+ * \title Server Side Decoration Compositor
* \example server-side-decoration
+ * \examplecategory {Embedded}
* \brief Server Side Decoration Compositor is a simple example that demonstrates server side window decorations on xdg-shell.
* \ingroup qtwaylandcompositor-examples
*
@@ -15,7 +16,7 @@
* server-side window decorations.
*
* For an introduction to the basic principles of creating a \l{Qt Wayland Compositor} with Qt,
- * see the \l{Qt Wayland Compositor Examples - Minimal QML}{Minimal QML example}.
+ * see the \l{Minimal QML}{Minimal QML example}.
*
* \section1 Decorations
*
diff --git a/examples/wayland/server-side-decoration/main.qml b/examples/wayland/server-side-decoration/main.qml
index 881ee9bf3..421cefa95 100644
--- a/examples/wayland/server-side-decoration/main.qml
+++ b/examples/wayland/server-side-decoration/main.qml
@@ -63,7 +63,7 @@ WaylandCompositor {
// ![XdgShell]
XdgShell {
- onToplevelCreated: shellSurfaces.append({shellSurface: xdgSurface});
+ onToplevelCreated: (toplevel, xdgSurface) => shellSurfaces.append({shellSurface: xdgSurface});
}
XdgDecorationManagerV1 {
preferredMode: XdgToplevel.ServerSideDecoration
diff --git a/examples/wayland/spanning-screens/CMakeLists.txt b/examples/wayland/spanning-screens/CMakeLists.txt
index 2f2761855..0e4239033 100644
--- a/examples/wayland/spanning-screens/CMakeLists.txt
+++ b/examples/wayland/spanning-screens/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(spanning-screens LANGUAGES CXX)
diff --git a/examples/wayland/spanning-screens/doc/src/spanning-screens.qdoc b/examples/wayland/spanning-screens/doc/src/spanning-screens.qdoc
index dd783a7e9..7c548171c 100644
--- a/examples/wayland/spanning-screens/doc/src/spanning-screens.qdoc
+++ b/examples/wayland/spanning-screens/doc/src/spanning-screens.qdoc
@@ -2,8 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
- * \title Qt Wayland Compositor Examples - Spanning Screens
+ * \title Spanning Screens
* \example spanning-screens
+ * \examplecategory {Embedded}
* \brief Spanning Screens is an example that demonstrates how to let Wayland clients span multiple screens.
* \ingroup qtwaylandcompositor-examples
*
@@ -15,7 +16,7 @@
* \image spanning-screens.jpg
*
* For an introduction to the basic principles of creating a \l{Qt Wayland Compositor} with Qt,
- * see the \l{Qt Wayland Compositor Examples - Minimal QML}{Minimal QML example}.
+ * see the \l{Minimal QML}{Minimal QML example}.
*
* \section1 Supporting Multiple Screens
*
@@ -48,11 +49,10 @@
*
* Referencing the same client surface from multiple items is a tool which can be used for many
* things. For a demonstration of a desktop-style compositor where windows can be moved from screen
- * to screen, take a look at the
- * \l{Qt Wayland Compositor Examples - Multi Screen}{Multi Screen example}.
+ * to screen, take a look at the \l{Multi Screen}{Multi Screen example}.
*
- * The \l{Qt Wayland Compositor Examples - Multi Output}{Multi Output example} shows how client
- * surfaces can be displayed on multiple outputs with different sizes and other properties.
+ * The \l{Multi Output}{Multi Output example} shows how client surfaces can be displayed on multiple
+ * outputs with different sizes and other properties.
*
* \note In order to support multiple Wayland outputs in the same compositor, the
* \l Qt::AA_ShareOpenGLContexts attribute must be set before the \l QGuiApplication
diff --git a/examples/wayland/spanning-screens/main.qml b/examples/wayland/spanning-screens/main.qml
index bff344b7d..d47246dee 100644
--- a/examples/wayland/spanning-screens/main.qml
+++ b/examples/wayland/spanning-screens/main.qml
@@ -65,7 +65,7 @@ WaylandCompositor {
}
XdgShell {
- onToplevelCreated: {
+ onToplevelCreated: (toplevel, xdgSurface) => {
const shellSurface = xdgSurface;
// ![create items]
diff --git a/examples/wayland/wayland.pro b/examples/wayland/wayland.pro
index 4a4aaf81d..145e1ec64 100644
--- a/examples/wayland/wayland.pro
+++ b/examples/wayland/wayland.pro
@@ -11,7 +11,7 @@ qtConfig(opengl) {
qtHaveModule(quick) {
SUBDIRS += minimal-qml
SUBDIRS += spanning-screens
- SUBDIRS += pure-qml
+ SUBDIRS += fancy-compositor
SUBDIRS += multi-output
SUBDIRS += multi-screen
SUBDIRS += overview-compositor
@@ -22,11 +22,5 @@ qtHaveModule(quick) {
SUBDIRS += \
custom-extension \
custom-shell
-
- qtConfig(opengl) {
- SUBDIRS += \
- server-buffer
- }
}
- SUBDIRS += hwlayer-compositor
}
diff --git a/qt_cmdline.cmake b/qt_cmdline.cmake
index e74a6c8f1..3c00390fb 100644
--- a/qt_cmdline.cmake
+++ b/qt_cmdline.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
qt_commandline_subconfig(src)
qt_commandline_subconfig(src/client)
qt_commandline_subconfig(src/compositor)
diff --git a/src/3rdparty/protocol/cursor-shape-v1.xml b/src/3rdparty/protocol/cursor-shape-v1.xml
new file mode 100644
index 000000000..b6fbe08b7
--- /dev/null
+++ b/src/3rdparty/protocol/cursor-shape-v1.xml
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="cursor_shape_v1">
+ <copyright>
+ Copyright 2018 The Chromium Authors
+ Copyright 2023 Simon Ser
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+ </copyright>
+
+ <interface name="wp_cursor_shape_manager_v1" version="1">
+ <description summary="cursor shape manager">
+ This global allows clients to set cursor images by name instead of
+ creating and attaching buffers.
+
+ Warning! The protocol described in this file is currently in the testing
+ phase. Backward compatible changes may be added together with the
+ corresponding interface version bump. Backward incompatible changes can
+ only be done by creating a new major version of the extension.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the manager">
+ Destroy the cursor shape manager.
+ </description>
+ </request>
+
+ <request name="get_pointer">
+ <description summary="manage the cursor shape of a pointer device">
+ Obtain a wp_cursor_shape_device_v1 for a wl_pointer object.
+ </description>
+ <arg name="cursor_shape_device" type="new_id" interface="wp_cursor_shape_device_v1"/>
+ <arg name="pointer" type="object" interface="wl_pointer"/>
+ </request>
+
+ <request name="get_tablet_tool_v2">
+ <description summary="manage the cursor shape of a tablet tool device">
+ Obtain a wp_cursor_shape_device_v1 for a zwp_tablet_tool_v2 object.
+ </description>
+ <arg name="cursor_shape_device" type="new_id" interface="wp_cursor_shape_device_v1"/>
+ <arg name="tablet_tool" type="object" interface="zwp_tablet_tool_v2"/>
+ </request>
+ </interface>
+
+ <interface name="wp_cursor_shape_device_v1" version="1">
+ <description summary="cursor shape for a device">
+ This interface advertises the list of supported cursor shapes for a
+ device, and allows clients to set the cursor shape.
+ </description>
+
+ <enum name="shape">
+ <description summary="cursor shapes">
+ This enum describes cursor shapes.
+
+ The names are taken from the CSS W3C specification:
+ https://w3c.github.io/csswg-drafts/css-ui/#cursor
+ </description>
+ <entry name="default" value="1" summary="default cursor"/>
+ <entry name="context_menu" value="2" summary="a context menu is available for the object under the cursor"/>
+ <entry name="help" value="3" summary="help is available for the object under the cursor"/>
+ <entry name="pointer" value="4" summary="pointer that indicates a link or another interactive element"/>
+ <entry name="progress" value="5" summary="progress indicator"/>
+ <entry name="wait" value="6" summary="program is busy, user should wait"/>
+ <entry name="cell" value="7" summary="a cell or set of cells may be selected"/>
+ <entry name="crosshair" value="8" summary="simple crosshair"/>
+ <entry name="text" value="9" summary="text may be selected"/>
+ <entry name="vertical_text" value="10" summary="vertical text may be selected"/>
+ <entry name="alias" value="11" summary="drag-and-drop: alias of/shortcut to something is to be created"/>
+ <entry name="copy" value="12" summary="drag-and-drop: something is to be copied"/>
+ <entry name="move" value="13" summary="drag-and-drop: something is to be moved"/>
+ <entry name="no_drop" value="14" summary="drag-and-drop: the dragged item cannot be dropped at the current cursor location"/>
+ <entry name="not_allowed" value="15" summary="drag-and-drop: the requested action will not be carried out"/>
+ <entry name="grab" value="16" summary="drag-and-drop: something can be grabbed"/>
+ <entry name="grabbing" value="17" summary="drag-and-drop: something is being grabbed"/>
+ <entry name="e_resize" value="18" summary="resizing: the east border is to be moved"/>
+ <entry name="n_resize" value="19" summary="resizing: the north border is to be moved"/>
+ <entry name="ne_resize" value="20" summary="resizing: the north-east corner is to be moved"/>
+ <entry name="nw_resize" value="21" summary="resizing: the north-west corner is to be moved"/>
+ <entry name="s_resize" value="22" summary="resizing: the south border is to be moved"/>
+ <entry name="se_resize" value="23" summary="resizing: the south-east corner is to be moved"/>
+ <entry name="sw_resize" value="24" summary="resizing: the south-west corner is to be moved"/>
+ <entry name="w_resize" value="25" summary="resizing: the west border is to be moved"/>
+ <entry name="ew_resize" value="26" summary="resizing: the east and west borders are to be moved"/>
+ <entry name="ns_resize" value="27" summary="resizing: the north and south borders are to be moved"/>
+ <entry name="nesw_resize" value="28" summary="resizing: the north-east and south-west corners are to be moved"/>
+ <entry name="nwse_resize" value="29" summary="resizing: the north-west and south-east corners are to be moved"/>
+ <entry name="col_resize" value="30" summary="resizing: that the item/column can be resized horizontally"/>
+ <entry name="row_resize" value="31" summary="resizing: that the item/row can be resized vertically"/>
+ <entry name="all_scroll" value="32" summary="something can be scrolled in any direction"/>
+ <entry name="zoom_in" value="33" summary="something can be zoomed in"/>
+ <entry name="zoom_out" value="34" summary="something can be zoomed out"/>
+ </enum>
+
+ <enum name="error">
+ <entry name="invalid_shape" value="1"
+ summary="the specified shape value is invalid"/>
+ </enum>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the cursor shape device">
+ Destroy the cursor shape device.
+
+ The device cursor shape remains unchanged.
+ </description>
+ </request>
+
+ <request name="set_shape">
+ <description summary="set device cursor to the shape">
+ Sets the device cursor to the specified shape. The compositor will
+ change the cursor image based on the specified shape.
+
+ The cursor actually changes only if the input device focus is one of
+ the requesting client's surfaces. If any, the previous cursor image
+ (surface or shape) is replaced.
+
+ The "shape" argument must be a valid enum entry, otherwise the
+ invalid_shape protocol error is raised.
+
+ This is similar to the wl_pointer.set_cursor and
+ zwp_tablet_tool_v2.set_cursor requests, but this request accepts a
+ shape instead of contents in the form of a surface. Clients can mix
+ set_cursor and set_shape requests.
+
+ The serial parameter must match the latest wl_pointer.enter or
+ zwp_tablet_tool_v2.proximity_in serial number sent to the client.
+ Otherwise the request will be ignored.
+ </description>
+ <arg name="serial" type="uint" summary="serial number of the enter event"/>
+ <arg name="shape" type="uint" enum="shape"/>
+ </request>
+ </interface>
+</protocol>
diff --git a/src/3rdparty/protocol/fractional-scale-v1.xml b/src/3rdparty/protocol/fractional-scale-v1.xml
new file mode 100644
index 000000000..350bfc01e
--- /dev/null
+++ b/src/3rdparty/protocol/fractional-scale-v1.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="fractional_scale_v1">
+ <copyright>
+ Copyright © 2022 Kenny Levinsen
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+ </copyright>
+
+ <description summary="Protocol for requesting fractional surface scales">
+ This protocol allows a compositor to suggest for surfaces to render at
+ fractional scales.
+
+ A client can submit scaled content by utilizing wp_viewport. This is done by
+ creating a wp_viewport object for the surface and setting the destination
+ rectangle to the surface size before the scale factor is applied.
+
+ The buffer size is calculated by multiplying the surface size by the
+ intended scale.
+
+ The wl_surface buffer scale should remain set to 1.
+
+ If a surface has a surface-local size of 100 px by 50 px and wishes to
+ submit buffers with a scale of 1.5, then a buffer of 150px by 75 px should
+ be used and the wp_viewport destination rectangle should be 100 px by 50 px.
+
+ For toplevel surfaces, the size is rounded halfway away from zero. The
+ rounding algorithm for subsurface position and size is not defined.
+ </description>
+
+ <interface name="wp_fractional_scale_manager_v1" version="1">
+ <description summary="fractional surface scale information">
+ A global interface for requesting surfaces to use fractional scales.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="unbind the fractional surface scale interface">
+ Informs the server that the client will not be using this protocol
+ object anymore. This does not affect any other objects,
+ wp_fractional_scale_v1 objects included.
+ </description>
+ </request>
+
+ <enum name="error">
+ <entry name="fractional_scale_exists" value="0"
+ summary="the surface already has a fractional_scale object associated"/>
+ </enum>
+
+ <request name="get_fractional_scale">
+ <description summary="extend surface interface for scale information">
+ Create an add-on object for the the wl_surface to let the compositor
+ request fractional scales. If the given wl_surface already has a
+ wp_fractional_scale_v1 object associated, the fractional_scale_exists
+ protocol error is raised.
+ </description>
+ <arg name="id" type="new_id" interface="wp_fractional_scale_v1"
+ summary="the new surface scale info interface id"/>
+ <arg name="surface" type="object" interface="wl_surface"
+ summary="the surface"/>
+ </request>
+ </interface>
+
+ <interface name="wp_fractional_scale_v1" version="1">
+ <description summary="fractional scale interface to a wl_surface">
+ An additional interface to a wl_surface object which allows the compositor
+ to inform the client of the preferred scale.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="remove surface scale information for surface">
+ Destroy the fractional scale object. When this object is destroyed,
+ preferred_scale events will no longer be sent.
+ </description>
+ </request>
+
+ <event name="preferred_scale">
+ <description summary="notify of new preferred scale">
+ Notification of a new preferred scale for this surface that the
+ compositor suggests that the client should use.
+
+ The sent scale is the numerator of a fraction with a denominator of 120.
+ </description>
+ <arg name="scale" type="uint" summary="the new preferred scale"/>
+ </event>
+ </interface>
+</protocol>
diff --git a/src/3rdparty/protocol/qt_attribution.json b/src/3rdparty/protocol/qt_attribution.json
index f51599de0..6ced46a2b 100644
--- a/src/3rdparty/protocol/qt_attribution.json
+++ b/src/3rdparty/protocol/qt_attribution.json
@@ -119,17 +119,18 @@
},
{
- "Id": "wayland-text-input-unstable-v4-wip",
+ "Id": "wayland-text-input-unstable-v3",
"Name": "Wayland Text Input Protocol",
"QDocModule": "qtwaylandcompositor",
"QtUsage": "Used in the Qt Wayland Compositor, and the Qt Wayland platform plugin.",
- "Files": "text-input-unstable-v4-wip.xml",
+ "Files": "text-input-unstable-v3.xml",
"Description": "Adds support for compositors to act as input methods and send text to applications.",
"Homepage": "https://wayland.freedesktop.org",
- "Version": "unstable v4, WIP",
- "LicenseId": "HPND",
- "License": "HPND License",
- "LicenseFile": "HPND_LICENSE.txt",
+ "Version": "unstable v3",
+ "DownloadLocation": "https://cgit.freedesktop.org/wayland/wayland-protocols/plain/unstable/text-input/text-input-unstable-v3.xml",
+ "LicenseId": "MIT",
+ "License": "MIT License",
+ "LicenseFile": "MIT_LICENSE.txt",
"Copyright": "Copyright © 2012, 2013 Intel Corporation\nCopyright © 2015, 2016 Jan Arne Petersen\nCopyright © 2017, 2018 Red Hat, Inc.\nCopyright © 2018 Purism SPC"
},
@@ -224,15 +225,15 @@
"Name": "Wayland Text Input Protocol v1",
"QDocModule": "qtwaylandcompositor",
"QtUsage": "Used in the Qt Wayland platform plugin",
- "File": "text-input-unstable-v1.xml",
+ "Files": "text-input-unstable-v1.xml",
"Description": "Adds support for text input and input methods to applications running on Wayland servers that only support text-input-unstable-v1.",
"Homepage": "https://wayland.freedesktop.org",
"Version": "unstable v1",
"DownloadLocation": "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/unstable/text-input/text-input-unstable-v1.xml",
"LicenseId": "MIT",
- "License": "MIT LIcense",
- "License file": "MIT_LICENSE.txt",
+ "License": "MIT License",
+ "LicenseFile": "MIT_LICENSE.txt",
"Copyright": "Copyright © 2012, 2013 Intel Corporation"
},
@@ -301,5 +302,56 @@
"License": "MIT License",
"LicenseFile": "MIT_LICENSE.txt",
"Copyright": "Copyright © 2013, 2014 Collabora, Ltd."
+ },
+
+ {
+ "Id": "xdg-foreign-unstable-v2",
+ "Name": "Wayland XDG Foreign Protocol",
+ "QDocModule": "qtwaylandcompositor",
+ "QtUsage": "Used in the Qt Wayland platform plugin",
+ "Files": "xdg-foreign-unstable-v2.xml",
+
+ "Description": "Allows referencing surfaces of different clients",
+ "Homepage": "https://wayland.freedesktop.org",
+ "Version": "1",
+ "DownloadLocation": "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/raw/1.25/unstable/xdg-foreign/xdg-foreign-unstable-v2.xml",
+ "LicenseId": "MIT",
+ "License": "MIT License",
+ "LicenseFile": "MIT_LICENSE.txt",
+ "Copyright": "Copyright © 2015-2016 Red Hat Inc."
+ },
+
+ {
+ "Id": "fractional-scale-v1",
+ "Name": "Wayland Fractional Scale Protocol",
+ "QDocModule": "qtwaylandcompositor",
+ "QtUsage": "Used in the Qt Wayland platform plugin",
+ "Files": "fractional-scale-v1.xml",
+
+ "Description": "Send a preferred scale to different clients",
+ "Homepage": "https://wayland.freedesktop.org",
+ "Version": "1",
+ "DownloadLocation": "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/raw/1.31/unstable/fractional-scale/fractional-scale-v1.xml",
+ "LicenseId": "MIT",
+ "License": "MIT License",
+ "LicenseFile": "MIT_LICENSE.txt",
+ "Copyright": "Copyright © 2022 Kenny Levinsen"
+ },
+
+ {
+ "Id": "xdg-dialog-v1",
+ "Name": "Wayland Dialog Protocol",
+ "QDocModule": "qtwaylandcompositor",
+ "QtUsage": "Used in the Qt Wayland platform plugin",
+ "Files": "xdg-dialog-v1.xml",
+
+ "Description": "Register toplevel as dialogs",
+ "Homepage": "https://wayland.freedesktop.org",
+ "Version": "1",
+ "DownloadLocation": "",
+ "LicenseId": "MIT",
+ "License": "MIT License",
+ "LicenseFile": "MIT_LICENSE.txt",
+ "Copyright": "Copyright © 2023 Carlos Garnacho"
}
]
diff --git a/src/3rdparty/protocol/text-input-unstable-v4-wip.xml b/src/3rdparty/protocol/text-input-unstable-v3.xml
index 1041e6f74..1fae54d7b 100644
--- a/src/3rdparty/protocol/text-input-unstable-v4-wip.xml
+++ b/src/3rdparty/protocol/text-input-unstable-v3.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<protocol name="text_input_unstable_v4_wip">
+<protocol name="text_input_unstable_v3">
<copyright>
Copyright © 2012, 2013 Intel Corporation
Copyright © 2015, 2016 Jan Arne Petersen
@@ -47,9 +47,9 @@
interface version number is reset.
</description>
- <interface name="zwp_text_input_v4" version="1">
+ <interface name="zwp_text_input_v3" version="1">
<description summary="text input">
- The zwp_text_input_v4 interface represents text input and input methods
+ The zwp_text_input_v3 interface represents text input and input methods
associated with a seat. It provides enter/leave events to follow the
text input focus for a seat.
@@ -64,9 +64,9 @@
Lengths must be measured between two valid indices.
Focus moving throughout surfaces will result in the emission of
- zwp_text_input_v4.enter and zwp_text_input_v4.leave events. The focused
- surface must commit zwp_text_input_v4.enable and
- zwp_text_input_v4.disable requests as the keyboard focus moves across
+ zwp_text_input_v3.enter and zwp_text_input_v3.leave events. The focused
+ surface must commit zwp_text_input_v3.enable and
+ zwp_text_input_v3.disable requests as the keyboard focus moves across
editable and non-editable elements of the UI. Those two requests are not
expected to be paired with each other, the compositor must be able to
handle consecutive series of the same request.
@@ -91,9 +91,15 @@
This request must be issued every time the active text input changes
to a new one, including within the current surface. Use
- zwp_text_input_v4.disable when there is no longer any input focus on
+ zwp_text_input_v3.disable when there is no longer any input focus on
the current surface.
+ Clients must not enable more than one text input on the single seat
+ and should disable the current text input before enabling the new one.
+ At most one instance of text input may be in enabled state per instance,
+ Requests to enable the another text input when some text input is active
+ must be ignored by compositor.
+
This request resets all state associated with previous enable, disable,
set_surrounding_text, set_text_change_cause, set_content_type, and
set_cursor_rectangle requests, as well as the state associated with
@@ -104,11 +110,11 @@
functionality.
State set with this request is double-buffered. It will get applied on
- the next zwp_text_input_v4.commit request, and stay valid until the
+ the next zwp_text_input_v3.commit request, and stay valid until the
next committed enable or disable request.
The changes must be applied by the compositor after issuing a
- zwp_text_input_v4.commit request.
+ zwp_text_input_v3.commit request.
</description>
</request>
@@ -118,7 +124,7 @@
there is no focus on any text entry inside the surface).
State set with this request is double-buffered. It will get applied on
- the next zwp_text_input_v4.commit request.
+ the next zwp_text_input_v3.commit request.
</description>
</request>
@@ -149,7 +155,7 @@
purpose of this event.
Values set with this request are double-buffered. They will get applied
- on the next zwp_text_input_v4.commit request, and stay valid until the
+ on the next zwp_text_input_v3.commit request, and stay valid until the
next committed enable or disable request.
The initial state for affected fields is empty, meaning that the text
@@ -182,7 +188,7 @@
cause describes the source of the change.
The value set with this request is double-buffered. It must be applied
- and reset to initial at the next zwp_text_input_v4.commit request.
+ and reset to initial at the next zwp_text_input_v3.commit request.
The initial value of cause is input_method.
</description>
@@ -238,7 +244,7 @@
the behavior.
Values set with this request are double-buffered. They will get applied
- on the next zwp_text_input_v4.commit request.
+ on the next zwp_text_input_v3.commit request.
Subsequent attempts to update them may have no effect. The values
remain valid until the next committed enable or disable request.
@@ -261,7 +267,7 @@
issue this request, to signify lack of support to the compositor.
Values set with this request are double-buffered. They will get applied
- on the next zwp_text_input_v4.commit request, and stay valid until the
+ on the next zwp_text_input_v3.commit request, and stay valid until the
next committed enable or disable request.
The initial values describing a cursor rectangle are empty. That means
@@ -298,7 +304,7 @@
Neither current nor pending state are modified unless noted otherwise.
The compositor must count the number of commit requests coming from
- each zwp_text_input_v4 object and use the count as the serial in done
+ each zwp_text_input_v3 object and use the count as the serial in done
events.
</description>
</request>
@@ -307,6 +313,9 @@
<description summary="enter event">
Notification that this seat's text-input focus is on a certain surface.
+ If client has created multiple text input objects, compositor must send
+ this event to all of them.
+
When the seat has the keyboard capability the text-input focus follows
the keyboard focus. This event sets the current surface for the
text-input object.
@@ -321,7 +330,9 @@
set.
The leave notification clears the current surface. It is sent before
- the enter notification for the new focus.
+ the enter notification for the new focus. After leave event, compositor
+ must ignore requests from any text input instances until next enter
+ event.
When the seat has the keyboard capability the text-input focus follows
the keyboard focus.
@@ -345,7 +356,7 @@
the same, or as a text highlight otherwise.
Values set with this event are double-buffered. They must be applied
- and reset to initial on the next zwp_text_input_v4.done event.
+ and reset to initial on the next zwp_text_input_v3.done event.
The initial value of text is an empty string, and cursor_begin,
cursor_end and cursor_hidden are all 0.
@@ -362,7 +373,7 @@
result of some composing (pre-edit).
Values set with this event are double-buffered. They must be applied
- and reset to initial on the next zwp_text_input_v4.done event.
+ and reset to initial on the next zwp_text_input_v3.done event.
The initial value of text is an empty string.
</description>
@@ -382,7 +393,7 @@
sequence).
Values set with this event are double-buffered. They must be applied
- and reset to initial on the next zwp_text_input_v4.done event.
+ and reset to initial on the next zwp_text_input_v3.done event.
The initial values of both before_length and after_length are 0.
</description>
@@ -408,44 +419,23 @@
5. Insert new preedit text in cursor position.
6. Place cursor inside preedit text.
- The serial number reflects the last state of the zwp_text_input_v4
+ The serial number reflects the last state of the zwp_text_input_v3
object known to the compositor. The value of the serial argument must
be equal to the number of commit requests already issued on that object.
+
When the client receives a done event with a serial different than the
- number of past commit requests, it must proceed as normal, except it
- should not change the current state of the zwp_text_input_v4 object.
+ number of past commit requests, it must proceed with evaluating and
+ applying the changes as normal, except it should not change the current
+ state of the zwp_text_input_v3 object. All pending state requests
+ (set_surrounding_text, set_content_type and set_cursor_rectangle) on
+ the zwp_text_input_v3 object should be sent and committed after
+ receiving a zwp_text_input_v3.done event with a matching serial.
</description>
<arg name="serial" type="uint"/>
</event>
-
- <enum name="commit_mode">
- <description summary="focus commit mode">
- Pre-edit commit mode when the focus widget or the cursor position
- is changed.
- </description>
- <entry name="clear" value="0" summary="pre-edit text is cleared"/>
- <entry name="commit" value="1" summary="pre-edit text is committed"/>
- </enum>
-
- <event name="preedit_commit_mode">
- <description summary="pre-edit commit mode">
- Specify how the visible preedit should be handled
- when switching the focus widget or changing the cursor position,
- whether to commit the preedit text or clear the preedit text.
-
- This is usually used together with the preedit_string event.
-
- The commit behavior is the same for focus switch and
- cursor position change.
-
- The parameter mode selects the desired behavior and
- its value is one from the commit mode enum.
- </description>
- <arg name="mode" type="uint" enum="commit_mode"/>
- </event>
</interface>
- <interface name="zwp_text_input_manager_v4" version="1">
+ <interface name="zwp_text_input_manager_v3" version="1">
<description summary="text input manager">
A factory for text-input objects. This object is a global singleton.
</description>
@@ -460,7 +450,7 @@
<description summary="create a new text input object">
Creates a new text-input object for a given seat.
</description>
- <arg name="id" type="new_id" interface="zwp_text_input_v4"/>
+ <arg name="id" type="new_id" interface="zwp_text_input_v3"/>
<arg name="seat" type="object" interface="wl_seat"/>
</request>
</interface>
diff --git a/src/3rdparty/protocol/wayland.xml b/src/3rdparty/protocol/wayland.xml
index 471daf668..10e039d6e 100644
--- a/src/3rdparty/protocol/wayland.xml
+++ b/src/3rdparty/protocol/wayland.xml
@@ -177,9 +177,12 @@
<description summary="callback object">
Clients can handle the 'done' event to get notified when
the related request is done.
+
+ Note, because wl_callback objects are created from multiple independent
+ factory interfaces, the wl_callback interface is frozen at version 1.
</description>
- <event name="done">
+ <event name="done" type="destructor">
<description summary="done event">
Notify the client when the related request is done.
</description>
@@ -187,7 +190,7 @@
</event>
</interface>
- <interface name="wl_compositor" version="4">
+ <interface name="wl_compositor" version="6">
<description summary="the compositor singleton">
A compositor. This object is a singleton global. The
compositor is in charge of combining the contents of multiple
@@ -258,6 +261,12 @@
for the pool from the file descriptor passed when the pool was
created, but using the new size. This request can only be
used to make the pool bigger.
+
+ This request only changes the amount of bytes that are mmapped
+ by the server and does not touch the file corresponding to the
+ file descriptor passed at creation time. It is the client's
+ responsibility to ensure that the file is at least as big as
+ the new pool size.
</description>
<arg name="size" type="int" summary="new size of the pool, in bytes"/>
</request>
@@ -271,8 +280,8 @@
Clients can create wl_shm_pool objects using the create_pool
request.
- At connection setup time, the wl_shm object emits one or more
- format events to inform clients about the valid pixel formats
+ On binding the wl_shm object one or more format events
+ are emitted to inform clients about the valid pixel formats
that can be used for buffers.
</description>
@@ -296,6 +305,9 @@
The drm format codes match the macros defined in drm_fourcc.h, except
argb8888 and xrgb8888. The formats actually supported by the compositor
will be reported by the format event.
+
+ For all wl_shm formats and unless specified in another protocol
+ extension, pre-multiplied alpha is used for pixel values.
</description>
<!-- Note to protocol writers: don't update this list manually, instead
run the automated script that keeps it in sync with drm_fourcc.h. -->
@@ -403,6 +415,10 @@
<entry name="nv15" value="0x3531564e" summary="2x2 subsampled Cr:Cb plane"/>
<entry name="q410" value="0x30313451"/>
<entry name="q401" value="0x31303451"/>
+ <entry name="xrgb16161616" value="0x38345258" summary="[63:0] x:R:G:B 16:16:16:16 little endian"/>
+ <entry name="xbgr16161616" value="0x38344258" summary="[63:0] x:B:G:R 16:16:16:16 little endian"/>
+ <entry name="argb16161616" value="0x38345241" summary="[63:0] A:R:G:B 16:16:16:16 little endian"/>
+ <entry name="abgr16161616" value="0x38344241" summary="[63:0] A:B:G:R 16:16:16:16 little endian"/>
</enum>
<request name="create_pool">
@@ -431,10 +447,18 @@
<interface name="wl_buffer" version="1">
<description summary="content for a wl_surface">
A buffer provides the content for a wl_surface. Buffers are
- created through factory interfaces such as wl_drm, wl_shm or
- similar. It has a width and a height and can be attached to a
- wl_surface, but the mechanism by which a client provides and
- updates the contents is defined by the buffer factory interface.
+ created through factory interfaces such as wl_shm, wp_linux_buffer_params
+ (from the linux-dmabuf protocol extension) or similar. It has a width and
+ a height and can be attached to a wl_surface, but the mechanism by which a
+ client provides and updates the contents is defined by the buffer factory
+ interface.
+
+ If the buffer uses a format that has an alpha channel, the alpha channel
+ is assumed to be premultiplied in the color channels unless otherwise
+ specified.
+
+ Note, because wl_buffer objects are created from multiple independent
+ factory interfaces, the wl_buffer interface is frozen at version 1.
</description>
<request name="destroy" type="destructor">
@@ -606,8 +630,9 @@
<event name="source_actions" since="3">
<description summary="notify the source-side available actions">
This event indicates the actions offered by the data source. It
- will be sent right after wl_data_device.enter, or anytime the source
- side changes its offered actions through wl_data_source.set_actions.
+ will be sent immediately after creating the wl_data_offer object,
+ or anytime the source side changes its offered actions through
+ wl_data_source.set_actions.
</description>
<arg name="source_actions" type="uint" summary="actions offered by the data source"
enum="wl_data_device_manager.dnd_action"/>
@@ -849,11 +874,8 @@
a drag-and-drop icon. If the icon surface already has another role,
it raises a protocol error.
- The current and pending input regions of the icon wl_surface are
- cleared, and wl_surface.set_input_region is ignored until the
- wl_surface is no longer used as the icon surface. When the use
- as an icon ends, the current and pending input regions become
- undefined, and the wl_surface is unmapped.
+ The input region is ignored for wl_surfaces with the role of a
+ drag-and-drop icon.
</description>
<arg name="source" type="object" interface="wl_data_source" allow-null="true" summary="data source for the eventual transfer"/>
<arg name="origin" type="object" interface="wl_surface" summary="surface where the drag originates"/>
@@ -878,7 +900,7 @@
which will subsequently be used in either the
data_device.enter event (for drag-and-drop) or the
data_device.selection event (for selections). Immediately
- following the data_device_data_offer event, the new data_offer
+ following the data_device.data_offer event, the new data_offer
object will send out data_offer.offer events to describe the
mime types it offers.
</description>
@@ -948,9 +970,10 @@
immediately before receiving keyboard focus and when a new
selection is set while the client has keyboard focus. The
data_offer is valid until a new data_offer or NULL is received
- or until the client loses keyboard focus. The client must
- destroy the previous selection data_offer, if any, upon receiving
- this event.
+ or until the client loses keyboard focus. Switching surface with
+ keyboard focus within the same client doesn't mean a new selection
+ will be sent. The client must destroy the previous selection
+ data_offer, if any, upon receiving this event.
</description>
<arg name="id" type="object" interface="wl_data_offer" allow-null="true"
summary="selection data_offer object"/>
@@ -1038,7 +1061,8 @@
a basic surface.
Note! This protocol is deprecated and not intended for production use.
- For desktop-style user interfaces, use xdg_shell.
+ For desktop-style user interfaces, use xdg_shell. Compositors and clients
+ should not implement this interface.
</description>
<enum name="error">
@@ -1332,7 +1356,7 @@
</event>
</interface>
- <interface name="wl_surface" version="4">
+ <interface name="wl_surface" version="6">
<description summary="an onscreen surface">
A surface is a rectangular area that may be displayed on zero
or more outputs, and shown any number of times at the compositor's
@@ -1364,8 +1388,9 @@
that this request gives a role to a wl_surface. Often, this
request also creates a new protocol object that represents the
role and adds additional functionality to wl_surface. When a
- client wants to destroy a wl_surface, they must destroy this 'role
- object' before the wl_surface.
+ client wants to destroy a wl_surface, they must destroy this role
+ object before the wl_surface, otherwise a defunct_role_object error is
+ sent.
Destroying the role object does not remove the role from the
wl_surface, but it may stop the wl_surface from "playing the role".
@@ -1384,6 +1409,9 @@
<entry name="invalid_scale" value="0" summary="buffer scale value is invalid"/>
<entry name="invalid_transform" value="1" summary="buffer transform value is invalid"/>
<entry name="invalid_size" value="2" summary="buffer size is invalid"/>
+ <entry name="invalid_offset" value="3" summary="buffer offset is invalid"/>
+ <entry name="defunct_role_object" value="4"
+ summary="surface was destroyed before its role object"/>
</enum>
<request name="destroy" type="destructor">
@@ -1406,7 +1434,15 @@
buffer's upper left corner, relative to the current buffer's upper
left corner, in surface-local coordinates. In other words, the
x and y, combined with the new surface size define in which
- directions the surface's size changes.
+ directions the surface's size changes. Setting anything other than 0
+ as x and y arguments is discouraged, and should instead be replaced
+ with using the separate wl_surface.offset request.
+
+ When the bound wl_surface version is 5 or higher, passing any
+ non-zero x or y is a protocol violation, and will result in an
+ 'invalid_offset' error being raised. The x and y arguments are ignored
+ and do not change the pending state. To achieve equivalent semantics,
+ use wl_surface.offset.
Surface contents are double-buffered state, see wl_surface.commit.
@@ -1434,9 +1470,12 @@
from the same backing storage or use wp_linux_buffer_release.
Destroying the wl_buffer after wl_buffer.release does not change
- the surface contents. However, if the client destroys the
- wl_buffer before receiving the wl_buffer.release event, the surface
- contents become undefined immediately.
+ the surface contents. Destroying the wl_buffer before wl_buffer.release
+ is allowed as long as the underlying buffer storage isn't re-used (this
+ can happen e.g. on client process termination). However, if the client
+ destroys the wl_buffer before receiving the wl_buffer.release event and
+ mutates the underlying buffer storage, the surface contents become
+ undefined immediately.
If wl_surface.attach is sent with a NULL wl_buffer, the
following wl_surface.commit will remove the surface content.
@@ -1734,9 +1773,58 @@
<arg name="width" type="int" summary="width of damage rectangle"/>
<arg name="height" type="int" summary="height of damage rectangle"/>
</request>
+
+ <!-- Version 5 additions -->
+
+ <request name="offset" since="5">
+ <description summary="set the surface contents offset">
+ The x and y arguments specify the location of the new pending
+ buffer's upper left corner, relative to the current buffer's upper
+ left corner, in surface-local coordinates. In other words, the
+ x and y, combined with the new surface size define in which
+ directions the surface's size changes.
+
+ Surface location offset is double-buffered state, see
+ wl_surface.commit.
+
+ This request is semantically equivalent to and the replaces the x and y
+ arguments in the wl_surface.attach request in wl_surface versions prior
+ to 5. See wl_surface.attach for details.
+ </description>
+ <arg name="x" type="int" summary="surface-local x coordinate"/>
+ <arg name="y" type="int" summary="surface-local y coordinate"/>
+ </request>
+
+ <!-- Version 6 additions -->
+
+ <event name="preferred_buffer_scale" since="6">
+ <description summary="preferred buffer scale for the surface">
+ This event indicates the preferred buffer scale for this surface. It is
+ sent whenever the compositor's preference changes.
+
+ It is intended that scaling aware clients use this event to scale their
+ content and use wl_surface.set_buffer_scale to indicate the scale they
+ have rendered with. This allows clients to supply a higher detail
+ buffer.
+ </description>
+ <arg name="factor" type="int" summary="preferred scaling factor"/>
+ </event>
+
+ <event name="preferred_buffer_transform" since="6">
+ <description summary="preferred buffer transform for the surface">
+ This event indicates the preferred buffer transform for this surface.
+ It is sent whenever the compositor's preference changes.
+
+ It is intended that transform aware clients use this event to apply the
+ transform to their content and use wl_surface.set_buffer_transform to
+ indicate the transform they have rendered with.
+ </description>
+ <arg name="transform" type="uint" enum="wl_output.transform"
+ summary="preferred transform"/>
+ </event>
</interface>
- <interface name="wl_seat" version="7">
+ <interface name="wl_seat" version="9">
<description summary="group of input devices">
A seat is a group of keyboards, pointer and touch devices. This
object is published as a global during start up, or when such a
@@ -1838,9 +1926,22 @@
<event name="name" since="2">
<description summary="unique identifier for this seat">
- In a multiseat configuration this can be used by the client to help
- identify which physical devices the seat represents. Based on
- the seat configuration used by the compositor.
+ In a multi-seat configuration the seat name can be used by clients to
+ help identify which physical devices the seat represents.
+
+ The seat name is a UTF-8 string with no convention defined for its
+ contents. Each name is unique among all wl_seat globals. The name is
+ only guaranteed to be unique for the current compositor instance.
+
+ The same seat names are used for all clients. Thus, the name can be
+ shared across processes to refer to a specific wl_seat global.
+
+ The name event is sent after binding to the seat global. This event is
+ only sent once per seat object, and the name does not change over the
+ lifetime of the wl_seat global.
+
+ Compositors may re-use the same seat name if the wl_seat global is
+ destroyed and re-created later.
</description>
<arg name="name" type="string" summary="seat identifier"/>
</event>
@@ -1856,7 +1957,7 @@
</interface>
- <interface name="wl_pointer" version="7">
+ <interface name="wl_pointer" version="9">
<description summary="pointer input device">
The wl_pointer interface represents one or more input devices,
such as mice, which control the pointer location and pointer_focus
@@ -1900,11 +2001,13 @@
pointer surface to this request with new values for hotspot_x
and hotspot_y.
- The current and pending input regions of the wl_surface are
- cleared, and wl_surface.set_input_region is ignored until the
- wl_surface is no longer used as the cursor. When the use as a
- cursor ends, the current and pending input regions become
- undefined, and the wl_surface is unmapped.
+ The input region is ignored for wl_surfaces with the role of
+ a cursor. When the use as a cursor ends, the wl_surface is
+ unmapped.
+
+ The serial parameter must match the latest wl_pointer.enter
+ serial number sent to the client. Otherwise the request will be
+ ignored.
</description>
<arg name="serial" type="uint" summary="serial number of the enter event"/>
<arg name="surface" type="object" interface="wl_surface" allow-null="true"
@@ -2152,6 +2255,9 @@
This event carries the axis value of the wl_pointer.axis event in
discrete steps (e.g. mouse wheel clicks).
+ This event is deprecated with wl_pointer version 8 - this event is not
+ sent to clients supporting version 8 or later.
+
This event does not occur on its own, it is coupled with a
wl_pointer.axis event that represents this axis value on a
continuous scale. The protocol guarantees that each axis_discrete
@@ -2159,7 +2265,8 @@
axis number within the same wl_pointer.frame. Note that the protocol
allows for other events to occur between the axis_discrete and
its coupled axis event, including other axis_discrete or axis
- events.
+ events. A wl_pointer.frame must not contain more than one axis_discrete
+ event per axis type.
This event is optional; continuous scrolling devices
like two-finger scrolling on touchpads do not have discrete
@@ -2177,9 +2284,93 @@
<arg name="axis" type="uint" enum="axis" summary="axis type"/>
<arg name="discrete" type="int" summary="number of steps"/>
</event>
+
+ <event name="axis_value120" since="8">
+ <description summary="axis high-resolution scroll event">
+ Discrete high-resolution scroll information.
+
+ This event carries high-resolution wheel scroll information,
+ with each multiple of 120 representing one logical scroll step
+ (a wheel detent). For example, an axis_value120 of 30 is one quarter of
+ a logical scroll step in the positive direction, a value120 of
+ -240 are two logical scroll steps in the negative direction within the
+ same hardware event.
+ Clients that rely on discrete scrolling should accumulate the
+ value120 to multiples of 120 before processing the event.
+
+ The value120 must not be zero.
+
+ This event replaces the wl_pointer.axis_discrete event in clients
+ supporting wl_pointer version 8 or later.
+
+ Where a wl_pointer.axis_source event occurs in the same
+ wl_pointer.frame, the axis source applies to this event.
+
+ The order of wl_pointer.axis_value120 and wl_pointer.axis_source is
+ not guaranteed.
+ </description>
+ <arg name="axis" type="uint" enum="axis" summary="axis type"/>
+ <arg name="value120" type="int" summary="scroll distance as fraction of 120"/>
+ </event>
+
+ <!-- Version 9 additions -->
+
+ <enum name="axis_relative_direction">
+ <description summary="axis relative direction">
+ This specifies the direction of the physical motion that caused a
+ wl_pointer.axis event, relative to the wl_pointer.axis direction.
+ </description>
+ <entry name="identical" value="0"
+ summary="physical motion matches axis direction"/>
+ <entry name="inverted" value="1"
+ summary="physical motion is the inverse of the axis direction"/>
+ </enum>
+
+ <event name="axis_relative_direction" since="9">
+ <description summary="axis relative physical direction event">
+ Relative directional information of the entity causing the axis
+ motion.
+
+ For a wl_pointer.axis event, the wl_pointer.axis_relative_direction
+ event specifies the movement direction of the entity causing the
+ wl_pointer.axis event. For example:
+ - if a user's fingers on a touchpad move down and this
+ causes a wl_pointer.axis vertical_scroll down event, the physical
+ direction is 'identical'
+ - if a user's fingers on a touchpad move down and this causes a
+ wl_pointer.axis vertical_scroll up scroll up event ('natural
+ scrolling'), the physical direction is 'inverted'.
+
+ A client may use this information to adjust scroll motion of
+ components. Specifically, enabling natural scrolling causes the
+ content to change direction compared to traditional scrolling.
+ Some widgets like volume control sliders should usually match the
+ physical direction regardless of whether natural scrolling is
+ active. This event enables clients to match the scroll direction of
+ a widget to the physical direction.
+
+ This event does not occur on its own, it is coupled with a
+ wl_pointer.axis event that represents this axis value.
+ The protocol guarantees that each axis_relative_direction event is
+ always followed by exactly one axis event with the same
+ axis number within the same wl_pointer.frame. Note that the protocol
+ allows for other events to occur between the axis_relative_direction
+ and its coupled axis event.
+
+ The axis number is identical to the axis number in the associated
+ axis event.
+
+ The order of wl_pointer.axis_relative_direction,
+ wl_pointer.axis_discrete and wl_pointer.axis_source is not
+ guaranteed.
+ </description>
+ <arg name="axis" type="uint" enum="axis" summary="axis type"/>
+ <arg name="direction" type="uint" enum="axis_relative_direction"
+ summary="physical direction relative to axis motion"/>
+ </event>
</interface>
- <interface name="wl_keyboard" version="7">
+ <interface name="wl_keyboard" version="9">
<description summary="keyboard input device">
The wl_keyboard interface represents one or more keyboards
associated with a seat.
@@ -2193,13 +2384,14 @@
<entry name="no_keymap" value="0"
summary="no keymap; client must understand how to interpret the raw keycode"/>
<entry name="xkb_v1" value="1"
- summary="libxkbcommon compatible; to determine the xkb keycode, clients must add 8 to the key event keycode"/>
+ summary="libxkbcommon compatible, null-terminated string; to determine the xkb keycode, clients must add 8 to the key event keycode"/>
</enum>
<event name="keymap">
<description summary="keyboard mapping">
This event provides a file descriptor to the client which can be
- memory-mapped to provide a keyboard mapping description.
+ memory-mapped in read-only mode to provide a keyboard mapping
+ description.
From version 7 onwards, the fd must be mapped with MAP_PRIVATE by
the recipient, as MAP_SHARED may fail.
@@ -2305,7 +2497,7 @@
</event>
</interface>
- <interface name="wl_touch" version="7">
+ <interface name="wl_touch" version="9">
<description summary="touchscreen input device">
The wl_touch interface represents a touchscreen
associated with a seat.
@@ -2449,7 +2641,7 @@
</event>
</interface>
- <interface name="wl_output" version="3">
+ <interface name="wl_output" version="4">
<description summary="compositor output region">
An output describes part of the compositor geometry. The
compositor works in the 'compositor coordinate system' and an
@@ -2505,12 +2697,15 @@
The physical size can be set to zero if it doesn't make sense for this
output (e.g. for projectors or virtual outputs).
+ The geometry event will be followed by a done event (starting from
+ version 2).
+
Note: wl_output only advertises partial information about the output
position and identification. Some compositors, for instance those not
implementing a desktop-style output layout or those exposing virtual
outputs, might fake this information. Instead of using x and y, clients
should use xdg_output.logical_position. Instead of using make and model,
- clients should use xdg_output.name and xdg_output.description.
+ clients should use name and description.
</description>
<arg name="x" type="int"
summary="x position within the global compositor space"/>
@@ -2566,6 +2761,9 @@
The vertical refresh rate can be set to zero if it doesn't make
sense for this output (e.g. for virtual outputs).
+ The mode event will be followed by a done event (starting from
+ version 2).
+
Clients should not use the refresh rate to schedule frames. Instead,
they should use the wl_surface.frame event or the presentation-time
protocol.
@@ -2612,6 +2810,8 @@
the scale of the output. That way the compositor can
avoid scaling the surface, and the client can supply
a higher detail image.
+
+ The scale event will be followed by a done event.
</description>
<arg name="factor" type="int" summary="scaling factor of output"/>
</event>
@@ -2624,6 +2824,62 @@
use the output object anymore.
</description>
</request>
+
+ <!-- Version 4 additions -->
+
+ <event name="name" since="4">
+ <description summary="name of this output">
+ Many compositors will assign user-friendly names to their outputs, show
+ them to the user, allow the user to refer to an output, etc. The client
+ may wish to know this name as well to offer the user similar behaviors.
+
+ The name is a UTF-8 string with no convention defined for its contents.
+ Each name is unique among all wl_output globals. The name is only
+ guaranteed to be unique for the compositor instance.
+
+ The same output name is used for all clients for a given wl_output
+ global. Thus, the name can be shared across processes to refer to a
+ specific wl_output global.
+
+ The name is not guaranteed to be persistent across sessions, thus cannot
+ be used to reliably identify an output in e.g. configuration files.
+
+ Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do
+ not assume that the name is a reflection of an underlying DRM connector,
+ X11 connection, etc.
+
+ The name event is sent after binding the output object. This event is
+ only sent once per output object, and the name does not change over the
+ lifetime of the wl_output global.
+
+ Compositors may re-use the same output name if the wl_output global is
+ destroyed and re-created later. Compositors should avoid re-using the
+ same name if possible.
+
+ The name event will be followed by a done event.
+ </description>
+ <arg name="name" type="string" summary="output name"/>
+ </event>
+
+ <event name="description" since="4">
+ <description summary="human-readable description of this output">
+ Many compositors can produce human-readable descriptions of their
+ outputs. The client may wish to know this description as well, e.g. for
+ output selection purposes.
+
+ The description is a UTF-8 string with no convention defined for its
+ contents. The description is not guaranteed to be unique among all
+ wl_output globals. Examples might include 'Foocorp 11" Display' or
+ 'Virtual X11 output via :1'.
+
+ The description event is sent after binding the output object and
+ whenever the description changes. The description is optional, and may
+ not be sent at all.
+
+ The description event will be followed by a done event.
+ </description>
+ <arg name="description" type="string" summary="output description"/>
+ </event>
</interface>
<interface name="wl_region" version="1">
@@ -2695,6 +2951,8 @@
<enum name="error">
<entry name="bad_surface" value="0"
summary="the to-be sub-surface is invalid"/>
+ <entry name="bad_parent" value="1"
+ summary="the to-be sub-surface parent is invalid"/>
</enum>
<request name="get_subsurface">
@@ -2704,14 +2962,18 @@
plain wl_surface into a sub-surface.
The to-be sub-surface must not already have another role, and it
- must not have an existing wl_subsurface object. Otherwise a protocol
- error is raised.
+ must not have an existing wl_subsurface object. Otherwise the
+ bad_surface protocol error is raised.
Adding sub-surfaces to a parent is a double-buffered operation on the
parent (see wl_surface.commit). The effect of adding a sub-surface
becomes visible on the next time the state of the parent surface is
applied.
+ The parent surface must not be one of the child surface's descendants,
+ and the parent must be different from the child surface, otherwise the
+ bad_parent protocol error is raised.
+
This request modifies the behaviour of wl_surface.commit request on
the sub-surface, see the documentation on wl_subsurface interface.
</description>
@@ -2766,12 +3028,10 @@
synchronized mode, and then assume that all its child and grand-child
sub-surfaces are synchronized, too, without explicitly setting them.
- If the wl_surface associated with the wl_subsurface is destroyed, the
- wl_subsurface object becomes inert. Note, that destroying either object
- takes effect immediately. If you need to synchronize the removal
- of a sub-surface to the parent surface update, unmap the sub-surface
- first by attaching a NULL wl_buffer, update parent, and then destroy
- the sub-surface.
+ Destroying a sub-surface takes effect immediately. If you need to
+ synchronize the removal of a sub-surface to the parent surface update,
+ unmap the sub-surface first by attaching a NULL wl_buffer, update parent,
+ and then destroy the sub-surface.
If the parent wl_surface object is destroyed, the sub-surface is
unmapped.
@@ -2782,8 +3042,7 @@
The sub-surface interface is removed from the wl_surface object
that was turned into a sub-surface with a
wl_subcompositor.get_subsurface request. The wl_surface's association
- to the parent is deleted, and the wl_surface loses its role as
- a sub-surface. The wl_surface is unmapped immediately.
+ to the parent is deleted. The wl_surface is unmapped immediately.
</description>
</request>
diff --git a/src/3rdparty/protocol/xdg-dialog-v1.xml b/src/3rdparty/protocol/xdg-dialog-v1.xml
new file mode 100644
index 000000000..ed2141132
--- /dev/null
+++ b/src/3rdparty/protocol/xdg-dialog-v1.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="dialog_v1">
+ <copyright>
+ Copyright © 2023 Carlos Garnacho
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+ </copyright>
+
+ <interface name="xdg_wm_dialog_v1" version="1">
+ <description summary="create dialogs related to other toplevels">
+ The xdg_wm_dialog_v1 interface is exposed as a global object allowing
+ to register surfaces with a xdg_toplevel role as "dialogs" relative to
+ another toplevel.
+
+ The compositor may let this relation influence how the surface is
+ placed, displayed or interacted with.
+
+ Warning! The protocol described in this file is currently in the testing
+ phase. Backward compatible changes may be added together with the
+ corresponding interface version bump. Backward incompatible changes can
+ only be done by creating a new major version of the extension.
+ </description>
+
+ <enum name="error">
+ <entry name="already_used" value="0"
+ summary="the xdg_toplevel object has already been used to create a xdg_dialog_v1"/>
+ </enum>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the dialog manager object">
+ Destroys the xdg_wm_dialog_v1 object. This does not affect
+ the xdg_dialog_v1 objects generated through it.
+ </description>
+ </request>
+
+ <request name="get_xdg_dialog">
+ <description summary="create a dialog object">
+ Creates a xdg_dialog_v1 object for the given toplevel. See the interface
+ description for more details.
+
+ Compositors must raise an already_used error if clients attempt to
+ create multiple xdg_dialog_v1 objects for the same xdg_toplevel.
+ </description>
+ <arg name="id" type="new_id" interface="xdg_dialog_v1"/>
+ <arg name="toplevel" type="object" interface="xdg_toplevel"/>
+ </request>
+ </interface>
+
+ <interface name="xdg_dialog_v1" version="1">
+ <description summary="dialog object">
+ A xdg_dialog_v1 object is an ancillary object tied to a xdg_toplevel. Its
+ purpose is hinting the compositor that the toplevel is a "dialog" (e.g. a
+ temporary window) relative to another toplevel (see
+ xdg_toplevel.set_parent). If the xdg_toplevel is destroyed, the xdg_dialog_v1
+ becomes inert.
+
+ Through this object, the client may provide additional hints about
+ the purpose of the secondary toplevel. This interface has no effect
+ on toplevels that are not attached to a parent toplevel.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the dialog object">
+ Destroys the xdg_dialog_v1 object. If this object is destroyed
+ before the related xdg_toplevel, the compositor should unapply its
+ effects.
+ </description>
+ </request>
+
+ <request name="set_modal">
+ <description summary="mark dialog as modal">
+ Hints that the dialog has "modal" behavior. Modal dialogs typically
+ require to be fully addressed by the user (i.e. closed) before resuming
+ interaction with the parent toplevel, and may require a distinct
+ presentation.
+
+ Clients must implement the logic to filter events in the parent
+ toplevel on their own.
+
+ Compositors may choose any policy in event delivery to the parent
+ toplevel, from delivering all events unfiltered to using them for
+ internal consumption.
+ </description>
+ </request>
+
+ <request name="unset_modal">
+ <description summary="mark dialog as not modal">
+ Drops the hint that this dialog has "modal" behavior. See
+ xdg_dialog_v1.set_modal for more details.
+ </description>
+ </request>
+ </interface>
+</protocol>
diff --git a/src/3rdparty/protocol/xdg-foreign-unstable-v2.xml b/src/3rdparty/protocol/xdg-foreign-unstable-v2.xml
new file mode 100644
index 000000000..cc3271dca
--- /dev/null
+++ b/src/3rdparty/protocol/xdg-foreign-unstable-v2.xml
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xdg_foreign_unstable_v2">
+
+ <copyright>
+ Copyright © 2015-2016 Red Hat Inc.
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+ </copyright>
+
+ <description summary="Protocol for exporting xdg surface handles">
+ This protocol specifies a way for making it possible to reference a surface
+ of a different client. With such a reference, a client can, by using the
+ interfaces provided by this protocol, manipulate the relationship between
+ its own surfaces and the surface of some other client. For example, stack
+ some of its own surface above the other clients surface.
+
+ In order for a client A to get a reference of a surface of client B, client
+ B must first export its surface using xdg_exporter.export_toplevel. Upon
+ doing this, client B will receive a handle (a unique string) that it may
+ share with client A in some way (for example D-Bus). After client A has
+ received the handle from client B, it may use xdg_importer.import_toplevel
+ to create a reference to the surface client B just exported. See the
+ corresponding requests for details.
+
+ A possible use case for this is out-of-process dialogs. For example when a
+ sandboxed client without file system access needs the user to select a file
+ on the file system, given sandbox environment support, it can export its
+ surface, passing the exported surface handle to an unsandboxed process that
+ can show a file browser dialog and stack it above the sandboxed client's
+ surface.
+
+ Warning! The protocol described in this file is experimental and backward
+ incompatible changes may be made. Backward compatible changes may be added
+ together with the corresponding interface version bump. Backward
+ incompatible changes are done by bumping the version number in the protocol
+ and interface names and resetting the interface version. Once the protocol
+ is to be declared stable, the 'z' prefix and the version number in the
+ protocol and interface names are removed and the interface version number is
+ reset.
+ </description>
+
+ <interface name="zxdg_exporter_v2" version="1">
+ <description summary="interface for exporting surfaces">
+ A global interface used for exporting surfaces that can later be imported
+ using xdg_importer.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the xdg_exporter object">
+ Notify the compositor that the xdg_exporter object will no longer be
+ used.
+ </description>
+ </request>
+
+ <enum name="error">
+ <description summary="error values">
+ These errors can be emitted in response to invalid xdg_exporter
+ requests.
+ </description>
+ <entry name="invalid_surface" value="0" summary="surface is not an xdg_toplevel"/>
+ </enum>
+
+ <request name="export_toplevel">
+ <description summary="export a toplevel surface">
+ The export_toplevel request exports the passed surface so that it can later be
+ imported via xdg_importer. When called, a new xdg_exported object will
+ be created and xdg_exported.handle will be sent immediately. See the
+ corresponding interface and event for details.
+
+ A surface may be exported multiple times, and each exported handle may
+ be used to create an xdg_imported multiple times. Only xdg_toplevel
+ equivalent surfaces may be exported, otherwise an invalid_surface
+ protocol error is sent.
+ </description>
+ <arg name="id" type="new_id" interface="zxdg_exported_v2"
+ summary="the new xdg_exported object"/>
+ <arg name="surface" type="object" interface="wl_surface"
+ summary="the surface to export"/>
+ </request>
+ </interface>
+
+ <interface name="zxdg_importer_v2" version="1">
+ <description summary="interface for importing surfaces">
+ A global interface used for importing surfaces exported by xdg_exporter.
+ With this interface, a client can create a reference to a surface of
+ another client.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the xdg_importer object">
+ Notify the compositor that the xdg_importer object will no longer be
+ used.
+ </description>
+ </request>
+
+ <request name="import_toplevel">
+ <description summary="import a toplevel surface">
+ The import_toplevel request imports a surface from any client given a handle
+ retrieved by exporting said surface using xdg_exporter.export_toplevel.
+ When called, a new xdg_imported object will be created. This new object
+ represents the imported surface, and the importing client can
+ manipulate its relationship using it. See xdg_imported for details.
+ </description>
+ <arg name="id" type="new_id" interface="zxdg_imported_v2"
+ summary="the new xdg_imported object"/>
+ <arg name="handle" type="string"
+ summary="the exported surface handle"/>
+ </request>
+ </interface>
+
+ <interface name="zxdg_exported_v2" version="1">
+ <description summary="an exported surface handle">
+ An xdg_exported object represents an exported reference to a surface. The
+ exported surface may be referenced as long as the xdg_exported object not
+ destroyed. Destroying the xdg_exported invalidates any relationship the
+ importer may have established using xdg_imported.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="unexport the exported surface">
+ Revoke the previously exported surface. This invalidates any
+ relationship the importer may have set up using the xdg_imported created
+ given the handle sent via xdg_exported.handle.
+ </description>
+ </request>
+
+ <event name="handle">
+ <description summary="the exported surface handle">
+ The handle event contains the unique handle of this exported surface
+ reference. It may be shared with any client, which then can use it to
+ import the surface by calling xdg_importer.import_toplevel. A handle
+ may be used to import the surface multiple times.
+ </description>
+ <arg name="handle" type="string" summary="the exported surface handle"/>
+ </event>
+ </interface>
+
+ <interface name="zxdg_imported_v2" version="1">
+ <description summary="an imported surface handle">
+ An xdg_imported object represents an imported reference to surface exported
+ by some client. A client can use this interface to manipulate
+ relationships between its own surfaces and the imported surface.
+ </description>
+
+ <enum name="error">
+ <description summary="error values">
+ These errors can be emitted in response to invalid xdg_imported
+ requests.
+ </description>
+ <entry name="invalid_surface" value="0" summary="surface is not an xdg_toplevel"/>
+ </enum>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the xdg_imported object">
+ Notify the compositor that it will no longer use the xdg_imported
+ object. Any relationship that may have been set up will at this point
+ be invalidated.
+ </description>
+ </request>
+
+ <request name="set_parent_of">
+ <description summary="set as the parent of some surface">
+ Set the imported surface as the parent of some surface of the client.
+ The passed surface must be an xdg_toplevel equivalent, otherwise an
+ invalid_surface protocol error is sent. Calling this function sets up
+ a surface to surface relation with the same stacking and positioning
+ semantics as xdg_toplevel.set_parent.
+ </description>
+ <arg name="surface" type="object" interface="wl_surface"
+ summary="the child surface"/>
+ </request>
+
+ <event name="destroyed">
+ <description summary="the imported surface handle has been destroyed">
+ The imported surface handle has been destroyed and any relationship set
+ up has been invalidated. This may happen for various reasons, for
+ example if the exported surface or the exported surface handle has been
+ destroyed, if the handle used for importing was invalid.
+ </description>
+ </event>
+ </interface>
+
+</protocol>
diff --git a/src/3rdparty/protocol/xdg-shell.xml b/src/3rdparty/protocol/xdg-shell.xml
index 3a87a9ed6..777eaa749 100644
--- a/src/3rdparty/protocol/xdg-shell.xml
+++ b/src/3rdparty/protocol/xdg-shell.xml
@@ -29,7 +29,7 @@
DEALINGS IN THE SOFTWARE.
</copyright>
- <interface name="xdg_wm_base" version="2">
+ <interface name="xdg_wm_base" version="6">
<description summary="create desktop-style surfaces">
The xdg_wm_base interface is exposed as a global object enabling clients
to turn their wl_surfaces into windows in a desktop environment. It
@@ -50,6 +50,8 @@
summary="the client provided an invalid surface state"/>
<entry name="invalid_positioner" value="5"
summary="the client provided an invalid positioner"/>
+ <entry name="unresponsive" value="6"
+ summary="the client didn’t respond to a ping event in time"/>
</enum>
<request name="destroy" type="destructor">
@@ -58,7 +60,7 @@
Destroying a bound xdg_wm_base object while there are surfaces
still alive created by this xdg_wm_base object instance is illegal
- and will result in a protocol error.
+ and will result in a defunct_surfaces error.
</description>
</request>
@@ -75,7 +77,9 @@
<description summary="create a shell surface from a surface">
This creates an xdg_surface for the given surface. While xdg_surface
itself is not a role, the corresponding surface may only be assigned
- a role extending xdg_surface, such as xdg_toplevel or xdg_popup.
+ a role extending xdg_surface, such as xdg_toplevel or xdg_popup. It is
+ illegal to create an xdg_surface for a wl_surface which already has an
+ assigned role and this will result in a role error.
This creates an xdg_surface for the given surface. An xdg_surface is
used as basis to define a role to a given surface, such as xdg_toplevel
@@ -92,7 +96,8 @@
<request name="pong">
<description summary="respond to a ping event">
A client must respond to a ping event with a pong request or
- the client may be deemed unresponsive. See xdg_wm_base.ping.
+ the client may be deemed unresponsive. See xdg_wm_base.ping
+ and xdg_wm_base.error.unresponsive.
</description>
<arg name="serial" type="uint" summary="serial of the ping event"/>
</request>
@@ -106,7 +111,9 @@
Compositors can use this to determine if the client is still
alive. It's unspecified what will happen if the client doesn't
respond to the ping request, or in what timeframe. Clients should
- try to respond in a reasonable amount of time.
+ try to respond in a reasonable amount of time. The “unresponsive”
+ error is provided for compositors that wish to disconnect unresponsive
+ clients.
A compositor is free to ping in any way it wants, but a client must
always respond to any xdg_wm_base object it created.
@@ -115,7 +122,7 @@
</event>
</interface>
- <interface name="xdg_positioner" version="2">
+ <interface name="xdg_positioner" version="6">
<description summary="child surface positioner">
The xdg_positioner provides a collection of rules for the placement of a
child surface relative to a parent surface. Rules can be defined to ensure
@@ -135,7 +142,7 @@
For an xdg_positioner object to be considered complete, it must have a
non-zero size set by set_size, and a non-zero anchor rectangle set by
set_anchor_rect. Passing an incomplete xdg_positioner object when
- positioning a surface raises an error.
+ positioning a surface raises an invalid_positioner error.
</description>
<enum name="error">
@@ -223,7 +230,8 @@
specified (e.g. 'bottom_right' or 'top_left'), then the child surface
will be placed towards the specified gravity; otherwise, the child
surface will be centered over the anchor point on any axis that had no
- gravity specified.
+ gravity specified. If the gravity is not in the ‘gravity’ enum, an
+ invalid_input error is raised.
</description>
<arg name="gravity" type="uint" enum="gravity"
summary="gravity direction"/>
@@ -357,9 +365,49 @@
<arg name="x" type="int" summary="surface position x offset"/>
<arg name="y" type="int" summary="surface position y offset"/>
</request>
+
+ <!-- Version 3 additions -->
+
+ <request name="set_reactive" since="3">
+ <description summary="continuously reconstrain the surface">
+ When set reactive, the surface is reconstrained if the conditions used
+ for constraining changed, e.g. the parent window moved.
+
+ If the conditions changed and the popup was reconstrained, an
+ xdg_popup.configure event is sent with updated geometry, followed by an
+ xdg_surface.configure event.
+ </description>
+ </request>
+
+ <request name="set_parent_size" since="3">
+ <description summary="">
+ Set the parent window geometry the compositor should use when
+ positioning the popup. The compositor may use this information to
+ determine the future state the popup should be constrained using. If
+ this doesn't match the dimension of the parent the popup is eventually
+ positioned against, the behavior is undefined.
+
+ The arguments are given in the surface-local coordinate space.
+ </description>
+ <arg name="parent_width" type="int"
+ summary="future window geometry width of parent"/>
+ <arg name="parent_height" type="int"
+ summary="future window geometry height of parent"/>
+ </request>
+
+ <request name="set_parent_configure" since="3">
+ <description summary="set parent configure this is a response to">
+ Set the serial of an xdg_surface.configure event this positioner will be
+ used in response to. The compositor may use this information together
+ with set_parent_size to determine what future state the popup should be
+ constrained using.
+ </description>
+ <arg name="serial" type="uint"
+ summary="serial of parent configure event"/>
+ </request>
</interface>
- <interface name="xdg_surface" version="2">
+ <interface name="xdg_surface" version="6">
<description summary="desktop user interface surface base interface">
An interface that may be implemented by a wl_surface, for
implementations that provide a desktop-style user interface.
@@ -386,6 +434,13 @@
manipulate a buffer prior to the first xdg_surface.configure call must
also be treated as errors.
+ After creating a role-specific object and setting it up, the client must
+ perform an initial commit without any buffer attached. The compositor
+ will reply with initial wl_surface state such as
+ wl_surface.preferred_buffer_scale followed by an xdg_surface.configure
+ event. The client must acknowledge it and is then allowed to attach a
+ buffer to map the surface.
+
Mapping an xdg_surface-based role surface is defined as making it
possible for the surface to be shown by the compositor. Note that
a mapped surface is not guaranteed to be visible once it is mapped.
@@ -399,19 +454,30 @@
A newly-unmapped surface is considered to have met condition (1) out
of the 3 required conditions for mapping a surface if its role surface
- has not been destroyed.
+ has not been destroyed, i.e. the client must perform the initial commit
+ again before attaching a buffer.
</description>
<enum name="error">
- <entry name="not_constructed" value="1"/>
- <entry name="already_constructed" value="2"/>
- <entry name="unconfigured_buffer" value="3"/>
+ <entry name="not_constructed" value="1"
+ summary="Surface was not fully constructed"/>
+ <entry name="already_constructed" value="2"
+ summary="Surface was already constructed"/>
+ <entry name="unconfigured_buffer" value="3"
+ summary="Attaching a buffer to an unconfigured surface"/>
+ <entry name="invalid_serial" value="4"
+ summary="Invalid serial number when acking a configure event"/>
+ <entry name="invalid_size" value="5"
+ summary="Width or height was zero or negative"/>
+ <entry name="defunct_role_object" value="6"
+ summary="Surface was destroyed before its role object"/>
</enum>
<request name="destroy" type="destructor">
<description summary="destroy the xdg_surface">
Destroy the xdg_surface object. An xdg_surface must only be destroyed
- after its role object has been destroyed.
+ after its role object has been destroyed, otherwise
+ a defunct_role_object error is raised.
</description>
</request>
@@ -466,13 +532,22 @@
commit. This unset is meant for extremely simple clients.
The arguments are given in the surface-local coordinate space of
- the wl_surface associated with this xdg_surface.
+ the wl_surface associated with this xdg_surface, and may extend outside
+ of the wl_surface itself to mark parts of the subsurface tree as part of
+ the window geometry.
- The width and height must be greater than zero. Setting an invalid size
- will raise an error. When applied, the effective window geometry will be
- the set window geometry clamped to the bounding rectangle of the
- combined geometry of the surface of the xdg_surface and the associated
+ When applied, the effective window geometry will be the set window
+ geometry clamped to the bounding rectangle of the combined
+ geometry of the surface of the xdg_surface and the associated
subsurfaces.
+
+ The effective geometry will not be recalculated unless a new call to
+ set_window_geometry is done and the new pending surface state is
+ subsequently applied.
+
+ The width and height of the effective window geometry must be
+ greater than zero. Setting an invalid size will raise an
+ invalid_size error.
</description>
<arg name="x" type="int"/>
<arg name="y" type="int"/>
@@ -493,6 +568,8 @@
If the client receives multiple configure events before it
can respond to one, it only has to ack the last configure event.
+ Acking a configure event that was never sent raises an invalid_serial
+ error.
A client is not required to commit immediately after sending
an ack_configure request - it may even ack_configure several times
@@ -501,6 +578,17 @@
A client may send multiple ack_configure requests before committing, but
only the last request sent before a commit indicates which configure
event the client really is responding to.
+
+ Sending an ack_configure request consumes the serial number sent with
+ the request, as well as serial numbers sent by all configure events
+ sent on this xdg_surface prior to the configure event referenced by
+ the committed serial.
+
+ It is an error to issue multiple ack_configure requests referencing a
+ serial from the same configure event, or to issue an ack_configure
+ request referencing a serial from a configure event issued before the
+ event identified by the last ack_configure request for the same
+ xdg_surface. Doing so will raise an invalid_serial error.
</description>
<arg name="serial" type="uint" summary="the serial from the configure event"/>
</request>
@@ -526,9 +614,10 @@
</description>
<arg name="serial" type="uint" summary="serial of the configure event"/>
</event>
+
</interface>
- <interface name="xdg_toplevel" version="2">
+ <interface name="xdg_toplevel" version="6">
<description summary="toplevel surface">
This interface defines an xdg_surface role which allows a surface to,
among other things, set window-like properties such as maximize,
@@ -540,7 +629,11 @@
by the compositor until it is explicitly mapped again.
All active operations (e.g., move, resize) are canceled and all
attributes (e.g. title, state, stacking, ...) are discarded for
- an xdg_toplevel surface when it is unmapped.
+ an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to
+ the state it had right after xdg_surface.get_toplevel. The client
+ can re-map the toplevel by perfoming a commit without any buffer
+ attached, waiting for a configure event and handling it as usual (see
+ xdg_surface description).
Attaching a null buffer to a toplevel unmaps the surface.
</description>
@@ -552,24 +645,37 @@
</description>
</request>
+ <enum name="error">
+ <entry name="invalid_resize_edge" value="0" summary="provided value is
+ not a valid variant of the resize_edge enum"/>
+ <entry name="invalid_parent" value="1"
+ summary="invalid parent toplevel"/>
+ <entry name="invalid_size" value="2"
+ summary="client provided an invalid min or max size"/>
+ </enum>
+
<request name="set_parent">
<description summary="set the parent of this surface">
Set the "parent" of this surface. This surface should be stacked
above the parent surface and all other ancestor surfaces.
- Parent windows should be set on dialogs, toolboxes, or other
+ Parent surfaces should be set on dialogs, toolboxes, or other
"auxiliary" surfaces, so that the parent is raised when the dialog
is raised.
- Setting a null parent for a child window removes any parent-child
- relationship for the child. Setting a null parent for a window which
- currently has no parent is a no-op.
+ Setting a null parent for a child surface unsets its parent. Setting
+ a null parent for a surface which currently has no parent is a no-op.
- If the parent is unmapped then its children are managed as
- though the parent of the now-unmapped parent has become the
- parent of this surface. If no parent exists for the now-unmapped
- parent then the children are managed as though they have no
- parent surface.
+ Only mapped surfaces can have child surfaces. Setting a parent which
+ is not mapped is equivalent to setting a null parent. If a surface
+ becomes unmapped, its children's parent is set to the parent of
+ the now-unmapped surface. If the now-unmapped surface has no parent,
+ its children's parent is unset. If the now-unmapped surface becomes
+ mapped again, its parent-child relationship is not restored.
+
+ The parent toplevel must not be one of the child toplevel's
+ descendants, and the parent must be different from the child toplevel,
+ otherwise the invalid_parent protocol error is raised.
</description>
<arg name="parent" type="object" interface="xdg_toplevel" allow-null="true"/>
</request>
@@ -611,7 +717,7 @@
application identifiers and how they relate to well-known D-Bus
names and .desktop files.
- [0] http://standards.freedesktop.org/desktop-entry-spec/
+ [0] https://standards.freedesktop.org/desktop-entry-spec/
</description>
<arg name="app_id" type="string"/>
</request>
@@ -625,7 +731,8 @@
This request asks the compositor to pop up such a window menu at
the given position, relative to the local surface coordinates of
the parent surface. There are no guarantees as to what menu items
- the window menu contains.
+ the window menu contains, or even if a window menu will be drawn
+ at all.
This request must be used in response to some sort of user action
like a button press, key press, or touch down event.
@@ -701,16 +808,17 @@
guarantee that the device focus will return when the resize is
completed.
- The edges parameter specifies how the surface should be resized,
- and is one of the values of the resize_edge enum. The compositor
- may use this information to update the surface position for
- example when dragging the top left corner. The compositor may also
- use this information to adapt its behavior, e.g. choose an
- appropriate cursor image.
+ The edges parameter specifies how the surface should be resized, and
+ is one of the values of the resize_edge enum. Values not matching
+ a variant of the enum will cause the invalid_resize_edge protocol error.
+ The compositor may use this information to update the surface position
+ for example when dragging the top left corner. The compositor may also
+ use this information to adapt its behavior, e.g. choose an appropriate
+ cursor image.
</description>
<arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
<arg name="serial" type="uint" summary="the serial of the user event"/>
- <arg name="edges" type="uint" summary="which edge or corner is being dragged"/>
+ <arg name="edges" type="uint" enum="resize_edge" summary="which edge or corner is being dragged"/>
</request>
<enum name="state">
@@ -726,7 +834,8 @@
<entry name="maximized" value="1" summary="the surface is maximized">
<description summary="the surface is maximized">
The surface is maximized. The window geometry specified in the configure
- event must be obeyed by the client.
+ event must be obeyed by the client, or the xdg_wm_base.invalid_surface_state
+ error is raised.
The client should draw without shadow or other
decoration outside of the window geometry.
@@ -757,29 +866,36 @@
</description>
</entry>
<entry name="tiled_left" value="5" since="2">
- <description summary="the surface is tiled">
+ <description summary="the surface’s left edge is tiled">
The window is currently in a tiled layout and the left edge is
considered to be adjacent to another part of the tiling grid.
</description>
</entry>
<entry name="tiled_right" value="6" since="2">
- <description summary="the surface is tiled">
+ <description summary="the surface’s right edge is tiled">
The window is currently in a tiled layout and the right edge is
considered to be adjacent to another part of the tiling grid.
</description>
</entry>
<entry name="tiled_top" value="7" since="2">
- <description summary="the surface is tiled">
+ <description summary="the surface’s top edge is tiled">
The window is currently in a tiled layout and the top edge is
considered to be adjacent to another part of the tiling grid.
</description>
</entry>
<entry name="tiled_bottom" value="8" since="2">
- <description summary="the surface is tiled">
+ <description summary="the surface’s bottom edge is tiled">
The window is currently in a tiled layout and the bottom edge is
considered to be adjacent to another part of the tiling grid.
</description>
</entry>
+ <entry name="suspended" value="9" since="6">
+ <description summary="surface repaint is suspended">
+ The surface is currently not ordinarily being repainted; for
+ example because its content is occluded by another window, or its
+ outputs are switched off due to screen locking.
+ </description>
+ </entry>
</enum>
<request name="set_max_size">
@@ -813,11 +929,11 @@
request.
Requesting a maximum size to be smaller than the minimum size of
- a surface is illegal and will result in a protocol error.
+ a surface is illegal and will result in an invalid_size error.
The width and height must be greater than or equal to zero. Using
- strictly negative values for width and height will result in a
- protocol error.
+ strictly negative values for width or height will result in a
+ invalid_size error.
</description>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
@@ -854,11 +970,11 @@
request.
Requesting a minimum size to be larger than the maximum size of
- a surface is illegal and will result in a protocol error.
+ a surface is illegal and will result in an invalid_size error.
The width and height must be greater than or equal to zero. Using
strictly negative values for width and height will result in a
- protocol error.
+ invalid_size error.
</description>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
@@ -1017,9 +1133,68 @@
a dialog to ask the user to save their data, etc.
</description>
</event>
+
+ <!-- Version 4 additions -->
+
+ <event name="configure_bounds" since="4">
+ <description summary="recommended window geometry bounds">
+ The configure_bounds event may be sent prior to a xdg_toplevel.configure
+ event to communicate the bounds a window geometry size is recommended
+ to constrain to.
+
+ The passed width and height are in surface coordinate space. If width
+ and height are 0, it means bounds is unknown and equivalent to as if no
+ configure_bounds event was ever sent for this surface.
+
+ The bounds can for example correspond to the size of a monitor excluding
+ any panels or other shell components, so that a surface isn't created in
+ a way that it cannot fit.
+
+ The bounds may change at any point, and in such a case, a new
+ xdg_toplevel.configure_bounds will be sent, followed by
+ xdg_toplevel.configure and xdg_surface.configure.
+ </description>
+ <arg name="width" type="int"/>
+ <arg name="height" type="int"/>
+ </event>
+
+ <!-- Version 5 additions -->
+
+ <enum name="wm_capabilities" since="5">
+ <entry name="window_menu" value="1" summary="show_window_menu is available"/>
+ <entry name="maximize" value="2" summary="set_maximized and unset_maximized are available"/>
+ <entry name="fullscreen" value="3" summary="set_fullscreen and unset_fullscreen are available"/>
+ <entry name="minimize" value="4" summary="set_minimized is available"/>
+ </enum>
+
+ <event name="wm_capabilities" since="5">
+ <description summary="compositor capabilities">
+ This event advertises the capabilities supported by the compositor. If
+ a capability isn't supported, clients should hide or disable the UI
+ elements that expose this functionality. For instance, if the
+ compositor doesn't advertise support for minimized toplevels, a button
+ triggering the set_minimized request should not be displayed.
+
+ The compositor will ignore requests it doesn't support. For instance,
+ a compositor which doesn't advertise support for minimized will ignore
+ set_minimized requests.
+
+ Compositors must send this event once before the first
+ xdg_surface.configure event. When the capabilities change, compositors
+ must send this event again and then send an xdg_surface.configure
+ event.
+
+ The configured state should not be applied immediately. See
+ xdg_surface.configure for details.
+
+ The capabilities are sent as an array of 32-bit unsigned integers in
+ native endianness.
+ </description>
+ <arg name="capabilities" type="array" summary="array of 32-bit capabilities"/>
+ </event>
</interface>
- <interface name="xdg_popup" version="2">
+ <interface name="xdg_popup" version="6">
<description summary="short-lived, popup surfaces for menus">
A popup surface is a short-lived, temporary surface. It can be used to
implement for example menus, popovers, tooltips and other similar user
@@ -1043,12 +1218,6 @@
The parent of an xdg_popup must be mapped (see the xdg_surface
description) before the xdg_popup itself.
- The x and y arguments passed when creating the popup object specify
- where the top left of the popup should be placed, relative to the
- local surface coordinates of the parent surface. See
- xdg_surface.get_popup. An xdg_popup must intersect with or be at least
- partially adjacent to its parent surface.
-
The client must call wl_surface.commit on the corresponding wl_surface
for the xdg_popup state to take effect.
</description>
@@ -1063,8 +1232,8 @@
This destroys the popup. Explicitly destroying the xdg_popup
object will also dismiss the popup, and unmap the surface.
- If this xdg_popup is not the "topmost" popup, a protocol error
- will be sent.
+ If this xdg_popup is not the "topmost" popup, the
+ xdg_wm_base.not_the_topmost_popup protocol error will be sent.
</description>
</request>
@@ -1096,10 +1265,6 @@
nested grabbing popup as well. When a compositor dismisses popups, it
will follow the same dismissing order as required from the client.
- The parent of a grabbing popup must either be another xdg_popup with an
- active explicit grab, or an xdg_popup or xdg_toplevel, if there are no
- explicit grabs already taken.
-
If the topmost grabbing popup is destroyed, the grab will be returned to
the parent of the popup, if that parent previously had an explicit grab.
@@ -1126,6 +1291,11 @@
The x and y arguments represent the position the popup was placed at
given the xdg_positioner rule, relative to the upper left corner of the
window geometry of the parent surface.
+
+ For version 2 or older, the configure event for an xdg_popup is only
+ ever sent once for the initial configuration. Starting with version 3,
+ it may be sent again if the popup is setup with an xdg_positioner with
+ set_reactive requested, or in response to xdg_popup.reposition requests.
</description>
<arg name="x" type="int"
summary="x position relative to parent surface window geometry"/>
@@ -1143,5 +1313,58 @@
</description>
</event>
+ <!-- Version 3 additions -->
+
+ <request name="reposition" since="3">
+ <description summary="recalculate the popup's location">
+ Reposition an already-mapped popup. The popup will be placed given the
+ details in the passed xdg_positioner object, and a
+ xdg_popup.repositioned followed by xdg_popup.configure and
+ xdg_surface.configure will be emitted in response. Any parameters set
+ by the previous positioner will be discarded.
+
+ The passed token will be sent in the corresponding
+ xdg_popup.repositioned event. The new popup position will not take
+ effect until the corresponding configure event is acknowledged by the
+ client. See xdg_popup.repositioned for details. The token itself is
+ opaque, and has no other special meaning.
+
+ If multiple reposition requests are sent, the compositor may skip all
+ but the last one.
+
+ If the popup is repositioned in response to a configure event for its
+ parent, the client should send an xdg_positioner.set_parent_configure
+ and possibly an xdg_positioner.set_parent_size request to allow the
+ compositor to properly constrain the popup.
+
+ If the popup is repositioned together with a parent that is being
+ resized, but not in response to a configure event, the client should
+ send an xdg_positioner.set_parent_size request.
+ </description>
+ <arg name="positioner" type="object" interface="xdg_positioner"/>
+ <arg name="token" type="uint" summary="reposition request token"/>
+ </request>
+
+ <event name="repositioned" since="3">
+ <description summary="signal the completion of a repositioned request">
+ The repositioned event is sent as part of a popup configuration
+ sequence, together with xdg_popup.configure and lastly
+ xdg_surface.configure to notify the completion of a reposition request.
+
+ The repositioned event is to notify about the completion of a
+ xdg_popup.reposition request. The token argument is the token passed
+ in the xdg_popup.reposition request.
+
+ Immediately after this event is emitted, xdg_popup.configure and
+ xdg_surface.configure will be sent with the updated size and position,
+ as well as a new configure serial.
+
+ The client should optionally update the content of the popup, but must
+ acknowledge the new popup configuration for the new position to take
+ effect. See xdg_surface.ack_configure for details.
+ </description>
+ <arg name="token" type="uint" summary="reposition request token"/>
+ </event>
+
</interface>
</protocol>
diff --git a/src/3rdparty/protocol/xdg-toplevel-drag-v1.xml b/src/3rdparty/protocol/xdg-toplevel-drag-v1.xml
new file mode 100644
index 000000000..2fe964583
--- /dev/null
+++ b/src/3rdparty/protocol/xdg-toplevel-drag-v1.xml
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xdg_toplevel_drag_v1">
+
+ <copyright>
+ Copyright 2023 David Redondo
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+ </copyright>
+
+ <interface name="xdg_toplevel_drag_manager_v1" version="1">
+ <description summary="Move a window during a drag">
+ This protocol enhances normal drag and drop with the ability to move a
+ window at the same time. This allows having detachable parts of a window
+ that when dragged out of it become a new window and can be dragged over
+ an existing window to be reattached.
+
+ A typical workflow would be when the user starts dragging on top of a
+ detachable part of a window, the client would create a wl_data_source and
+ a xdg_toplevel_drag_v1 object and start the drag as normal via
+ wl_data_device.start_drag. Once the client determines that the detachable
+ window contents should be detached from the originating window, it creates
+ a new xdg_toplevel with these contents and issues a
+ xdg_toplevel_drag_v1.attach request before mapping it. From now on the new
+ window is moved by the compositor during the drag as if the client called
+ xdg_toplevel.move.
+
+ Dragging an existing window is similar. The client creates a
+ xdg_toplevel_drag_v1 object and attaches the existing toplevel before
+ starting the drag.
+
+ Clients use the existing drag and drop mechanism to detect when a window
+ can be docked or undocked. If the client wants to snap a window into a
+ parent window it should delete or unmap the dragged top-level. If the
+ contents should be detached again it attaches a new toplevel as described
+ above. If a drag operation is cancelled without being dropped, clients
+ should revert to the previous state, deleting any newly created windows
+ as appropriate. When a drag operation ends as indicated by
+ wl_data_source.dnd_drop_performed the dragged toplevel window's final
+ position is determined as if a xdg_toplevel_move operation ended.
+
+ Warning! The protocol described in this file is currently in the testing
+ phase. Backward compatible changes may be added together with the
+ corresponding interface version bump. Backward incompatible changes can
+ only be done by creating a new major version of the extension.
+ </description>
+
+ <enum name="error">
+ <entry name="invalid_source" value="0"
+ summary="data_source already used for toplevel drag"/>
+ </enum>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the xdg_toplevel_drag_manager_v1 object">
+ Destroy this xdg_toplevel_drag_manager_v1 object. Other objects,
+ including xdg_toplevel_drag_v1 objects created by this factory, are not
+ affected by this request.
+ </description>
+ </request>
+
+ <request name="get_xdg_toplevel_drag">
+ <description summary="get an xdg_toplevel_drag for a wl_data_source">
+ Create an xdg_toplevel_drag for a drag and drop operation that is going
+ to be started with data_source.
+
+ This request can only be made on sources used in drag-and-drop, so it
+ must be performed before wl_data_device.start_drag. Attempting to use
+ the source other than for drag-and-drop such as in
+ wl_data_device.set_selection will raise an invalid_source error.
+
+ Destroying data_source while a toplevel is attached to the
+ xdg_toplevel_drag is undefined.
+ </description>
+
+ <arg name="id" type="new_id" interface="xdg_toplevel_drag_v1"/>
+ <arg name="data_source" type="object" interface="wl_data_source"/>
+ </request>
+ </interface>
+
+ <interface name="xdg_toplevel_drag_v1" version="1">
+ <description summary="Object representing a toplevel move during a drag">
+ </description>
+
+ <enum name="error">
+ <entry name="toplevel_attached" value="0"
+ summary="valid toplevel already attached"/>
+ <entry name="ongoing_drag" value="1"
+ summary="drag has not ended" />
+ </enum>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy an xdg_toplevel_drag_v1 object">
+ Destroy this xdg_toplevel_drag_v1 object. This request must only be
+ called after the underlying wl_data_source drag has ended, as indicated
+ by the dnd_drop_performed or cancelled events. In any other case an
+ ongoing_drag error is raised.
+ </description>
+ </request>
+
+ <request name="attach">
+ <description summary="Move a toplevel with the drag operation">
+ Request that the window will be moved with the cursor during the drag
+ operation. The offset is a hint to the compositor how the toplevel
+ should be positioned relative to the cursor hotspot in surface local
+ coordinates. For example it might only be used when an unmapped window
+ is attached. The attached window does not participate in the selection
+ of the drag target.
+
+ If the toplevel is unmapped while it is attached, it is automatically
+ detached from the drag. In this case this request has to be called again
+ if the window should be attached after it is remapped.
+
+ This request can be called multiple times but issuing it while a
+ toplevel with an active role is attached raises a toplevel_attached
+ error.
+ </description>
+
+ <arg name="toplevel" type="object" interface="xdg_toplevel"/>
+ <arg name="x_offset" type="int" summary="dragged surface x offset"/>
+ <arg name="y_offset" type="int" summary="dragged surface y offset"/>
+ </request>
+
+ </interface>
+</protocol>
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6787e9cbc..a38d95512 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,7 +1,24 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from src.pro.
# special case begin
qt_find_package(WaylandScanner PROVIDED_TARGETS Wayland::Scanner)
-qt_find_package(Wayland 1.15 PROVIDED_TARGETS Wayland::Client Wayland::Server)
+
+set(wayland_libs
+ Wayland::Client
+ Wayland::Server
+ Wayland::Cursor
+ Wayland::Egl
+)
+
+foreach(lib IN LISTS wayland_libs)
+ if(TARGET ${lib})
+ qt_internal_disable_find_package_global_promotion(${lib})
+ endif()
+endforeach()
+
+qt_find_package(Wayland 1.15 PROVIDED_TARGETS ${wayland_libs})
if (NOT WaylandScanner_FOUND OR NOT Wayland_FOUND)
message(WARNING "QtWayland is missing required dependencies, nothing will be built. \
@@ -12,7 +29,20 @@ configure the module on targets that are missing dependencies.")
endif()
# See global/README for a description of the following module.
-qt_internal_add_module(WaylandGlobalPrivate INTERNAL_MODULE HEADER_MODULE)
+qt_internal_add_module(WaylandGlobalPrivate
+ INTERNAL_MODULE
+ HEADER_MODULE
+ NO_GENERATE_CPP_EXPORTS
+)
+
+# Work around 115101.
+# If nothing depends on the WaylandGlobalPrivate target it doesn't run custom commands that the
+# target depends on. WaylandGlobalPrivate_ensure_sync_headers makes sure that 'all' depends on
+# WaylandGlobalPrivate_sync_headers.
+# TODO: This needs to be removed once the fix for QTBUG-115101 is merged in qtbase.
+add_custom_target(WaylandGlobalPrivate_ensure_sync_headers ALL)
+add_dependencies(WaylandGlobalPrivate_ensure_sync_headers WaylandGlobalPrivate_sync_headers)
+
add_subdirectory(qtwaylandscanner)
# special case begin
diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt
index be6065c14..4916af81e 100644
--- a/src/client/CMakeLists.txt
+++ b/src/client/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from client.pro.
#####################################################################
@@ -29,9 +32,11 @@ qt_internal_add_module(WaylandClient
qwaylanddecorationplugin.cpp qwaylanddecorationplugin_p.h
qwaylanddisplay.cpp qwaylanddisplay_p.h
qwaylandextendedsurface.cpp qwaylandextendedsurface_p.h
+ qwaylandfractionalscale.cpp qwaylandfractionalscale_p.h
qwaylandinputcontext.cpp qwaylandinputcontext_p.h
qwaylandtextinputv1.cpp qwaylandtextinputv1_p.h
qwaylandtextinputv2.cpp qwaylandtextinputv2_p.h
+ qwaylandtextinputv3.cpp qwaylandtextinputv3_p.h
qwaylandtextinputinterface.cpp qwaylandtextinputinterface_p.h
qwaylandinputdevice.cpp qwaylandinputdevice_p.h
qwaylandinputmethodcontext.cpp qwaylandinputmethodcontext_p.h
@@ -47,6 +52,7 @@ qt_internal_add_module(WaylandClient
qwaylandsubsurface.cpp qwaylandsubsurface_p.h
qwaylandsurface.cpp qwaylandsurface_p.h
qwaylandtouch.cpp qwaylandtouch_p.h
+ qwaylandviewport.cpp qwaylandviewport_p.h
qwaylandwindow.cpp qwaylandwindow_p.h
qwaylandwindowmanagerintegration.cpp qwaylandwindowmanagerintegration_p.h
shellintegration/qwaylandclientshellapi_p.h
@@ -71,18 +77,25 @@ qt_internal_add_module(WaylandClient
Qt::CorePrivate
Qt::GuiPrivate
Qt::WaylandGlobalPrivate
+ PRIVATE_HEADER_FILTERS
+ "^qwayland-.*\.h|^wayland-.*-protocol\.h"
)
qt6_generate_wayland_protocol_client_sources(WaylandClient
FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/cursor-shape-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/pointer-gestures-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/tablet-unstable-v2.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/text-input-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/text-input-unstable-v2.xml
- ${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/text-input-unstable-v4-wip.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/text-input-unstable-v3.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/wayland.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/wp-primary-selection-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/xdg-output-unstable-v1.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/fractional-scale-v1.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/viewporter.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/xdg-shell.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/xdg-toplevel-drag-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-key-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-text-input-method-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-windowmanager.xml
@@ -114,13 +127,6 @@ qt_internal_extend_target(WaylandClient CONDITION QT_FEATURE_tabletevent
qwaylandtabletv2.cpp qwaylandtabletv2_p.h
)
-qt_internal_extend_target(WaylandClient CONDITION QT_FEATURE_wayland_text_input_v4_wip
- SOURCES
- qwaylandtextinputv4.cpp qwaylandtextinputv4_p.h
- DEFINES
- QT_WAYLAND_TEXT_INPUT_V4_WIP=1
-)
-
qt_internal_extend_target(WaylandClient CONDITION QT_FEATURE_clipboard
SOURCES
qwaylandclipboard.cpp qwaylandclipboard_p.h
@@ -157,5 +163,9 @@ qt_internal_extend_target(WaylandClient CONDITION QT_FEATURE_draganddrop
qwaylanddnd.cpp qwaylanddnd_p.h
)
+qt_internal_add_docs(WaylandClient
+ doc/qtwaylandclient.qdocconf
+)
+
qt_record_extra_qt_main_tools_package_dependency(WaylandClient WaylandScannerTools "${PROJECT_VERSION}")
qt_record_extra_qt_package_dependency(WaylandClient WaylandGlobalPrivate "${PROJECT_VERSION}")
diff --git a/src/client/Qt6WaylandClientMacros.cmake b/src/client/Qt6WaylandClientMacros.cmake
index 1f2dd272d..b4266c558 100644
--- a/src/client/Qt6WaylandClientMacros.cmake
+++ b/src/client/Qt6WaylandClientMacros.cmake
@@ -1,5 +1,14 @@
+
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
function(qt6_generate_wayland_protocol_client_sources target)
- cmake_parse_arguments(arg "" "__QT_INTERNAL_WAYLAND_INCLUDE_DIR" "FILES" ${ARGN})
+ cmake_parse_arguments(arg
+ "NO_INCLUDE_CORE_ONLY;PRIVATE_CODE;PUBLIC_CODE"
+ "__QT_INTERNAL_WAYLAND_INCLUDE_DIR"
+ "FILES"
+ ${ARGN})
+
if(DEFINED arg_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unknown arguments were passed to qt6_generate_wayland_protocol_client_sources: (${arg_UNPARSED_ARGUMENTS}).")
endif()
@@ -28,15 +37,28 @@ function(qt6_generate_wayland_protocol_client_sources target)
set(qtwaylandscanner_header_output "${target_binary_dir}/qwayland-${protocol_name}.h")
set(qtwaylandscanner_code_output "${target_binary_dir}/qwayland-${protocol_name}.cpp")
+ if (NOT arg_NO_INCLUDE_CORE_ONLY)
+ set(waylandscanner_extra_args "--include-core-only")
+ endif()
+
+
+ if (arg_PRIVATE_CODE)
+ set(wayland_scanner_code_option "private-code")
+ else()
+ set(wayland_scanner_code_option "public-code")
+ endif()
+
add_custom_command(
OUTPUT "${waylandscanner_header_output}"
#TODO: Maybe put the files in ${CMAKE_CURRENT_BINARY_DIR/wayland_generated instead?
- COMMAND Wayland::Scanner --strict --include-core-only client-header < "${protocol_file}" > "${waylandscanner_header_output}"
+ COMMAND Wayland::Scanner ${waylandscanner_extra_args} client-header < "${protocol_file}" > "${waylandscanner_header_output}"
+ DEPENDS ${protocol_file} Wayland::Scanner
)
add_custom_command(
OUTPUT "${waylandscanner_code_output}"
- COMMAND Wayland::Scanner --strict --include-core-only public-code < "${protocol_file}" > "${waylandscanner_code_output}"
+ COMMAND Wayland::Scanner ${waylandscanner_extra_args} ${wayland_scanner_code_option} < "${protocol_file}" > "${waylandscanner_code_output}"
+ DEPENDS ${protocol_file} Wayland::Scanner
)
set(wayland_include_dir "")
@@ -78,12 +100,14 @@ function(qt6_generate_wayland_protocol_client_sources target)
DEPENDS ${protocol_file} Qt6::qtwaylandscanner
)
- target_sources(${target} PRIVATE
- "${waylandscanner_header_output}"
+ set(sources "${waylandscanner_header_output}"
"${waylandscanner_code_output}"
"${qtwaylandscanner_header_output}"
- "${qtwaylandscanner_code_output}"
- )
+ "${qtwaylandscanner_code_output}")
+
+ target_sources(${target} PRIVATE ${sources})
+
+ set_source_files_properties(${sources} PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
endforeach()
target_include_directories(${target} PRIVATE ${target_binary_dir})
endfunction()
diff --git a/src/client/configure.cmake b/src/client/configure.cmake
index a8184fc1c..5ed7995ef 100644
--- a/src/client/configure.cmake
+++ b/src/client/configure.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#### Inputs
diff --git a/src/client/doc/qtwaylandclient.qdocconf b/src/client/doc/qtwaylandclient.qdocconf
new file mode 100644
index 000000000..20ceaef02
--- /dev/null
+++ b/src/client/doc/qtwaylandclient.qdocconf
@@ -0,0 +1,31 @@
+include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
+include($QT_INSTALL_DOCS/config/exampleurl-qtwayland.qdocconf)
+
+project = QtWaylandClient
+description = Qt Wayland Client Reference Documentation
+version = $QT_VERSION
+
+qhp.projects = QtWaylandClient
+
+qhp.QtWaylandClient.file = qtwaylandclient.qhp
+qhp.QtWaylandClient.namespace = org.qt-project.QtWaylandClient.$QT_VERSION_TAG
+qhp.QtWaylandClient.virtualFolder = QtWaylandClient
+qhp.QtWaylandClient.indexTitle = Qt Wayland Client
+qhp.QtWaylandClient.indexRoot =
+
+depends += qtcore \
+ qtqml \
+ qtquick \
+ qtdoc \
+ qtcmake \
+ qtwaylandcompositor
+
+headerdirs += \
+ ../
+sourcedirs += \
+ ../
+
+navigation.landingpage = "Qt Wayland Client"
+
+# Enforce zero documentation warnings
+warninglimit = 0
diff --git a/src/client/doc/src/cmake/qt_generate_wayland_protocol_client_sources.qdoc b/src/client/doc/src/cmake/qt_generate_wayland_protocol_client_sources.qdoc
new file mode 100644
index 000000000..43f448fbd
--- /dev/null
+++ b/src/client/doc/src/cmake/qt_generate_wayland_protocol_client_sources.qdoc
@@ -0,0 +1,50 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt-generate-wayland-protocol-client-sources.html
+\ingroup cmake-commands-qtwaylandclient
+
+\title qt_generate_wayland_protocol_client_sources
+\keyword qt6_generate_wayland_protocol_client_sources
+
+\summary {Generates client-side C++ bindings for a Wayland protocol .XML file}
+
+\cmakecommandsince 6.0
+
+The command is defined in the \c WaylandClient component of the \c Qt6 package, which
+can be loaded like so:
+
+\badcode
+find_package(Qt6 REQUIRED COMPONENTS WaylandClient)
+\endcode
+
+\section1 Synopsis
+
+\badcode
+qt_generate_wayland_protocol_client_sources(target
+ [PUBLIC_CODE | PRIVATE_CODE]
+ FILES file1.xml [file2.xml ...])
+\endcode
+
+\versionlessCMakeCommandsNote qt6_generate_wayland_protocol_client_sources()
+
+\section1 Description
+
+qt_generate_wayland_protocol_client_sources() creates the build steps to run \c{wayland-scanner} and
+\c{qtwaylandscanner} on one or more Wayland protocol files. The tools will in turn generate binding
+code in C and C++ for implementing the protocols, and the resulting files will be built as part
+of the \c target.
+
+The options \c{PUBLIC_CODE} and \c{PRIVATE_CODE} correspond to the \c{public-code} and
+\c{private-code} options of \c{wayland-scanner}. For backwards compatibility \c{PUBLIC_CODE} is the
+default but generally \c{PRIVATE_CODE} is strongly recommended.
+
+qt_generate_wayland_protocol_client_sources() will trigger generation of the files needed to
+implement the client side of the protocol. \l{qt_generate_wayland_protocol_server_sources}{qt_generate_wayland_protocol_server_sources()}
+is the equivalent function for the compositor.
+
+See the \l{Custom Shell} or \l{Custom Extension} examples for a demonstration of how to use these
+functions.
+*/
+
diff --git a/src/client/doc/src/qtwaylandclient-overview.qdoc b/src/client/doc/src/qtwaylandclient-overview.qdoc
new file mode 100644
index 000000000..a6f5ce56a
--- /dev/null
+++ b/src/client/doc/src/qtwaylandclient-overview.qdoc
@@ -0,0 +1,36 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page qtwaylandclient-index.html
+ \title Qt Wayland Client
+ \brief Library to enable connecting to a Wayland compositor as a client
+
+ The Qt Wayland Client library provides the necessary functions for an application to act
+ as a \l {https://wayland.freedesktop.org/}{Wayland} client and connect to a Wayland compositor.
+ For most use cases, the library is used automatically through the Wayland QPA plugin, and there is
+ no need for the application itself to use any functions from the library.
+
+ However, when paired with \l{Qt Wayland Compositor}, the cmake function
+ \l{qt_generate_wayland_protocol_client_sources}{qt_generate_wayland_protocol_client_sources()}
+ can be used to create custom protocol extensions.
+
+ \section1 Licenses and Attributions
+
+ Qt Wayland Compositor and the Qt Wayland integration plugin
+ are available under commercial licenses from \l{The Qt Company}.
+
+ In addition, Qt Wayland Compositor is available under the
+ \l{GNU General Public License, version 3}, while
+ the Qt Wayland integration plugin is available under the
+ \l{GNU Lesser General Public License, version 3} or the
+ \l{GNU General Public License, version 2}.
+
+ See \l{Qt Licensing} for further details.
+
+ Qt Wayland Compositor and the Qt Wayland integration plugin
+ use protocol definitions under following permissive licenses:
+
+ \generatelist{groupsbymodule attributions-qtwaylandcompositor}
+
+*/
diff --git a/src/client/global/qwaylandclientextension.cpp b/src/client/global/qwaylandclientextension.cpp
index ca0954f78..b2783088b 100644
--- a/src/client/global/qwaylandclientextension.cpp
+++ b/src/client/global/qwaylandclientextension.cpp
@@ -6,10 +6,6 @@
#include "qwaylandclientextension_p.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtWaylandClient/private/qwaylandintegration_p.h>
-#include <QtGui/QGuiApplication>
-#include <QtGui/qpa/qplatformnativeinterface.h>
-#include <QtGui/private/qguiapplication_p.h>
-#include <QtCore/QDebug>
QT_BEGIN_NAMESPACE
@@ -19,12 +15,9 @@ QWaylandClientExtensionPrivate::QWaylandClientExtensionPrivate()
{
// Keep the possibility to use a custom waylandIntegration as a plugin,
// but also add the possibility to run it as a QML component.
- waylandIntegration = static_cast<QtWaylandClient::QWaylandIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ waylandIntegration = QtWaylandClient::QWaylandIntegration::instance();
if (!waylandIntegration)
waylandIntegration = new QtWaylandClient::QWaylandIntegration();
-
- if (!waylandIntegration->nativeInterface()->nativeResourceForIntegration("wl_display"))
- qWarning() << "This application requires a Wayland platform plugin";
}
void QWaylandClientExtensionPrivate::globalAdded(const RegistryGlobal &global)
diff --git a/src/client/global/qwaylandclientextension.h b/src/client/global/qwaylandclientextension.h
index b7c4a3239..c57549c34 100644
--- a/src/client/global/qwaylandclientextension.h
+++ b/src/client/global/qwaylandclientextension.h
@@ -4,7 +4,7 @@
#ifndef QWAYLANDCLIENTEXTENSION_H
#define QWAYLANDCLIENTEXTENSION_H
-#include <QObject>
+#include <QtCore/QObject>
#include <QtWaylandClient/qtwaylandclientglobal.h>
struct wl_interface;
@@ -45,14 +45,31 @@ protected Q_SLOTS:
void initialize();
};
-template <typename T>
+
+template<typename T, auto destruct = nullptr>
class Q_WAYLANDCLIENT_EXPORT QWaylandClientExtensionTemplate : public QWaylandClientExtension
{
Q_DECLARE_PRIVATE(QWaylandClientExtensionTemplate)
+
public:
- QWaylandClientExtensionTemplate(const int ver) :
- QWaylandClientExtension(ver)
+ QWaylandClientExtensionTemplate(const int ver) : QWaylandClientExtension(ver)
{
+ if constexpr (destruct != nullptr) {
+ connect(this, &QWaylandClientExtensionTemplate::activeChanged, this, [this] {
+ if (!isActive()) {
+ std::invoke(destruct, static_cast<T *>(this));
+ }
+ });
+ }
+ }
+
+ ~QWaylandClientExtensionTemplate()
+ {
+ if constexpr (destruct != nullptr) {
+ if (isActive()) {
+ std::invoke(destruct, static_cast<T *>(this));
+ }
+ }
}
const struct wl_interface *extensionInterface() const override
diff --git a/src/client/hardwareintegration/qwaylandclientbufferintegrationfactory.cpp b/src/client/hardwareintegration/qwaylandclientbufferintegrationfactory.cpp
index 48310589e..65c7a450d 100644
--- a/src/client/hardwareintegration/qwaylandclientbufferintegrationfactory.cpp
+++ b/src/client/hardwareintegration/qwaylandclientbufferintegrationfactory.cpp
@@ -12,17 +12,17 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
-Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, qwcbifLoader,
(QWaylandClientBufferIntegrationFactoryInterface_iid, QLatin1String("/wayland-graphics-integration-client"), Qt::CaseInsensitive))
QStringList QWaylandClientBufferIntegrationFactory::keys()
{
- return loader->keyMap().values();
+ return qwcbifLoader->keyMap().values();
}
QWaylandClientBufferIntegration *QWaylandClientBufferIntegrationFactory::create(const QString &name, const QStringList &args)
{
- return qLoadPlugin<QWaylandClientBufferIntegration, QWaylandClientBufferIntegrationPlugin>(loader(), name, args);
+ return qLoadPlugin<QWaylandClientBufferIntegration, QWaylandClientBufferIntegrationPlugin>(qwcbifLoader(), name, args);
}
}
diff --git a/src/client/hardwareintegration/qwaylandserverbufferintegrationfactory.cpp b/src/client/hardwareintegration/qwaylandserverbufferintegrationfactory.cpp
index a8b0c1d87..e30bb4dc0 100644
--- a/src/client/hardwareintegration/qwaylandserverbufferintegrationfactory.cpp
+++ b/src/client/hardwareintegration/qwaylandserverbufferintegrationfactory.cpp
@@ -12,17 +12,17 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
-Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, qwsbifLoader,
(QWaylandServerBufferIntegrationFactoryInterface_iid, QLatin1String("/wayland-graphics-integration-client"), Qt::CaseInsensitive))
QStringList QWaylandServerBufferIntegrationFactory::keys()
{
- return loader->keyMap().values();
+ return qwsbifLoader->keyMap().values();
}
QWaylandServerBufferIntegration *QWaylandServerBufferIntegrationFactory::create(const QString &name, const QStringList &args)
{
- return qLoadPlugin<QWaylandServerBufferIntegration, QWaylandServerBufferIntegrationPlugin>(loader(), name, args);
+ return qLoadPlugin<QWaylandServerBufferIntegration, QWaylandServerBufferIntegrationPlugin>(qwsbifLoader(), name, args);
}
}
diff --git a/src/client/inputdeviceintegration/qwaylandinputdeviceintegrationfactory.cpp b/src/client/inputdeviceintegration/qwaylandinputdeviceintegrationfactory.cpp
index d53a91f05..1c8eb213d 100644
--- a/src/client/inputdeviceintegration/qwaylandinputdeviceintegrationfactory.cpp
+++ b/src/client/inputdeviceintegration/qwaylandinputdeviceintegrationfactory.cpp
@@ -12,17 +12,17 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
-Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, qwidfiLoader,
(QWaylandInputDeviceIntegrationFactoryInterface_iid, QLatin1String("/wayland-inputdevice-integration"), Qt::CaseInsensitive))
QStringList QWaylandInputDeviceIntegrationFactory::keys()
{
- return loader->keyMap().values();
+ return qwidfiLoader->keyMap().values();
}
QWaylandInputDeviceIntegration *QWaylandInputDeviceIntegrationFactory::create(const QString &name, const QStringList &args)
{
- return qLoadPlugin<QWaylandInputDeviceIntegration, QWaylandInputDeviceIntegrationPlugin>(loader(), name, args);
+ return qLoadPlugin<QWaylandInputDeviceIntegration, QWaylandInputDeviceIntegrationPlugin>(qwidfiLoader(), name, args);
}
}
diff --git a/src/client/qwaylandbuffer_p.h b/src/client/qwaylandbuffer_p.h
index 381debc81..3798ef3eb 100644
--- a/src/client/qwaylandbuffer_p.h
+++ b/src/client/qwaylandbuffer_p.h
@@ -37,7 +37,7 @@ public:
virtual QSize size() const = 0;
virtual int scale() const { return 1; }
- void setBusy() { mBusy = true; }
+ void setBusy(bool busy) { mBusy = busy; }
bool busy() const { return mBusy; }
void setCommitted() { mCommitted = true; }
diff --git a/src/client/qwaylandclipboard.cpp b/src/client/qwaylandclipboard.cpp
index d3566244b..df6cf5d2b 100644
--- a/src/client/qwaylandclipboard.cpp
+++ b/src/client/qwaylandclipboard.cpp
@@ -18,10 +18,15 @@ namespace QtWaylandClient {
QWaylandClipboard::QWaylandClipboard(QWaylandDisplay *display)
: mDisplay(display)
{
+ m_clientClipboard[QClipboard::Clipboard] = nullptr;
+ m_clientClipboard[QClipboard::Selection] = nullptr;
}
QWaylandClipboard::~QWaylandClipboard()
{
+ if (m_clientClipboard[QClipboard::Clipboard] != m_clientClipboard[QClipboard::Selection])
+ delete m_clientClipboard[QClipboard::Clipboard];
+ delete m_clientClipboard[QClipboard::Selection];
}
QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
@@ -33,8 +38,8 @@ QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
switch (mode) {
case QClipboard::Clipboard:
if (auto *dataDevice = seat->dataDevice()) {
- if (auto *source = dataDevice->selectionSource())
- return source->mimeData();
+ if (dataDevice->selectionSource())
+ return m_clientClipboard[QClipboard::Clipboard];
if (auto *offer = dataDevice->selectionOffer())
return offer->mimeData();
}
@@ -42,8 +47,8 @@ QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
case QClipboard::Selection:
#if QT_CONFIG(wayland_client_primary_selection)
if (auto *selectionDevice = seat->primarySelectionDevice()) {
- if (auto *source = selectionDevice->selectionSource())
- return source->mimeData();
+ if (selectionDevice->selectionSource())
+ return m_clientClipboard[QClipboard::Selection];
if (auto *offer = selectionDevice->selectionOffer())
return offer->mimeData();
}
@@ -68,17 +73,27 @@ void QWaylandClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
if (data && data->hasFormat(plain) && !data->hasFormat(utf8))
data->setData(utf8, data->data(plain));
+ if (m_clientClipboard[mode]) {
+ if (m_clientClipboard[QClipboard::Clipboard] != m_clientClipboard[QClipboard::Selection])
+ delete m_clientClipboard[mode];
+ m_clientClipboard[mode] = nullptr;
+ }
+
+ m_clientClipboard[mode] = data;
+
switch (mode) {
case QClipboard::Clipboard:
if (auto *dataDevice = seat->dataDevice()) {
- dataDevice->setSelectionSource(data ? new QWaylandDataSource(mDisplay->dndSelectionHandler(), data) : nullptr);
+ dataDevice->setSelectionSource(data ? new QWaylandDataSource(mDisplay->dndSelectionHandler(),
+ m_clientClipboard[QClipboard::Clipboard]) : nullptr);
emitChanged(mode);
}
break;
case QClipboard::Selection:
#if QT_CONFIG(wayland_client_primary_selection)
if (auto *selectionDevice = seat->primarySelectionDevice()) {
- selectionDevice->setSelectionSource(data ? new QWaylandPrimarySelectionSourceV1(mDisplay->primarySelectionManager(), data) : nullptr);
+ selectionDevice->setSelectionSource(data ? new QWaylandPrimarySelectionSourceV1(mDisplay->primarySelectionManager(),
+ m_clientClipboard[QClipboard::Selection]) : nullptr);
emitChanged(mode);
}
#endif
diff --git a/src/client/qwaylandclipboard_p.h b/src/client/qwaylandclipboard_p.h
index 655620bda..414e3dc71 100644
--- a/src/client/qwaylandclipboard_p.h
+++ b/src/client/qwaylandclipboard_p.h
@@ -45,6 +45,7 @@ public:
private:
QWaylandDisplay *mDisplay = nullptr;
QMimeData m_emptyData;
+ QMimeData *m_clientClipboard[2];
};
}
diff --git a/src/client/qwaylandcursor.cpp b/src/client/qwaylandcursor.cpp
index 67a846df6..98d51a842 100644
--- a/src/client/qwaylandcursor.cpp
+++ b/src/client/qwaylandcursor.cpp
@@ -1,4 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2023 David Edmundson <davidedmundson@kde.org>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwaylandcursor_p.h"
@@ -7,6 +8,9 @@
#include "qwaylandinputdevice_p.h"
#include "qwaylandshmbackingstore_p.h"
+#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatformtheme.h>
+
#include <QtGui/QImageReader>
#include <QDebug>
@@ -206,6 +210,77 @@ wl_cursor *QWaylandCursorTheme::requestCursor(WaylandCursor shape)
return waylandCursor;
}
+QWaylandCursorShape::QWaylandCursorShape(::wp_cursor_shape_device_v1 *object)
+ : QtWayland::wp_cursor_shape_device_v1(object)
+{}
+
+QWaylandCursorShape::~QWaylandCursorShape()
+{
+ destroy();
+}
+
+static QtWayland::wp_cursor_shape_device_v1::shape qtCursorShapeToWaylandShape(Qt::CursorShape cursorShape)
+{
+ using QtWayland::wp_cursor_shape_device_v1;
+
+ switch (cursorShape) {
+ case Qt::BlankCursor:
+ case Qt::CustomCursor:
+ case Qt::BitmapCursor:
+ // these should have been handled separately before using the shape protocol
+ Q_ASSERT(false);
+ break;
+ case Qt::ArrowCursor:
+ return wp_cursor_shape_device_v1::shape_default;
+ case Qt::SizeVerCursor:
+ return wp_cursor_shape_device_v1::shape_ns_resize;
+ case Qt::UpArrowCursor:
+ return wp_cursor_shape_device_v1::shape_n_resize;
+ case Qt::SizeHorCursor:
+ return wp_cursor_shape_device_v1::shape_ew_resize;
+ case Qt::CrossCursor:
+ return wp_cursor_shape_device_v1::shape_crosshair;
+ case Qt::SizeBDiagCursor:
+ return wp_cursor_shape_device_v1::shape_nesw_resize;
+ case Qt::IBeamCursor:
+ return wp_cursor_shape_device_v1::shape_text;
+ case Qt::SizeFDiagCursor:
+ return wp_cursor_shape_device_v1::shape_nwse_resize;
+ case Qt::WaitCursor:
+ return wp_cursor_shape_device_v1::shape_wait;
+ case Qt::SizeAllCursor:
+ return wp_cursor_shape_device_v1::shape_all_scroll;
+ case Qt::BusyCursor:
+ return wp_cursor_shape_device_v1::shape_progress;
+ case Qt::SplitVCursor:
+ return wp_cursor_shape_device_v1::shape_row_resize;
+ case Qt::ForbiddenCursor:
+ return wp_cursor_shape_device_v1::shape_not_allowed;
+ case Qt::SplitHCursor:
+ return wp_cursor_shape_device_v1::shape_col_resize;
+ case Qt::PointingHandCursor:
+ return wp_cursor_shape_device_v1::shape_pointer;
+ case Qt::OpenHandCursor:
+ return wp_cursor_shape_device_v1::shape_grab;
+ case Qt::WhatsThisCursor:
+ return wp_cursor_shape_device_v1::shape_help;
+ case Qt::ClosedHandCursor:
+ return wp_cursor_shape_device_v1::shape_grabbing;
+ case Qt::DragMoveCursor:
+ return wp_cursor_shape_device_v1::shape_move;
+ case Qt::DragCopyCursor:
+ return wp_cursor_shape_device_v1::shape_copy;
+ case Qt::DragLinkCursor:
+ return wp_cursor_shape_device_v1::shape_alias;
+ }
+ return wp_cursor_shape_device_v1::shape_default;
+}
+
+void QWaylandCursorShape::setShape(uint32_t serial, Qt::CursorShape shape)
+{
+ set_shape(serial, qtCursorShapeToWaylandShape(shape));
+}
+
QWaylandCursor::QWaylandCursor(QWaylandDisplay *display)
: mDisplay(display)
{
@@ -214,7 +289,21 @@ QWaylandCursor::QWaylandCursor(QWaylandDisplay *display)
QSharedPointer<QWaylandBuffer> QWaylandCursor::cursorBitmapBuffer(QWaylandDisplay *display, const QCursor *cursor)
{
Q_ASSERT(cursor->shape() == Qt::BitmapCursor);
- const QImage &img = cursor->pixmap().toImage();
+ QImage img = !cursor->pixmap().isNull() ? cursor->pixmap().toImage() : cursor->bitmap().toImage();
+
+ // convert to supported format if necessary
+ if (!display->shm()->formatSupported(img.format())) {
+ if (cursor->mask().isNull()) {
+ img.convertTo(QImage::Format_RGB32);
+ } else {
+ // preserve mask
+ img.convertTo(QImage::Format_ARGB32);
+ QPixmap pixmap = QPixmap::fromImage(img);
+ pixmap.setMask(cursor->mask());
+ img = pixmap.toImage();
+ }
+ }
+
QSharedPointer<QWaylandShmBuffer> buffer(new QWaylandShmBuffer(display, img.size(), img.format()));
memcpy(buffer->image()->bits(), img.bits(), size_t(img.sizeInBytes()));
return buffer;
@@ -250,6 +339,13 @@ void QWaylandCursor::setPos(const QPoint &pos)
qCWarning(lcQpaWayland) << "Setting cursor position is not possible on wayland";
}
+QSize QWaylandCursor::size() const
+{
+ if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
+ return theme->themeHint(QPlatformTheme::MouseCursorSize).toSize();
+ return QSize(24, 24);
+}
+
} // namespace QtWaylandClient
QT_END_NAMESPACE
diff --git a/src/client/qwaylandcursor_p.h b/src/client/qwaylandcursor_p.h
index 2334c88d9..1f6d5109e 100644
--- a/src/client/qwaylandcursor_p.h
+++ b/src/client/qwaylandcursor_p.h
@@ -18,6 +18,7 @@
#include <qpa/qplatformcursor.h>
#include <QtCore/QMap>
#include <QtWaylandClient/qtwaylandclientglobal.h>
+#include <QtWaylandClient/private/qwayland-cursor-shape-v1.h>
#include <QtCore/private/qglobal_p.h>
#if QT_CONFIG(cursor)
@@ -87,6 +88,14 @@ protected:
wl_cursor *m_cursors[NumWaylandCursors] = {};
};
+class Q_WAYLANDCLIENT_EXPORT QWaylandCursorShape : public QtWayland::wp_cursor_shape_device_v1
+{
+public:
+ QWaylandCursorShape(struct ::wp_cursor_shape_device_v1 *object);
+ ~QWaylandCursorShape();
+ void setShape(uint32_t serial, Qt::CursorShape shape);
+};
+
class Q_WAYLANDCLIENT_EXPORT QWaylandCursor : public QPlatformCursor
{
public:
@@ -97,6 +106,8 @@ public:
QPoint pos() const override;
void setPos(const QPoint &pos) override;
+ QSize size() const override;
+
static QSharedPointer<QWaylandBuffer> cursorBitmapBuffer(QWaylandDisplay *display, const QCursor *cursor);
protected:
diff --git a/src/client/qwaylanddatadevice.cpp b/src/client/qwaylanddatadevice.cpp
index 6034cd60e..a59b201f6 100644
--- a/src/client/qwaylanddatadevice.cpp
+++ b/src/client/qwaylanddatadevice.cpp
@@ -13,6 +13,8 @@
#include "qwaylandabstractdecoration_p.h"
#include "qwaylandsurface_p.h"
+#include <QtWaylandClient/private/qwayland-xdg-toplevel-drag-v1.h>
+
#include <QtCore/QMimeData>
#include <QtGui/QGuiApplication>
#include <QtGui/private/qguiapplication_p.h>
@@ -27,6 +29,8 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
+using namespace Qt::StringLiterals;
+
QWaylandDataDevice::QWaylandDataDevice(QWaylandDataDeviceManager *manager, QWaylandInputDevice *inputDevice)
: QObject(inputDevice)
, QtWayland::wl_data_device(manager->get_data_device(inputDevice->wl_seat()))
@@ -39,6 +43,8 @@ QWaylandDataDevice::~QWaylandDataDevice()
{
if (version() >= WL_DATA_DEVICE_RELEASE_SINCE_VERSION)
release();
+ else
+ wl_data_device_destroy(object());
}
QWaylandDataOffer *QWaylandDataDevice::selectionOffer() const
@@ -89,6 +95,12 @@ bool QWaylandDataDevice::startDrag(QMimeData *mimeData, Qt::DropActions supporte
return false;
}
+ // dragging data without mimetypes is a legal operation in Qt terms
+ // but Wayland uses a mimetype to determine if a drag is accepted or not
+ // In this rare case, insert a placeholder
+ if (mimeData->formats().isEmpty())
+ mimeData->setData("application/x-qt-avoid-empty-placeholder"_L1, QByteArray("1"));
+
m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData));
if (version() >= 3)
@@ -97,6 +109,9 @@ bool QWaylandDataDevice::startDrag(QMimeData *mimeData, Qt::DropActions supporte
connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled);
connect(m_dragSource.data(), &QWaylandDataSource::dndResponseUpdated, this, [this](bool accepted, Qt::DropAction action) {
auto drag = static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag());
+ if (!drag->currentDrag()) {
+ return;
+ }
// in old versions drop action is not set, so we guess
if (m_dragSource->version() < 3) {
drag->setResponse(accepted);
@@ -105,14 +120,47 @@ bool QWaylandDataDevice::startDrag(QMimeData *mimeData, Qt::DropActions supporte
drag->setResponse(response);
}
});
- connect(m_dragSource.data(), &QWaylandDataSource::dndDropped, this, [](bool accepted, Qt::DropAction action) {
- QPlatformDropQtResponse response(accepted, action);
- static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setDropResponse(response);
- });
- connect(m_dragSource.data(), &QWaylandDataSource::finished, this, []() {
+ connect(m_dragSource.data(), &QWaylandDataSource::dndDropped, this,
+ [this](bool accepted, Qt::DropAction action) {
+ QPlatformDropQtResponse response(accepted, action);
+ if (m_toplevelDrag) {
+ // If the widget was dropped but the drag not accepted it
+ // should be its own window in the future. To distinguish
+ // from canceling mid-drag the drag is accepted here as the
+ // we know if the widget is over a zone where it can be
+ // incorporated or not
+ response = { accepted, Qt::MoveAction };
+ }
+ static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())
+ ->setDropResponse(response);
+ });
+ connect(m_dragSource.data(), &QWaylandDataSource::finished, this, [this]() {
static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag();
+ if (m_toplevelDrag) {
+ m_toplevelDrag->destroy();
+ m_toplevelDrag = nullptr;
+ }
});
+ if (mimeData->hasFormat("application/x-qt-mainwindowdrag-window"_L1)
+ && m_display->xdgToplevelDragManager()) {
+ qintptr dockWindowPtr;
+ QPoint offset;
+ QDataStream windowStream(mimeData->data("application/x-qt-mainwindowdrag-window"_L1));
+ windowStream >> dockWindowPtr;
+ QWindow *dockWindow = reinterpret_cast<QWindow *>(dockWindowPtr);
+ QDataStream offsetStream(mimeData->data("application/x-qt-mainwindowdrag-position"_L1));
+ offsetStream >> offset;
+ if (auto waylandWindow = static_cast<QWaylandWindow *>(dockWindow->handle())) {
+ if (auto toplevel = waylandWindow->surfaceRole<xdg_toplevel>()) {
+ m_toplevelDrag = new QtWayland::xdg_toplevel_drag_v1(
+ m_display->xdgToplevelDragManager()->get_xdg_toplevel_drag(
+ m_dragSource->object()));
+ m_toplevelDrag->attach(toplevel, offset.x(), offset.y());
+ }
+ }
+ }
+
start_drag(m_dragSource->object(), origin->wlSurface(), icon->wlSurface(), m_display->currentInputDevice()->serial());
return true;
}
@@ -148,7 +196,6 @@ void QWaylandDataDevice::data_device_drop()
QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(m_dragWindow, dragData, m_dragPoint, supportedActions,
QGuiApplication::mouseButtons(),
QGuiApplication::keyboardModifiers());
-
if (drag) {
auto drag = static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag());
drag->setDropResponse(response);
@@ -181,10 +228,9 @@ void QWaylandDataDevice::data_device_enter(uint32_t serial, wl_surface *surface,
supportedActions = m_dragOffer->supportedActions();
}
- const QPlatformDragQtResponse &response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions,
- QGuiApplication::mouseButtons(),
- QGuiApplication::keyboardModifiers());
-
+ const QPlatformDragQtResponse &response = QWindowSystemInterface::handleDrag(
+ m_dragWindow, dragData, m_dragPoint, supportedActions, QGuiApplication::mouseButtons(),
+ QGuiApplication::keyboardModifiers());
if (drag) {
static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setResponse(response);
}
@@ -261,7 +307,12 @@ void QWaylandDataDevice::selectionSourceCancelled()
#if QT_CONFIG(draganddrop)
void QWaylandDataDevice::dragSourceCancelled()
{
+ static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag();
m_dragSource.reset();
+ if (m_toplevelDrag) {
+ m_toplevelDrag->destroy();
+ m_toplevelDrag = nullptr;
+ }
}
QPoint QWaylandDataDevice::calculateDragPosition(int x, int y, QWindow *wnd) const
diff --git a/src/client/qwaylanddatadevice_p.h b/src/client/qwaylanddatadevice_p.h
index 76c8965f9..3dc4fcaf6 100644
--- a/src/client/qwaylanddatadevice_p.h
+++ b/src/client/qwaylanddatadevice_p.h
@@ -31,6 +31,10 @@ class QMimeData;
class QPlatformDragQtResponse;
class QWindow;
+namespace QtWayland {
+class xdg_toplevel_drag_v1;
+}
+
namespace QtWaylandClient {
class QWaylandDisplay;
@@ -93,8 +97,8 @@ private:
QScopedPointer<QWaylandDataOffer> m_dragOffer;
QScopedPointer<QWaylandDataOffer> m_selectionOffer;
QScopedPointer<QWaylandDataSource> m_selectionSource;
-
QScopedPointer<QWaylandDataSource> m_dragSource;
+ QtWayland::xdg_toplevel_drag_v1 *m_toplevelDrag = nullptr;
};
}
diff --git a/src/client/qwaylanddataoffer.cpp b/src/client/qwaylanddataoffer.cpp
index 533c0023a..8110ce35f 100644
--- a/src/client/qwaylanddataoffer.cpp
+++ b/src/client/qwaylanddataoffer.cpp
@@ -11,6 +11,8 @@
#include <QtCore/QDebug>
+using namespace std::chrono;
+
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
@@ -20,6 +22,65 @@ static QString utf8Text()
return QStringLiteral("text/plain;charset=utf-8");
}
+static QString uriList()
+{
+ return QStringLiteral("text/uri-list");
+}
+
+static QString mozUrl()
+{
+ return QStringLiteral("text/x-moz-url");
+}
+
+static QString portalFileTransfer()
+{
+ return QStringLiteral("application/vnd.portal.filetransfer");
+}
+
+static QByteArray convertData(const QString &originalMime, const QString &newMime, const QByteArray &data)
+{
+ if (originalMime == newMime)
+ return data;
+
+ // Convert text/x-moz-url, which is an UTF-16 string of
+ // URL and page title pairs, all separated by line breaks, to text/uri-list.
+ // see also qtbase/src/plugins/platforms/xcb/qxcbmime.cpp
+ if (originalMime == uriList() && newMime == mozUrl()) {
+ if (data.size() > 1) {
+ const quint8 byte0 = data.at(0);
+ const quint8 byte1 = data.at(1);
+
+ if ((byte0 == 0xff && byte1 == 0xfe) || (byte0 == 0xfe && byte1 == 0xff)
+ || (byte0 != 0 && byte1 == 0) || (byte0 == 0 && byte1 != 0)) {
+ QByteArray converted;
+ const QString str = QString::fromUtf16(
+ reinterpret_cast<const char16_t *>(data.constData()), data.size() / 2);
+ if (!str.isNull()) {
+ const auto urls = QStringView{str}.split(u'\n');
+ // Only the URL is interesting, skip the page title.
+ for (int i = 0; i < urls.size(); i += 2) {
+ const QUrl url(urls.at(i).trimmed().toString());
+ if (url.isValid()) {
+ converted += url.toEncoded();
+ converted += "\r\n";
+ }
+ }
+ }
+ return converted;
+ // 8 byte encoding, remove a possible 0 at the end.
+ } else {
+ QByteArray converted = data;
+ if (converted.endsWith('\0'))
+ converted.chop(1);
+ converted += "\r\n";
+ return converted;
+ }
+ }
+ }
+
+ return data;
+}
+
QWaylandDataOffer::QWaylandDataOffer(QWaylandDisplay *display, struct ::wl_data_offer *offer)
: QtWayland::wl_data_offer(offer)
, m_display(display)
@@ -93,8 +154,11 @@ QWaylandMimeData::~QWaylandMimeData()
void QWaylandMimeData::appendFormat(const QString &mimeType)
{
- m_types << mimeType;
- m_data.remove(mimeType); // Clear previous contents
+ // "DELETE" is a potential leftover from XdndActionMode sent by e.g. Firefox, ignore it.
+ if (mimeType != QLatin1String("DELETE")) {
+ m_types << mimeType;
+ m_data.remove(mimeType); // Clear previous contents
+ }
}
bool QWaylandMimeData::hasFormat_sys(const QString &mimeType) const
@@ -105,6 +169,9 @@ bool QWaylandMimeData::hasFormat_sys(const QString &mimeType) const
if (mimeType == QStringLiteral("text/plain") && m_types.contains(utf8Text()))
return true;
+ if (mimeType == uriList() && m_types.contains(mozUrl()))
+ return true;
+
return false;
}
@@ -117,14 +184,17 @@ QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QMetaType t
{
Q_UNUSED(type);
- if (m_data.contains(mimeType))
- return m_data.value(mimeType);
+ auto it = m_data.constFind(mimeType);
+ if (it != m_data.constEnd())
+ return *it;
QString mime = mimeType;
if (!m_types.contains(mimeType)) {
if (mimeType == QStringLiteral("text/plain") && m_types.contains(utf8Text()))
mime = utf8Text();
+ else if (mimeType == uriList() && m_types.contains(mozUrl()))
+ mime = mozUrl();
else
return QVariant();
}
@@ -146,7 +216,12 @@ QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QMetaType t
}
close(pipefd[0]);
- m_data.insert(mimeType, content);
+
+ content = convertData(mimeType, mime, content);
+
+ if (mimeType != portalFileTransfer())
+ m_data.insert(mimeType, content);
+
return content;
}
@@ -155,13 +230,9 @@ int QWaylandMimeData::readData(int fd, QByteArray &data) const
struct pollfd readset;
readset.fd = fd;
readset.events = POLLIN;
- struct timespec timeout;
- timeout.tv_sec = 1;
- timeout.tv_nsec = 0;
-
Q_FOREVER {
- int ready = qt_safe_poll(&readset, 1, &timeout);
+ int ready = qt_safe_poll(&readset, 1, QDeadlineTimer(1s));
if (ready < 0) {
qWarning() << "QWaylandDataOffer: qt_safe_poll() failed";
return -1;
diff --git a/src/client/qwaylanddatasource.cpp b/src/client/qwaylanddatasource.cpp
index ef1d14d39..966d5ef7f 100644
--- a/src/client/qwaylanddatasource.cpp
+++ b/src/client/qwaylanddatasource.cpp
@@ -13,6 +13,7 @@
#include <unistd.h>
#include <signal.h>
+#include <fcntl.h>
QT_BEGIN_NAMESPACE
@@ -35,11 +36,6 @@ QWaylandDataSource::~QWaylandDataSource()
destroy();
}
-QMimeData * QWaylandDataSource::mimeData() const
-{
- return m_mime_data;
-}
-
void QWaylandDataSource::data_source_cancelled()
{
Q_EMIT cancelled();
@@ -57,6 +53,13 @@ void QWaylandDataSource::data_source_send(const QString &mime_type, int32_t fd)
action.sa_flags = 0;
sigaction(SIGPIPE, &action, &oldAction);
+ // Some compositors (e.g., mutter) make fd with O_NONBLOCK.
+ // Since wl_data_source.send describes that fd is closed here,
+ // it should be done in a loop and don't have any advantage.
+ // Blocking operation will be used.
+ // According to fcntl(2), FSETFL ignores O_WRONLY. So this
+ // call will just remove O_NONBLOCK.
+ fcntl(fd, F_SETFL, O_WRONLY);
ssize_t unused = write(fd, content.constData(), content.size());
Q_UNUSED(unused);
sigaction(SIGPIPE, &oldAction, nullptr);
diff --git a/src/client/qwaylanddatasource_p.h b/src/client/qwaylanddatasource_p.h
index 0ce09a409..a4b317c26 100644
--- a/src/client/qwaylanddatasource_p.h
+++ b/src/client/qwaylanddatasource_p.h
@@ -38,8 +38,6 @@ public:
QWaylandDataSource(QWaylandDataDeviceManager *dataDeviceManager, QMimeData *mimeData);
~QWaylandDataSource() override;
- QMimeData *mimeData() const;
-
Q_SIGNALS:
void cancelled();
void finished();
diff --git a/src/client/qwaylanddecorationfactory.cpp b/src/client/qwaylanddecorationfactory.cpp
index e2f1af2f1..b716a4aee 100644
--- a/src/client/qwaylanddecorationfactory.cpp
+++ b/src/client/qwaylanddecorationfactory.cpp
@@ -12,17 +12,17 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
-Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, qwdfiLoader,
(QWaylandDecorationFactoryInterface_iid, QLatin1String("/wayland-decoration-client"), Qt::CaseInsensitive))
QStringList QWaylandDecorationFactory::keys()
{
- return loader->keyMap().values();
+ return qwdfiLoader->keyMap().values();
}
QWaylandAbstractDecoration *QWaylandDecorationFactory::create(const QString &name, const QStringList &args)
{
- return qLoadPlugin<QWaylandAbstractDecoration, QWaylandDecorationPlugin>(loader(), name, args);
+ return qLoadPlugin<QWaylandAbstractDecoration, QWaylandDecorationPlugin>(qwdfiLoader(), name, args);
}
}
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
index c75ede732..265f0bb3f 100644
--- a/src/client/qwaylanddisplay.cpp
+++ b/src/client/qwaylanddisplay.cpp
@@ -26,9 +26,7 @@
#include "qwaylandhardwareintegration_p.h"
#include "qwaylandtextinputv1_p.h"
#include "qwaylandtextinputv2_p.h"
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
-#include "qwaylandtextinputv4_p.h"
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
+#include "qwaylandtextinputv3_p.h"
#include "qwaylandinputcontext_p.h"
#include "qwaylandinputmethodcontext_p.h"
@@ -47,9 +45,13 @@
#include <QtWaylandClient/private/qwayland-text-input-unstable-v1.h>
#include <QtWaylandClient/private/qwayland-text-input-unstable-v2.h>
-#include <QtWaylandClient/private/qwayland-text-input-unstable-v4-wip.h>
+#include <QtWaylandClient/private/qwayland-text-input-unstable-v3.h>
#include <QtWaylandClient/private/qwayland-wp-primary-selection-unstable-v1.h>
#include <QtWaylandClient/private/qwayland-qt-text-input-method-unstable-v1.h>
+#include <QtWaylandClient/private/qwayland-fractional-scale-v1.h>
+#include <QtWaylandClient/private/qwayland-viewporter.h>
+#include <QtWaylandClient/private/qwayland-cursor-shape-v1.h>
+#include <QtWaylandClient/private/qwayland-xdg-toplevel-drag-v1.h>
#include <QtCore/private/qcore_unix_p.h>
@@ -63,18 +65,6 @@
#include <tuple> // for std::tie
-static void checkWaylandError(struct wl_display *display)
-{
- int ecode = wl_display_get_error(display);
- if ((ecode == EPIPE || ecode == ECONNRESET)) {
- // special case this to provide a nicer error
- qWarning("The Wayland connection broke. Did the Wayland compositor die?");
- } else {
- qWarning("The Wayland connection experienced a fatal error: %s", strerror(ecode));
- }
- _exit(1);
-}
-
QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
@@ -112,9 +102,13 @@ public:
* not only the one issued from event thread's waitForReading(), which means functions
* called from dispatch_pending() can safely spin an event loop.
*/
+ if (m_quitting)
+ return;
+
for (;;) {
if (dispatchQueuePending() < 0) {
- checkWaylandError(m_wldisplay);
+ Q_EMIT waylandError();
+ m_quitting = true;
return;
}
@@ -152,6 +146,7 @@ public:
Q_SIGNALS:
void needReadAndDispatch();
+ void waylandError();
protected:
void run() override
@@ -265,14 +260,14 @@ Q_LOGGING_CATEGORY(lcQpaWayland, "qt.qpa.wayland"); // for general (uncategorize
struct wl_surface *QWaylandDisplay::createSurface(void *handle)
{
- struct wl_surface *surface = mCompositor.create_surface();
+ struct wl_surface *surface = mGlobals.compositor->create_surface();
wl_surface_set_user_data(surface, handle);
return surface;
}
struct ::wl_region *QWaylandDisplay::createRegion(const QRegion &qregion)
{
- struct ::wl_region *region = mCompositor.create_region();
+ struct ::wl_region *region = mGlobals.compositor->create_region();
for (const QRect &rect : qregion)
wl_region_add(region, rect.x(), rect.y(), rect.width(), rect.height());
@@ -282,7 +277,7 @@ struct ::wl_region *QWaylandDisplay::createRegion(const QRegion &qregion)
::wl_subsurface *QWaylandDisplay::createSubSurface(QWaylandWindow *window, QWaylandWindow *parent)
{
- if (!mSubCompositor) {
+ if (!mGlobals.subCompositor) {
qCWarning(lcQpaWayland) << "Can't create subsurface, not supported by the compositor.";
return nullptr;
}
@@ -291,7 +286,18 @@ struct ::wl_region *QWaylandDisplay::createRegion(const QRegion &qregion)
Q_ASSERT(parent->wlSurface());
Q_ASSERT(window->wlSurface());
- return mSubCompositor->get_subsurface(window->wlSurface(), parent->wlSurface());
+ return mGlobals.subCompositor->get_subsurface(window->wlSurface(), parent->wlSurface());
+}
+
+::wp_viewport *QWaylandDisplay::createViewport(QWaylandWindow *window)
+{
+ if (!mGlobals.viewporter) {
+ qCWarning(lcQpaWayland) << "Can't create wp_viewport, not supported by the compositor.";
+ return nullptr;
+ }
+
+ Q_ASSERT(window->wlSurface());
+ return mGlobals.viewporter->get_viewport(window->wlSurface());
}
QWaylandShellIntegration *QWaylandDisplay::shellIntegration() const
@@ -315,11 +321,17 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration)
qRegisterMetaType<uint32_t>("uint32_t");
mDisplay = wl_display_connect(nullptr);
- if (!mDisplay) {
+ if (mDisplay) {
+ setupConnection();
+ } else {
qErrnoWarning(errno, "Failed to create wl_display");
- return;
}
+ mWaylandTryReconnect = qEnvironmentVariableIsSet("QT_WAYLAND_RECONNECT");
+}
+
+void QWaylandDisplay::setupConnection()
+{
struct ::wl_registry *registry = wl_display_get_registry(mDisplay);
init(registry);
@@ -330,7 +342,7 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration)
if (!mXkbContext)
qCWarning(lcQpaWayland, "failed to create xkb context");
#endif
- if (!mClientSideInputContextRequested)
+ if (mWaylandInputContextRequested)
checkTextInputProtocol();
}
@@ -345,38 +357,50 @@ QWaylandDisplay::~QWaylandDisplay(void)
if (mSyncCallback)
wl_callback_destroy(mSyncCallback);
- qDeleteAll(qExchange(mInputDevices, {}));
+ qDeleteAll(std::exchange(mInputDevices, {}));
- for (QWaylandScreen *screen : qExchange(mScreens, {})) {
+ for (QWaylandScreen *screen : std::exchange(mScreens, {})) {
QWindowSystemInterface::handleScreenRemoved(screen);
}
qDeleteAll(mWaitingScreens);
-#if QT_CONFIG(wayland_datadevice)
- mDndSelectionHandler.reset();
-#endif
#if QT_CONFIG(cursor)
mCursorThemes.clear();
#endif
- if (mDisplay)
- wl_display_disconnect(mDisplay);
if (m_frameEventQueue)
wl_event_queue_destroy(m_frameEventQueue);
+
+ // Reset the globals manually since they need to be destroyed before the wl_display
+ mGlobals = {};
+ mWindowManagerIntegration.reset();
+
+ if (object())
+ wl_registry_destroy(object());
+
+ if (mDisplay)
+ wl_display_disconnect(mDisplay);
}
// Steps which is called just after constructor. This separates registry_global() out of the constructor
// so that factory functions in integration can be overridden.
-void QWaylandDisplay::initialize()
+bool QWaylandDisplay::initialize()
{
+ if (!isInitialized())
+ return false;
+
forceRoundTrip();
+ emit connected();
+
if (!mWaitingScreens.isEmpty()) {
// Give wl_output.done and zxdg_output_v1.done events a chance to arrive
forceRoundTrip();
}
- if (!mClientSideInputContextRequested)
+ if (mWaylandInputContextRequested)
mTextInputManagerIndex = INT_MAX;
+
+ return qEnvironmentVariableIntValue("QT_WAYLAND_DONT_CHECK_SHELL_INTEGRATION") || shellIntegration();
}
void QWaylandDisplay::ensureScreen()
@@ -391,7 +415,94 @@ void QWaylandDisplay::ensureScreen()
Q_ASSERT(!QGuiApplication::screens().empty());
}
-// Called in main thread, either from queued signal or directly.
+void QWaylandDisplay::reconnect()
+{
+ qCWarning(lcQpaWayland) << "Attempting wayland reconnect";
+ m_eventThread->stop();
+ m_frameEventQueueThread->stop();
+ m_eventThread->wait();
+ m_frameEventQueueThread->wait();
+
+ qDeleteAll(mWaitingScreens);
+ mWaitingScreens.clear();
+
+ while (!mScreens.isEmpty()) {
+ auto screen = mScreens.takeLast();
+ ensureScreen();
+ QWindowSystemInterface::handleScreenRemoved(screen);
+ }
+
+ mCursorThemes.clear();
+ mCursor.reset();
+
+ mGlobals = GlobalHolder();
+
+ mWaylandIntegration->reset();
+
+ qDeleteAll(std::exchange(mInputDevices, {}));
+ mLastInputDevice = nullptr;
+
+ for (const RegistryGlobal &global : mRegistryGlobals) {
+ emit globalRemoved(global);
+ }
+ mRegistryGlobals.clear();
+
+ mLastInputSerial = 0;
+ mLastInputWindow.clear();
+ mLastKeyboardFocus.clear();
+ mActiveWindows.clear();
+
+ const auto windows = QGuiApplication::allWindows();
+ for (auto window : windows) {
+ if (auto waylandWindow = static_cast<QWaylandWindow *>(window->handle()))
+ waylandWindow->closeChildPopups();
+ }
+ // Remove windows that do not need to be recreated and now closed popups
+ QList<QWaylandWindow *> recreateWindows;
+ for (auto window : std::as_const(windows)) {
+ auto waylandWindow = static_cast<QWaylandWindow*>(window->handle());
+ if (waylandWindow && waylandWindow->wlSurface()) {
+ waylandWindow->reset();
+ recreateWindows.push_back(waylandWindow);
+ }
+ }
+
+ if (mSyncCallback) {
+ wl_callback_destroy(mSyncCallback);
+ mSyncCallback = nullptr;
+ }
+
+ if (object())
+ wl_registry_destroy(object());
+ mDisplay = wl_display_connect(nullptr);
+ if (!mDisplay)
+ _exit(1);
+
+ setupConnection();
+ initialize();
+
+ if (m_frameEventQueue)
+ wl_event_queue_destroy(m_frameEventQueue);
+ initEventThread();
+
+ auto needsRecreate = [](QPlatformWindow *window) {
+ return window && !static_cast<QWaylandWindow *>(window)->wlSurface();
+ };
+ auto window = recreateWindows.begin();
+ while (!recreateWindows.isEmpty()) {
+ if (!needsRecreate((*window)->QPlatformWindow::parent()) && !needsRecreate((*window)->transientParent())) {
+ (*window)->reinit();
+ window = recreateWindows.erase(window);
+ } else {
+ ++window;
+ }
+ if (window == recreateWindows.end())
+ window = recreateWindows.begin();
+ }
+
+ mWaylandIntegration->reconfigureInputContext();
+}
+
void QWaylandDisplay::flushRequests()
{
m_eventThread->readAndDispatchEvents();
@@ -406,6 +517,8 @@ void QWaylandDisplay::initEventThread()
new EventThread(mDisplay, /* default queue */ nullptr, EventThread::EmitToDispatch));
connect(m_eventThread.get(), &EventThread::needReadAndDispatch, this,
&QWaylandDisplay::flushRequests, Qt::QueuedConnection);
+ connect(m_eventThread.get(), &EventThread::waylandError, this,
+ &QWaylandDisplay::checkWaylandError, Qt::QueuedConnection);
m_eventThread->start();
// wl_display_disconnect() free this.
@@ -415,25 +528,48 @@ void QWaylandDisplay::initEventThread()
m_frameEventQueueThread->start();
}
+void QWaylandDisplay::checkWaylandError()
+{
+ int ecode = wl_display_get_error(mDisplay);
+ if ((ecode == EPIPE || ecode == ECONNRESET)) {
+ qWarning("The Wayland connection broke. Did the Wayland compositor die?");
+ if (mWaylandTryReconnect) {
+ reconnect();
+ return;
+ }
+ } else {
+ qWarning("The Wayland connection experienced a fatal error: %s", strerror(ecode));
+ }
+ _exit(-1);
+}
+
void QWaylandDisplay::blockingReadEvents()
{
- if (wl_display_dispatch(mDisplay) < 0)
- checkWaylandError(mDisplay);
+ if (wl_display_dispatch(mDisplay) < 0) {
+ int ecode = wl_display_get_error(mDisplay);
+ if ((ecode == EPIPE || ecode == ECONNRESET))
+ qWarning("The Wayland connection broke during blocking read event. Did the Wayland compositor die?");
+ else
+ qWarning("The Wayland connection experienced a fatal error during blocking read event: %s", strerror(ecode));
+ _exit(-1);
+ }
}
void QWaylandDisplay::checkTextInputProtocol()
{
QStringList tips, timps; // for text input protocols and text input manager protocols
+ // zwp_text_input_v2 is preferred over zwp_text_input_v3 because:
+ // - Currently, v3 is not as feature rich as v2.
+ // - While v2 is not upstreamed, it is well supported by KWin since Plasma 5 and Plasma
+ // Mobile uses some v2 only.
tips << QLatin1String(QtWayland::qt_text_input_method_v1::interface()->name)
<< QLatin1String(QtWayland::zwp_text_input_v2::interface()->name)
+ << QLatin1String(QtWayland::zwp_text_input_v3::interface()->name)
<< QLatin1String(QtWayland::zwp_text_input_v1::interface()->name);
timps << QLatin1String(QtWayland::qt_text_input_method_manager_v1::interface()->name)
<< QLatin1String(QtWayland::zwp_text_input_manager_v2::interface()->name)
+ << QLatin1String(QtWayland::zwp_text_input_manager_v3::interface()->name)
<< QLatin1String(QtWayland::zwp_text_input_manager_v1::interface()->name);
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- tips << QLatin1String(QtWayland::zwp_text_input_v4::interface()->name);
- timps << QLatin1String(QtWayland::zwp_text_input_manager_v4::interface()->name);
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
QString tiProtocols = QString::fromLocal8Bit(qgetenv("QT_WAYLAND_TEXT_INPUT_PROTOCOL"));
qCDebug(lcQpaWayland) << "QT_WAYLAND_TEXT_INPUT_PROTOCOL=" << tiProtocols;
@@ -455,7 +591,7 @@ void QWaylandDisplay::checkTextInputProtocol()
QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const
{
- for (auto screen : qAsConst(mScreens)) {
+ for (auto screen : std::as_const(mScreens)) {
if (screen->output() == output)
return screen;
}
@@ -475,75 +611,104 @@ void QWaylandDisplay::handleScreenInitialized(QWaylandScreen *screen)
}
}
+template <typename T, auto f>
+struct WithDestructor : public T
+{
+ using T::T;
+ ~WithDestructor()
+ {
+ f(this->object());
+ }
+};
+
void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uint32_t version)
{
struct ::wl_registry *registry = object();
+ static QStringList interfaceBlacklist = qEnvironmentVariable("QT_WAYLAND_DISABLED_INTERFACES").split(u',');
+ if (interfaceBlacklist.contains(interface)) {
+ return;
+ }
+
if (interface == QLatin1String(QtWayland::wl_output::interface()->name)) {
mWaitingScreens << mWaylandIntegration->createPlatformScreen(this, version, id);
} else if (interface == QLatin1String(QtWayland::wl_compositor::interface()->name)) {
- mCompositor.init(registry, id, qMin((int)version, 4));
+ mGlobals.compositor.reset(
+ new WithDestructor<QtWayland::wl_compositor, wl_compositor_destroy>(
+ registry, id, qMin((int)version, 6)));
} else if (interface == QLatin1String(QWaylandShm::interface()->name)) {
- mShm.reset(new QWaylandShm(this, version, id));
+ mGlobals.shm.reset(new QWaylandShm(this, version, id));
} else if (interface == QLatin1String(QWaylandInputDevice::interface()->name)) {
QWaylandInputDevice *inputDevice = mWaylandIntegration->createInputDevice(this, version, id);
mInputDevices.append(inputDevice);
#if QT_CONFIG(wayland_datadevice)
} else if (interface == QLatin1String(QWaylandDataDeviceManager::interface()->name)) {
- mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, version, id));
+ mGlobals.dndSelectionHandler.reset(new QWaylandDataDeviceManager(this, version, id));
#endif
} else if (interface == QLatin1String(QtWayland::qt_surface_extension::interface()->name)) {
- mWindowExtension.reset(new QtWayland::qt_surface_extension(registry, id, 1));
+ mGlobals.surfaceExtension.reset(
+ new WithDestructor<QtWayland::qt_surface_extension, qt_surface_extension_destroy>(
+ registry, id, 1));
} else if (interface == QLatin1String(QtWayland::wl_subcompositor::interface()->name)) {
- mSubCompositor.reset(new QtWayland::wl_subcompositor(registry, id, 1));
+ mGlobals.subCompositor.reset(
+ new WithDestructor<QtWayland::wl_subcompositor, wl_subcompositor_destroy>(registry,
+ id, 1));
} else if (interface == QLatin1String(QWaylandTouchExtension::interface()->name)) {
- mTouchExtension.reset(new QWaylandTouchExtension(this, id));
+ mGlobals.touchExtension.reset(new QWaylandTouchExtension(this, id));
} else if (interface == QLatin1String(QWaylandQtKeyExtension::interface()->name)) {
- mQtKeyExtension.reset(new QWaylandQtKeyExtension(this, id));
+ mGlobals.qtKeyExtension.reset(new QWaylandQtKeyExtension(this, id));
#if QT_CONFIG(tabletevent)
} else if (interface == QLatin1String(QWaylandTabletManagerV2::interface()->name)) {
- mTabletManager.reset(new QWaylandTabletManagerV2(this, id, qMin(1, int(version))));
+ mGlobals.tabletManager.reset(new QWaylandTabletManagerV2(this, id, qMin(1, int(version))));
#endif
} else if (interface == QLatin1String(QWaylandPointerGestures::interface()->name)) {
- mPointerGestures.reset(new QWaylandPointerGestures(this, id, 1));
+ mGlobals.pointerGestures.reset(new QWaylandPointerGestures(this, id, 1));
#if QT_CONFIG(wayland_client_primary_selection)
} else if (interface == QLatin1String(QWaylandPrimarySelectionDeviceManagerV1::interface()->name)) {
- mPrimarySelectionManager.reset(new QWaylandPrimarySelectionDeviceManagerV1(this, id, 1));
+ mGlobals.primarySelectionManager.reset(
+ new QWaylandPrimarySelectionDeviceManagerV1(this, id, 1));
+ for (QWaylandInputDevice *inputDevice : std::as_const(mInputDevices))
+ inputDevice->setPrimarySelectionDevice(
+ mGlobals.primarySelectionManager->createDevice(inputDevice));
#endif
} else if (interface == QLatin1String(QtWayland::qt_text_input_method_manager_v1::interface()->name)
&& (mTextInputManagerList.contains(interface) && mTextInputManagerList.indexOf(interface) < mTextInputManagerIndex)) {
qCDebug(lcQpaWayland) << "text input: register qt_text_input_method_manager_v1";
if (mTextInputManagerIndex < INT_MAX) {
- mTextInputManagerv1.reset();
- mTextInputManagerv2.reset();
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- mTextInputManagerv4.reset();
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
- for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
+ mGlobals.textInputManagerv1.reset();
+ mGlobals.textInputManagerv2.reset();
+ mGlobals.textInputManagerv3.reset();
+ for (QWaylandInputDevice *inputDevice : std::as_const(mInputDevices))
inputDevice->setTextInput(nullptr);
}
- mTextInputMethodManager.reset(new QtWayland::qt_text_input_method_manager_v1(registry, id, 1));
- for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
- inputDevice->setTextInputMethod(new QWaylandTextInputMethod(this, mTextInputMethodManager->get_text_input_method(inputDevice->wl_seat())));
+ mGlobals.textInputMethodManager.reset(
+ new WithDestructor<QtWayland::qt_text_input_method_manager_v1,
+ qt_text_input_method_manager_v1_destroy>(registry, id, 1));
+ for (QWaylandInputDevice *inputDevice : std::as_const(mInputDevices))
+ inputDevice->setTextInputMethod(new QWaylandTextInputMethod(
+ this,
+ mGlobals.textInputMethodManager->get_text_input_method(
+ inputDevice->wl_seat())));
mWaylandIntegration->reconfigureInputContext();
mTextInputManagerIndex = mTextInputManagerList.indexOf(interface);
} else if (interface == QLatin1String(QtWayland::zwp_text_input_manager_v1::interface()->name)
&& (mTextInputManagerList.contains(interface) && mTextInputManagerList.indexOf(interface) < mTextInputManagerIndex)) {
qCDebug(lcQpaWayland) << "text input: register zwp_text_input_v1";
if (mTextInputManagerIndex < INT_MAX) {
- mTextInputMethodManager.reset();
- mTextInputManagerv2.reset();
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- mTextInputManagerv4.reset();
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
- for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
+ mGlobals.textInputMethodManager.reset();
+ mGlobals.textInputManagerv2.reset();
+ mGlobals.textInputManagerv3.reset();
+ for (QWaylandInputDevice *inputDevice : std::as_const(mInputDevices))
inputDevice->setTextInputMethod(nullptr);
}
- mTextInputManagerv1.reset(new QtWayland::zwp_text_input_manager_v1(registry, id, 1));
- for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices)) {
- auto textInput = new QWaylandTextInputv1(this, mTextInputManagerv1->create_text_input());
+ mGlobals.textInputManagerv1.reset(
+ new WithDestructor<QtWayland::zwp_text_input_manager_v1,
+ zwp_text_input_manager_v1_destroy>(registry, id, 1));
+ for (QWaylandInputDevice *inputDevice : std::as_const(mInputDevices)) {
+ auto textInput =
+ new QWaylandTextInputv1(this, mGlobals.textInputManagerv1->create_text_input());
textInput->setSeat(inputDevice->wl_seat());
inputDevice->setTextInput(textInput);
}
@@ -554,54 +719,72 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
&& (mTextInputManagerList.contains(interface) && mTextInputManagerList.indexOf(interface) < mTextInputManagerIndex)) {
qCDebug(lcQpaWayland) << "text input: register zwp_text_input_v2";
if (mTextInputManagerIndex < INT_MAX) {
- mTextInputMethodManager.reset();
- mTextInputManagerv1.reset();
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- mTextInputManagerv4.reset();
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
- for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
+ mGlobals.textInputMethodManager.reset();
+ mGlobals.textInputManagerv1.reset();
+ mGlobals.textInputManagerv3.reset();
+ for (QWaylandInputDevice *inputDevice : std::as_const(mInputDevices))
inputDevice->setTextInputMethod(nullptr);
}
- mTextInputManagerv2.reset(new QtWayland::zwp_text_input_manager_v2(registry, id, 1));
- for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
- inputDevice->setTextInput(new QWaylandTextInputv2(this, mTextInputManagerv2->get_text_input(inputDevice->wl_seat())));
+ mGlobals.textInputManagerv2.reset(
+ new WithDestructor<QtWayland::zwp_text_input_manager_v2,
+ zwp_text_input_manager_v2_destroy>(registry, id, 1));
+ for (QWaylandInputDevice *inputDevice : std::as_const(mInputDevices))
+ inputDevice->setTextInput(new QWaylandTextInputv2(
+ this, mGlobals.textInputManagerv2->get_text_input(inputDevice->wl_seat())));
mWaylandIntegration->reconfigureInputContext();
mTextInputManagerIndex = mTextInputManagerList.indexOf(interface);
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- } else if (interface == QLatin1String(QtWayland::zwp_text_input_manager_v4::interface()->name)
+ } else if (interface == QLatin1String(QtWayland::zwp_text_input_manager_v3::interface()->name)
&& (mTextInputManagerList.contains(interface) && mTextInputManagerList.indexOf(interface) < mTextInputManagerIndex)) {
- qCDebug(lcQpaWayland) << "text input: register zwp_text_input_v4";
+ qCDebug(lcQpaWayland) << "text input: register zwp_text_input_v3";
if (mTextInputManagerIndex < INT_MAX) {
- mTextInputMethodManager.reset();
- mTextInputManagerv2.reset();
- for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
+ mGlobals.textInputMethodManager.reset();
+ mGlobals.textInputManagerv2.reset();
+ for (QWaylandInputDevice *inputDevice : std::as_const(mInputDevices))
inputDevice->setTextInputMethod(nullptr);
}
+ mGlobals.textInputManagerv3.reset(
+ new WithDestructor<QtWayland::zwp_text_input_manager_v3,
+ zwp_text_input_manager_v3_destroy>(registry, id, 1));
+ for (QWaylandInputDevice *inputDevice : std::as_const(mInputDevices))
+ inputDevice->setTextInput(new QWaylandTextInputv3(
+ this, mGlobals.textInputManagerv3->get_text_input(inputDevice->wl_seat())));
- mTextInputManagerv4.reset(new QtWayland::zwp_text_input_manager_v4(registry, id, 1));
- for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
- inputDevice->setTextInput(new QWaylandTextInputv4(this, mTextInputManagerv4->get_text_input(inputDevice->wl_seat())));
mWaylandIntegration->reconfigureInputContext();
mTextInputManagerIndex = mTextInputManagerList.indexOf(interface);
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
- } else if (interface == QLatin1String(QWaylandHardwareIntegration::interface()->name)) {
+ }else if (interface == QLatin1String(QWaylandHardwareIntegration::interface()->name)) {
bool disableHardwareIntegration = qEnvironmentVariableIntValue("QT_WAYLAND_DISABLE_HW_INTEGRATION");
if (!disableHardwareIntegration) {
- mHardwareIntegration.reset(new QWaylandHardwareIntegration(registry, id));
+ mGlobals.hardwareIntegration.reset(new QWaylandHardwareIntegration(registry, id));
// make a roundtrip here since we need to receive the events sent by
// qt_hardware_integration before creating windows
forceRoundTrip();
}
} else if (interface == QLatin1String(QWaylandXdgOutputManagerV1::interface()->name)) {
- mXdgOutputManager.reset(new QWaylandXdgOutputManagerV1(this, id, version));
- for (auto *screen : qAsConst(mWaitingScreens))
+ mGlobals.xdgOutputManager.reset(new QWaylandXdgOutputManagerV1(this, id, version));
+ for (auto *screen : std::as_const(mWaitingScreens))
screen->initXdgOutput(xdgOutputManager());
- forceRoundTrip();
+ } else if (interface == QLatin1String(QtWayland::wp_fractional_scale_manager_v1::interface()->name)) {
+ mGlobals.fractionalScaleManager.reset(
+ new WithDestructor<QtWayland::wp_fractional_scale_manager_v1,
+ wp_fractional_scale_manager_v1_destroy>(registry, id, 1));
+ } else if (interface == QLatin1String("wp_viewporter")) {
+ mGlobals.viewporter.reset(
+ new WithDestructor<QtWayland::wp_viewporter, wp_viewporter_destroy>(
+ registry, id, qMin(1u, version)));
+ } else if (interface == QLatin1String(QtWayland::wp_cursor_shape_manager_v1::interface()->name)) {
+ mGlobals.cursorShapeManager.reset(new WithDestructor<QtWayland::wp_cursor_shape_manager_v1,
+ wp_cursor_shape_manager_v1_destroy>(
+ registry, id, std::min(1u, version)));
+ } else if (
+ interface == QLatin1String(QtWayland::xdg_toplevel_drag_manager_v1::interface()->name)) {
+ mGlobals.xdgToplevelDragManager.reset(
+ new WithDestructor<QtWayland::xdg_toplevel_drag_manager_v1,
+ xdg_toplevel_drag_manager_v1_destroy>(registry, id, 1));
}
- mGlobals.append(RegistryGlobal(id, interface, version, registry));
- emit globalAdded(mGlobals.back());
+ mRegistryGlobals.append(RegistryGlobal(id, interface, version, registry));
+ emit globalAdded(mRegistryGlobals.back());
const auto copy = mRegistryListeners; // be prepared for listeners unregistering on notification
for (Listener l : copy)
@@ -610,8 +793,8 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
void QWaylandDisplay::registry_global_remove(uint32_t id)
{
- for (int i = 0, ie = mGlobals.count(); i != ie; ++i) {
- RegistryGlobal &global = mGlobals[i];
+ for (int i = 0, ie = mRegistryGlobals.size(); i != ie; ++i) {
+ RegistryGlobal &global = mRegistryGlobals[i];
if (global.id == id) {
if (global.interface == QLatin1String(QtWayland::wl_output::interface()->name)) {
for (auto *screen : mWaitingScreens) {
@@ -622,7 +805,7 @@ void QWaylandDisplay::registry_global_remove(uint32_t id)
}
}
- for (QWaylandScreen *screen : qAsConst(mScreens)) {
+ for (QWaylandScreen *screen : std::as_const(mScreens)) {
if (screen->outputId() == id) {
mScreens.removeOne(screen);
// If this is the last screen, we have to add a fake screen, or Qt will break.
@@ -633,32 +816,37 @@ void QWaylandDisplay::registry_global_remove(uint32_t id)
}
}
if (global.interface == QLatin1String(QtWayland::zwp_text_input_manager_v1::interface()->name)) {
- mTextInputManagerv1.reset();
- for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
+ mGlobals.textInputManagerv1.reset();
+ for (QWaylandInputDevice *inputDevice : std::as_const(mInputDevices))
inputDevice->setTextInput(nullptr);
mWaylandIntegration->reconfigureInputContext();
}
if (global.interface == QLatin1String(QtWayland::zwp_text_input_manager_v2::interface()->name)) {
- mTextInputManagerv2.reset();
- for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
+ mGlobals.textInputManagerv2.reset();
+ for (QWaylandInputDevice *inputDevice : std::as_const(mInputDevices))
inputDevice->setTextInput(nullptr);
mWaylandIntegration->reconfigureInputContext();
}
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- if (global.interface == QLatin1String(QtWayland::zwp_text_input_manager_v4::interface()->name)) {
- mTextInputManagerv4.reset();
- for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
+ if (global.interface == QLatin1String(QtWayland::zwp_text_input_manager_v3::interface()->name)) {
+ mGlobals.textInputManagerv3.reset();
+ for (QWaylandInputDevice *inputDevice : std::as_const(mInputDevices))
inputDevice->setTextInput(nullptr);
mWaylandIntegration->reconfigureInputContext();
}
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
if (global.interface == QLatin1String(QtWayland::qt_text_input_method_manager_v1::interface()->name)) {
- mTextInputMethodManager.reset();
- for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
+ mGlobals.textInputMethodManager.reset();
+ for (QWaylandInputDevice *inputDevice : std::as_const(mInputDevices))
inputDevice->setTextInputMethod(nullptr);
mWaylandIntegration->reconfigureInputContext();
}
- emit globalRemoved(mGlobals.takeAt(i));
+#if QT_CONFIG(wayland_client_primary_selection)
+ if (global.interface == QLatin1String(QtWayland::zwp_primary_selection_device_manager_v1::interface()->name)) {
+ mGlobals.primarySelectionManager.reset();
+ for (QWaylandInputDevice *inputDevice : std::as_const(mInputDevices))
+ inputDevice->setPrimarySelectionDevice(nullptr);
+ }
+#endif
+ emit globalRemoved(mRegistryGlobals.takeAt(i));
break;
}
}
@@ -666,7 +854,7 @@ void QWaylandDisplay::registry_global_remove(uint32_t id)
bool QWaylandDisplay::hasRegistryGlobal(QStringView interfaceName) const
{
- for (const RegistryGlobal &global : mGlobals)
+ for (const RegistryGlobal &global : mRegistryGlobals)
if (global.interface == interfaceName)
return true;
@@ -677,8 +865,9 @@ void QWaylandDisplay::addRegistryListener(RegistryListener listener, void *data)
{
Listener l = { listener, data };
mRegistryListeners.append(l);
- for (int i = 0, ie = mGlobals.count(); i != ie; ++i)
- (*l.listener)(l.data, mGlobals[i].registry, mGlobals[i].id, mGlobals[i].interface, mGlobals[i].version);
+ for (int i = 0, ie = mRegistryGlobals.size(); i != ie; ++i)
+ (*l.listener)(l.data, mRegistryGlobals[i].registry, mRegistryGlobals[i].id,
+ mRegistryGlobals[i].interface, mRegistryGlobals[i].version);
}
void QWaylandDisplay::removeListener(RegistryListener listener, void *data)
@@ -689,16 +878,6 @@ void QWaylandDisplay::removeListener(RegistryListener listener, void *data)
mRegistryListeners.erase(iter, mRegistryListeners.end());
}
-uint32_t QWaylandDisplay::currentTimeMillisec()
-{
- //### we throw away the time information
- struct timeval tv;
- int ret = gettimeofday(&tv, nullptr);
- if (ret == 0)
- return tv.tv_sec*1000 + tv.tv_usec/1000;
- return 0;
-}
-
void QWaylandDisplay::forceRoundTrip()
{
wl_display_roundtrip(mDisplay);
@@ -754,6 +933,9 @@ void QWaylandDisplay::handleWindowDeactivated(QWaylandWindow *window)
mActiveWindows.removeOne(window);
+ if (QCoreApplication::closingDown())
+ return;
+
if (auto *decoration = window->decoration())
decoration->update();
}
@@ -786,7 +968,7 @@ void QWaylandDisplay::handleWaylandSync()
// handleWindowActivated() calls immediately.
QWindow *activeWindow = mActiveWindows.empty() ? nullptr : mActiveWindows.last()->window();
if (activeWindow != QGuiApplication::focusWindow())
- QWindowSystemInterface::handleWindowActivated(activeWindow);
+ QWindowSystemInterface::handleFocusWindowChanged(activeWindow);
if (!activeWindow) {
if (lastInputDevice()) {
@@ -823,7 +1005,7 @@ void QWaylandDisplay::requestWaylandSync()
QWaylandInputDevice *QWaylandDisplay::defaultInputDevice() const
{
- return mInputDevices.isEmpty() ? 0 : mInputDevices.first();
+ return mInputDevices.isEmpty() ? nullptr : mInputDevices.first();
}
bool QWaylandDisplay::isKeyboardAvailable() const
@@ -833,6 +1015,10 @@ bool QWaylandDisplay::isKeyboardAvailable() const
[](const QWaylandInputDevice *device) { return device->keyboard() != nullptr; });
}
+bool QWaylandDisplay::isWaylandInputContextRequested() const {
+ return mWaylandInputContextRequested;
+}
+
#if QT_CONFIG(cursor)
QWaylandCursor *QWaylandDisplay::waylandCursor()
@@ -874,8 +1060,7 @@ QWaylandCursorTheme *QWaylandDisplay::loadCursorTheme(const QString &name, int p
} // namespace QtWaylandClient
-#include "qwaylanddisplay.moc"
-
QT_END_NAMESPACE
+#include "qwaylanddisplay.moc"
#include "moc_qwaylanddisplay_p.cpp"
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
index 3809de1ea..5b564c8d7 100644
--- a/src/client/qwaylanddisplay_p.h
+++ b/src/client/qwaylanddisplay_p.h
@@ -36,9 +36,12 @@
#endif
struct wl_cursor_image;
+struct wp_viewport;
QT_BEGIN_NAMESPACE
+#define WAYLAND_IM_KEY "wayland"
+
class QAbstractEventDispatcher;
class QSocketNotifier;
class QPlatformScreen;
@@ -48,8 +51,12 @@ namespace QtWayland {
class qt_surface_extension;
class zwp_text_input_manager_v1;
class zwp_text_input_manager_v2;
- class zwp_text_input_manager_v4;
+ class zwp_text_input_manager_v3;
class qt_text_input_method_manager_v1;
+ class wp_cursor_shape_manager_v1;
+ class wp_fractional_scale_manager_v1;
+ class wp_viewporter;
+ class xdg_toplevel_drag_manager_v1;
}
namespace QtWaylandClient {
@@ -94,7 +101,7 @@ public:
QWaylandDisplay(QWaylandIntegration *waylandIntegration);
~QWaylandDisplay(void) override;
- void initialize();
+ bool initialize();
#if QT_CONFIG(xkbcommon)
struct xkb_context *xkbContext() const { return mXkbContext.get(); }
@@ -110,6 +117,7 @@ public:
struct wl_surface *createSurface(void *handle);
struct ::wl_region *createRegion(const QRegion &qregion);
struct ::wl_subsurface *createSubSurface(QWaylandWindow *window, QWaylandWindow *parent);
+ struct ::wp_viewport *createViewport(QWaylandWindow *window);
QWaylandShellIntegration *shellIntegration() const;
QWaylandClientBufferIntegration *clientBufferIntegration() const;
@@ -119,33 +127,91 @@ public:
QWaylandCursor *waylandCursor();
QWaylandCursorTheme *loadCursorTheme(const QString &name, int pixelSize);
#endif
- struct wl_display *wl_display() const { return mDisplay; }
+ struct wl_display *wl_display() const
+ {
+ return mDisplay;
+ }
struct ::wl_registry *wl_registry() { return object(); }
- const struct wl_compositor *wl_compositor() const { return mCompositor.object(); }
- QtWayland::wl_compositor *compositor() { return &mCompositor; }
+ QtWayland::wl_compositor *compositor()
+ {
+ return mGlobals.compositor.get();
+ }
QList<QWaylandInputDevice *> inputDevices() const { return mInputDevices; }
QWaylandInputDevice *defaultInputDevice() const;
QWaylandInputDevice *currentInputDevice() const { return defaultInputDevice(); }
#if QT_CONFIG(wayland_datadevice)
- QWaylandDataDeviceManager *dndSelectionHandler() const { return mDndSelectionHandler.get(); }
+ QWaylandDataDeviceManager *dndSelectionHandler() const
+ {
+ return mGlobals.dndSelectionHandler.get();
+ }
#endif
#if QT_CONFIG(wayland_client_primary_selection)
- QWaylandPrimarySelectionDeviceManagerV1 *primarySelectionManager() const { return mPrimarySelectionManager.data(); }
+ QWaylandPrimarySelectionDeviceManagerV1 *primarySelectionManager() const
+ {
+ return mGlobals.primarySelectionManager.get();
+ }
#endif
- QtWayland::qt_surface_extension *windowExtension() const { return mWindowExtension.data(); }
+ QtWayland::qt_surface_extension *windowExtension() const
+ {
+ return mGlobals.surfaceExtension.get();
+ }
#if QT_CONFIG(tabletevent)
- QWaylandTabletManagerV2 *tabletManager() const { return mTabletManager.data(); }
+ QWaylandTabletManagerV2 *tabletManager() const
+ {
+ return mGlobals.tabletManager.get();
+ }
#endif
- QWaylandPointerGestures *pointerGestures() const { return mPointerGestures.data(); }
- QWaylandTouchExtension *touchExtension() const { return mTouchExtension.data(); }
- QtWayland::qt_text_input_method_manager_v1 *textInputMethodManager() const { return mTextInputMethodManager.data(); }
- QtWayland::zwp_text_input_manager_v1 *textInputManagerv1() const { return mTextInputManagerv1.data(); }
- QtWayland::zwp_text_input_manager_v2 *textInputManagerv2() const { return mTextInputManagerv2.data(); }
- QtWayland::zwp_text_input_manager_v4 *textInputManagerv4() const { return mTextInputManagerv4.data(); }
- QWaylandHardwareIntegration *hardwareIntegration() const { return mHardwareIntegration.data(); }
- QWaylandXdgOutputManagerV1 *xdgOutputManager() const { return mXdgOutputManager.data(); }
+ QWaylandPointerGestures *pointerGestures() const
+ {
+ return mGlobals.pointerGestures.get();
+ }
+ QWaylandTouchExtension *touchExtension() const
+ {
+ return mGlobals.touchExtension.get();
+ }
+ QtWayland::qt_text_input_method_manager_v1 *textInputMethodManager() const
+ {
+ return mGlobals.textInputMethodManager.get();
+ }
+ QtWayland::zwp_text_input_manager_v1 *textInputManagerv1() const
+ {
+ return mGlobals.textInputManagerv1.get();
+ }
+ QtWayland::zwp_text_input_manager_v2 *textInputManagerv2() const
+ {
+ return mGlobals.textInputManagerv2.get();
+ }
+ QtWayland::zwp_text_input_manager_v3 *textInputManagerv3() const
+ {
+ return mGlobals.textInputManagerv3.get();
+ }
+ QWaylandHardwareIntegration *hardwareIntegration() const
+ {
+ return mGlobals.hardwareIntegration.get();
+ }
+ QWaylandXdgOutputManagerV1 *xdgOutputManager() const
+ {
+ return mGlobals.xdgOutputManager.get();
+ }
+ QtWayland::wp_fractional_scale_manager_v1 *fractionalScaleManager() const
+ {
+ return mGlobals.fractionalScaleManager.get();
+ }
+ QtWayland::wp_viewporter *viewporter() const
+ {
+ return mGlobals.viewporter.get();
+ }
+ QtWayland::wp_cursor_shape_manager_v1 *cursorShapeManager() const
+ {
+ return mGlobals.cursorShapeManager.get();
+ }
+ QtWayland::xdg_toplevel_drag_manager_v1 *xdgToplevelDragManager() const
+ {
+ return mGlobals.xdgToplevelDragManager.get();
+ }
+
struct RegistryGlobal {
uint32_t id;
@@ -155,7 +221,10 @@ public:
RegistryGlobal(uint32_t id_, const QString &interface_, uint32_t version_, struct ::wl_registry *registry_)
: id(id_), interface(interface_), version(version_), registry(registry_) { }
};
- QList<RegistryGlobal> globals() const { return mGlobals; }
+ QList<RegistryGlobal> globals() const
+ {
+ return mRegistryGlobals;
+ }
bool hasRegistryGlobal(QStringView interfaceName) const;
/* wl_registry_add_listener does not add but rather sets a listener, so this function is used
@@ -163,9 +232,10 @@ public:
void addRegistryListener(RegistryListener listener, void *data);
void removeListener(RegistryListener listener, void *data);
- QWaylandShm *shm() const { return mShm.data(); }
-
- static uint32_t currentTimeMillisec();
+ QWaylandShm *shm() const
+ {
+ return mGlobals.shm.get();
+ }
void forceRoundTrip();
@@ -185,18 +255,23 @@ public:
wl_event_queue *frameEventQueue() { return m_frameEventQueue; };
bool isKeyboardAvailable() const;
+ bool isWaylandInputContextRequested() const;
void initEventThread();
-public slots:
+public Q_SLOTS:
void blockingReadEvents();
void flushRequests();
-signals:
+Q_SIGNALS:
+ void connected();
void globalAdded(const RegistryGlobal &global);
void globalRemoved(const RegistryGlobal &global);
private:
+ void checkWaylandError();
+ void reconnect();
+ void setupConnection();
void handleWaylandSync();
void requestWaylandSync();
@@ -211,13 +286,10 @@ private:
RegistryListener listener = nullptr;
void *data = nullptr;
};
-
struct wl_display *mDisplay = nullptr;
std::unique_ptr<EventThread> m_eventThread;
wl_event_queue *m_frameEventQueue = nullptr;
QScopedPointer<EventThread> m_frameEventQueueThread;
- QtWayland::wl_compositor mCompositor;
- QScopedPointer<QWaylandShm> mShm;
QList<QWaylandScreen *> mWaitingScreens;
QList<QWaylandScreen *> mScreens;
QPlatformPlaceholderScreen *mPlaceholderScreen = nullptr;
@@ -239,34 +311,45 @@ private:
QWaylandCursorTheme *theme() const noexcept
{ return found ? position->theme.get() : nullptr; }
};
- FindExistingCursorThemeResult findExistingCursorTheme(const QString &name, int pixelSize) const noexcept;
-
+ FindExistingCursorThemeResult findExistingCursorTheme(const QString &name,
+ int pixelSize) const noexcept;
QScopedPointer<QWaylandCursor> mCursor;
#endif
+
+ QScopedPointer<QWaylandWindowManagerIntegration> mWindowManagerIntegration;
+
+ struct GlobalHolder
+ {
+ std::unique_ptr<QtWayland::wl_compositor> compositor;
+ std::unique_ptr<QWaylandShm> shm;
#if QT_CONFIG(wayland_datadevice)
- QScopedPointer<QWaylandDataDeviceManager> mDndSelectionHandler;
+ std::unique_ptr<QWaylandDataDeviceManager> dndSelectionHandler;
#endif
- QScopedPointer<QtWayland::qt_surface_extension> mWindowExtension;
- QScopedPointer<QtWayland::wl_subcompositor> mSubCompositor;
- QScopedPointer<QWaylandTouchExtension> mTouchExtension;
- QScopedPointer<QWaylandQtKeyExtension> mQtKeyExtension;
- QScopedPointer<QWaylandWindowManagerIntegration> mWindowManagerIntegration;
+ std::unique_ptr<QtWayland::qt_surface_extension> surfaceExtension;
+ std::unique_ptr<QtWayland::wl_subcompositor> subCompositor;
+ std::unique_ptr<QWaylandTouchExtension> touchExtension;
+ std::unique_ptr<QWaylandQtKeyExtension> qtKeyExtension;
#if QT_CONFIG(tabletevent)
- QScopedPointer<QWaylandTabletManagerV2> mTabletManager;
+ std::unique_ptr<QWaylandTabletManagerV2> tabletManager;
#endif
- QScopedPointer<QWaylandPointerGestures> mPointerGestures;
+ std::unique_ptr<QWaylandPointerGestures> pointerGestures;
#if QT_CONFIG(wayland_client_primary_selection)
- QScopedPointer<QWaylandPrimarySelectionDeviceManagerV1> mPrimarySelectionManager;
+ std::unique_ptr<QWaylandPrimarySelectionDeviceManagerV1> primarySelectionManager;
#endif
- QScopedPointer<QtWayland::qt_text_input_method_manager_v1> mTextInputMethodManager;
- QScopedPointer<QtWayland::zwp_text_input_manager_v1> mTextInputManagerv1;
- QScopedPointer<QtWayland::zwp_text_input_manager_v2> mTextInputManagerv2;
- QScopedPointer<QtWayland::zwp_text_input_manager_v4> mTextInputManagerv4;
- QScopedPointer<QWaylandHardwareIntegration> mHardwareIntegration;
- QScopedPointer<QWaylandXdgOutputManagerV1> mXdgOutputManager;
+ std::unique_ptr<QtWayland::qt_text_input_method_manager_v1> textInputMethodManager;
+ std::unique_ptr<QtWayland::zwp_text_input_manager_v1> textInputManagerv1;
+ std::unique_ptr<QtWayland::zwp_text_input_manager_v2> textInputManagerv2;
+ std::unique_ptr<QtWayland::zwp_text_input_manager_v3> textInputManagerv3;
+ std::unique_ptr<QWaylandHardwareIntegration> hardwareIntegration;
+ std::unique_ptr<QWaylandXdgOutputManagerV1> xdgOutputManager;
+ std::unique_ptr<QtWayland::wp_viewporter> viewporter;
+ std::unique_ptr<QtWayland::wp_fractional_scale_manager_v1> fractionalScaleManager;
+ std::unique_ptr<QtWayland::wp_cursor_shape_manager_v1> cursorShapeManager;
+ std::unique_ptr<QtWayland::xdg_toplevel_drag_manager_v1> xdgToplevelDragManager;
+ } mGlobals;
int mFd = -1;
int mWritableNotificationFd = -1;
- QList<RegistryGlobal> mGlobals;
+ QList<RegistryGlobal> mRegistryGlobals;
uint32_t mLastInputSerial = 0;
QWaylandInputDevice *mLastInputDevice = nullptr;
QPointer<QWaylandWindow> mLastInputWindow;
@@ -274,8 +357,12 @@ private:
QList<QWaylandWindow *> mActiveWindows;
struct wl_callback *mSyncCallback = nullptr;
static const wl_callback_listener syncCallbackListener;
+ bool mWaylandTryReconnect = false;
- bool mClientSideInputContextRequested = !QPlatformInputContextFactory::requested().isNull();
+ bool mWaylandInputContextRequested = [] () {
+ const auto requested = QPlatformInputContextFactory::requested();
+ return requested.isEmpty() || requested.contains(QLatin1String(WAYLAND_IM_KEY));
+ }();
QStringList mTextInputManagerList;
int mTextInputManagerIndex = INT_MAX;
diff --git a/src/client/qwaylanddnd.cpp b/src/client/qwaylanddnd.cpp
index ff89069fc..5ea1e0d33 100644
--- a/src/client/qwaylanddnd.cpp
+++ b/src/client/qwaylanddnd.cpp
@@ -59,10 +59,7 @@ void QWaylandDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::Keyboar
void QWaylandDrag::drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
{
- Q_UNUSED(globalPos);
- Q_UNUSED(b);
- Q_UNUSED(mods);
- // Do nothing
+ QBasicDrag::drop(globalPos, b, mods);
}
void QWaylandDrag::endDrag()
diff --git a/src/client/qwaylandfractionalscale.cpp b/src/client/qwaylandfractionalscale.cpp
new file mode 100644
index 000000000..6cd933f47
--- /dev/null
+++ b/src/client/qwaylandfractionalscale.cpp
@@ -0,0 +1,31 @@
+// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwaylandfractionalscale_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+QWaylandFractionalScale::QWaylandFractionalScale(struct ::wp_fractional_scale_v1 *object)
+ : QtWayland::wp_fractional_scale_v1(object)
+{}
+
+
+QWaylandFractionalScale::~QWaylandFractionalScale()
+{
+ destroy();
+}
+
+void QWaylandFractionalScale::wp_fractional_scale_v1_preferred_scale(uint scale)
+{
+ qreal preferredScale = scale / 120.0; // hardcoded denominator determined in the spec
+ if (preferredScale != mPreferredScale) {
+ mPreferredScale = preferredScale;
+ Q_EMIT preferredScaleChanged();
+ }
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/client/qwaylandfractionalscale_p.h b/src/client/qwaylandfractionalscale_p.h
new file mode 100644
index 000000000..48e1fb487
--- /dev/null
+++ b/src/client/qwaylandfractionalscale_p.h
@@ -0,0 +1,52 @@
+// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWAYLANDFRACTIONALSCALE_P_H
+#define QWAYLANDFRACTIONALSCALE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtWaylandClient/private/qwayland-fractional-scale-v1.h>
+#include <QtWaylandClient/qtwaylandclientglobal.h>
+
+#include <QObject>
+
+#include <optional>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+class QWaylandFractionalScale : public QObject, public QtWayland::wp_fractional_scale_v1
+{
+ Q_OBJECT
+public:
+ explicit QWaylandFractionalScale(struct ::wp_fractional_scale_v1 *object);
+ ~QWaylandFractionalScale();
+
+ std::optional<qreal> preferredScale() const { return mPreferredScale; }
+
+Q_SIGNALS:
+ void preferredScaleChanged();
+
+protected:
+ void wp_fractional_scale_v1_preferred_scale(uint scale) override;
+
+private:
+ std::optional<qreal> mPreferredScale;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/client/qwaylandinputcontext.cpp b/src/client/qwaylandinputcontext.cpp
index cb94005b3..a38bb9a0a 100644
--- a/src/client/qwaylandinputcontext.cpp
+++ b/src/client/qwaylandinputcontext.cpp
@@ -35,11 +35,7 @@ QWaylandInputContext::~QWaylandInputContext()
bool QWaylandInputContext::isValid() const
{
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- return mDisplay->textInputManagerv2() != nullptr || mDisplay->textInputManagerv1() != nullptr || mDisplay->textInputManagerv4() != nullptr;
-#else // QT_WAYLAND_TEXT_INPUT_V4_WIP
- return mDisplay->textInputManagerv2() != nullptr || mDisplay->textInputManagerv1() != nullptr;
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
+ return mDisplay->textInputManagerv2() != nullptr || mDisplay->textInputManagerv1() != nullptr || mDisplay->textInputManagerv3() != nullptr;
}
void QWaylandInputContext::reset()
@@ -52,20 +48,22 @@ void QWaylandInputContext::reset()
QPlatformInputContext::reset();
- if (!textInput())
+ QWaylandTextInputInterface *inputInterface = textInput();
+ if (!inputInterface)
return;
- textInput()->reset();
+ inputInterface->reset();
}
void QWaylandInputContext::commit()
{
qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO;
- if (!textInput())
+ QWaylandTextInputInterface *inputInterface = textInput();
+ if (!inputInterface)
return;
- textInput()->commit();
+ inputInterface->commit();
}
static ::wl_surface *surfaceForWindow(QWindow *window)
@@ -81,92 +79,100 @@ void QWaylandInputContext::update(Qt::InputMethodQueries queries)
{
qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO << queries;
- if (!QGuiApplication::focusObject() || !textInput())
+ QWaylandTextInputInterface *inputInterface = textInput();
+ if (!QGuiApplication::focusObject() || !inputInterface)
return;
auto *currentSurface = surfaceForWindow(mCurrentWindow);
if (currentSurface && !inputMethodAccepted()) {
- textInput()->disableSurface(currentSurface);
+ inputInterface->disableSurface(currentSurface);
mCurrentWindow.clear();
} else if (!currentSurface && inputMethodAccepted()) {
QWindow *window = QGuiApplication::focusWindow();
if (auto *focusSurface = surfaceForWindow(window)) {
- textInput()->enableSurface(focusSurface);
+ inputInterface->enableSurface(focusSurface);
mCurrentWindow = window;
}
}
- textInput()->updateState(queries, QWaylandTextInputInterface::update_state_change);
+ inputInterface->updateState(queries, QWaylandTextInputInterface::update_state_change);
}
void QWaylandInputContext::invokeAction(QInputMethod::Action action, int cursorPostion)
{
- if (!textInput())
+ QWaylandTextInputInterface *inputInterface = textInput();
+ if (!inputInterface)
return;
if (action == QInputMethod::Click)
- textInput()->setCursorInsidePreedit(cursorPostion);
+ inputInterface->setCursorInsidePreedit(cursorPostion);
}
void QWaylandInputContext::showInputPanel()
{
qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO;
- if (!textInput())
+ QWaylandTextInputInterface *inputInterface = textInput();
+ if (!inputInterface)
return;
- textInput()->showInputPanel();
+ inputInterface->showInputPanel();
}
void QWaylandInputContext::hideInputPanel()
{
qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO;
- if (!textInput())
+ QWaylandTextInputInterface *inputInterface = textInput();
+ if (!inputInterface)
return;
- textInput()->hideInputPanel();
+ inputInterface->hideInputPanel();
}
bool QWaylandInputContext::isInputPanelVisible() const
{
qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO;
- if (!textInput())
+ QWaylandTextInputInterface *inputInterface = textInput();
+ if (!inputInterface)
return QPlatformInputContext::isInputPanelVisible();
- return textInput()->isInputPanelVisible();
+ return inputInterface->isInputPanelVisible();
}
QRectF QWaylandInputContext::keyboardRect() const
{
qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO;
- if (!textInput())
+ QWaylandTextInputInterface *inputInterface = textInput();
+ if (!inputInterface)
return QPlatformInputContext::keyboardRect();
- return textInput()->keyboardRect();
+ return inputInterface->keyboardRect();
}
QLocale QWaylandInputContext::locale() const
{
qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO;
- if (!textInput())
+ QWaylandTextInputInterface *inputInterface = textInput();
+ if (!inputInterface)
return QPlatformInputContext::locale();
- return textInput()->locale();
+ return inputInterface->locale();
}
Qt::LayoutDirection QWaylandInputContext::inputDirection() const
{
qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO;
- if (!textInput())
+ QWaylandTextInputInterface *inputInterface = textInput();
+ if (!inputInterface)
return QPlatformInputContext::inputDirection();
- return textInput()->inputDirection();
+ return inputInterface->inputDirection();
}
void QWaylandInputContext::setFocusObject(QObject *object)
@@ -178,7 +184,8 @@ void QWaylandInputContext::setFocusObject(QObject *object)
Q_UNUSED(object);
#endif
- if (!textInput())
+ QWaylandTextInputInterface *inputInterface = textInput();
+ if (!inputInterface)
return;
QWindow *window = QGuiApplication::focusWindow();
@@ -187,7 +194,7 @@ void QWaylandInputContext::setFocusObject(QObject *object)
if (mCurrentWindow.data() != window || !inputMethodAccepted()) {
auto *surface = static_cast<QWaylandWindow *>(mCurrentWindow->handle())->wlSurface();
if (surface)
- textInput()->disableSurface(surface);
+ inputInterface->disableSurface(surface);
mCurrentWindow.clear();
}
}
@@ -196,17 +203,17 @@ void QWaylandInputContext::setFocusObject(QObject *object)
if (mCurrentWindow.data() != window) {
auto *surface = static_cast<QWaylandWindow *>(window->handle())->wlSurface();
if (surface) {
- textInput()->enableSurface(surface);
+ inputInterface->enableSurface(surface);
mCurrentWindow = window;
}
}
- textInput()->updateState(Qt::ImQueryAll, QWaylandTextInputInterface::update_state_enter);
+ inputInterface->updateState(Qt::ImQueryAll, QWaylandTextInputInterface::update_state_enter);
}
}
QWaylandTextInputInterface *QWaylandInputContext::textInput() const
{
- return mDisplay->defaultInputDevice()->textInput();
+ return mDisplay->defaultInputDevice() ? mDisplay->defaultInputDevice()->textInput() : nullptr;
}
#if QT_CONFIG(xkbcommon)
@@ -222,9 +229,7 @@ void QWaylandInputContext::ensureInitialized()
}
m_initialized = true;
- const char *locale = setlocale(LC_CTYPE, "");
- if (!locale)
- locale = setlocale(LC_CTYPE, nullptr);
+ const char *const locale = setlocale(LC_CTYPE, nullptr);
qCDebug(qLcQpaInputMethods) << "detected locale (LC_CTYPE):" << locale;
m_composeTable = xkb_compose_table_new_from_locale(m_XkbContext, locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
@@ -288,8 +293,7 @@ bool QWaylandInputContext::filterEvent(const QEvent *event)
case XKB_COMPOSE_NOTHING:
return false;
default:
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
}
diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp
index c531699a6..1df7ac483 100644
--- a/src/client/qwaylandinputdevice.cpp
+++ b/src/client/qwaylandinputdevice.cpp
@@ -4,6 +4,7 @@
#include "qwaylandinputdevice_p.h"
#include "qwaylandintegration_p.h"
+#include "qwaylandtextinputv3_p.h"
#include "qwaylandwindow_p.h"
#include "qwaylandsurface_p.h"
#include "qwaylandbuffer_p.h"
@@ -25,9 +26,6 @@
#include "qwaylandshmbackingstore_p.h"
#include "qwaylandtextinputv1_p.h"
#include "qwaylandtextinputv2_p.h"
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
-#include "qwaylandtextinputv4_p.h"
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
#include "qwaylandtextinputinterface_p.h"
#include "qwaylandinputcontext_p.h"
#include "qwaylandinputmethodcontext_p.h"
@@ -36,6 +34,7 @@
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformwindow.h>
#include <qpa/qplatforminputcontext.h>
+#include <qpa/qplatformtheme.h>
#include <QDebug>
#include <unistd.h>
@@ -62,18 +61,20 @@ static const int MaxTouchPoints = 10;
QWaylandInputDevice::Keyboard::Keyboard(QWaylandInputDevice *p)
: mParent(p)
{
- mRepeatTimer.callOnTimeout([&]() {
+ init(p->get_keyboard());
+ mRepeatTimer.callOnTimeout(this, [&]() {
if (!focusWindow()) {
// We destroyed the keyboard focus surface, but the server didn't get the message yet...
// or the server didn't send an enter event first.
return;
}
mRepeatTimer.setInterval(1000 / mRepeatRate);
- handleKey(mRepeatKey.time, QEvent::KeyRelease, mRepeatKey.key, mRepeatKey.modifiers,
- mRepeatKey.code, mRepeatKey.nativeVirtualKey, mRepeatKey.nativeModifiers,
+ Qt::KeyboardModifiers modifiers = this->modifiers();
+ handleKey(mRepeatKey.time, QEvent::KeyRelease, mRepeatKey.key, modifiers,
+ mRepeatKey.code, mRepeatKey.nativeVirtualKey, this->mNativeModifiers,
mRepeatKey.text, true);
- handleKey(mRepeatKey.time, QEvent::KeyPress, mRepeatKey.key, mRepeatKey.modifiers,
- mRepeatKey.code, mRepeatKey.nativeVirtualKey, mRepeatKey.nativeModifiers,
+ handleKey(mRepeatKey.time, QEvent::KeyPress, mRepeatKey.key, modifiers,
+ mRepeatKey.code, mRepeatKey.nativeVirtualKey, this->mNativeModifiers,
mRepeatKey.text, true);
});
}
@@ -108,7 +109,7 @@ bool QWaylandInputDevice::Keyboard::createDefaultKeymap()
QWaylandInputDevice::Keyboard::~Keyboard()
{
if (mFocus)
- QWindowSystemInterface::handleWindowActivated(nullptr);
+ QWindowSystemInterface::handleFocusWindowChanged(nullptr);
if (version() >= 3)
wl_keyboard_release(object());
else
@@ -117,15 +118,20 @@ QWaylandInputDevice::Keyboard::~Keyboard()
QWaylandWindow *QWaylandInputDevice::Keyboard::focusWindow() const
{
- return mFocus ? QWaylandWindow::fromWlSurface(mFocus) : nullptr;
+ return mFocus ? mFocus->waylandWindow() : nullptr;
}
QWaylandInputDevice::Pointer::Pointer(QWaylandInputDevice *seat)
: mParent(seat)
{
+ init(seat->get_pointer());
#if QT_CONFIG(cursor)
+ if (auto cursorShapeManager = seat->mQDisplay->cursorShapeManager()) {
+ mCursor.shape.reset(new QWaylandCursorShape(cursorShapeManager->get_pointer(object())));
+ }
+
mCursor.frameTimer.setSingleShot(true);
- mCursor.frameTimer.callOnTimeout([&]() {
+ mCursor.frameTimer.callOnTimeout(this, [&]() {
cursorTimerCallback();
});
#endif
@@ -148,23 +154,16 @@ QWaylandWindow *QWaylandInputDevice::Pointer::focusWindow() const
class WlCallback : public QtWayland::wl_callback {
public:
- explicit WlCallback(::wl_callback *callback, std::function<void(uint32_t)> fn, bool autoDelete = false)
+ explicit WlCallback(::wl_callback *callback, std::function<void(uint32_t)> fn)
: QtWayland::wl_callback(callback)
, m_fn(fn)
- , m_autoDelete(autoDelete)
{}
~WlCallback() override { wl_callback_destroy(object()); }
- bool done() const { return m_done; }
void callback_done(uint32_t callback_data) override {
- m_done = true;
m_fn(callback_data);
- if (m_autoDelete)
- delete this;
}
private:
- bool m_done = false;
std::function<void(uint32_t)> m_fn;
- bool m_autoDelete = false;
};
class CursorSurface : public QWaylandSurface
@@ -178,12 +177,10 @@ public:
m_pointer, &QWaylandInputDevice::Pointer::updateCursor);
}
- void hide()
+ void reset()
{
- uint serial = m_pointer->mEnterSerial;
- Q_ASSERT(serial);
- m_pointer->set_cursor(serial, nullptr, 0, 0);
m_setSerial = 0;
+ m_hotspot = QPoint();
}
// Size and hotspot are in surface coordinates
@@ -229,19 +226,6 @@ private:
QPoint m_hotspot;
};
-QString QWaylandInputDevice::Pointer::cursorThemeName() const
-{
- static QString themeName = qEnvironmentVariable("XCURSOR_THEME", QStringLiteral("default"));
- return themeName;
-}
-
-int QWaylandInputDevice::Pointer::cursorSize() const
-{
- constexpr int defaultCursorSize = 32;
- static const int xCursorSize = qEnvironmentVariableIntValue("XCURSOR_SIZE");
- return xCursorSize > 0 ? xCursorSize : defaultCursorSize;
-}
-
int QWaylandInputDevice::Pointer::idealCursorScale() const
{
if (seat()->mQDisplay->compositor()->version() < 3) {
@@ -258,17 +242,30 @@ int QWaylandInputDevice::Pointer::idealCursorScale() const
void QWaylandInputDevice::Pointer::updateCursorTheme()
{
+ QString cursorThemeName;
+ QSize cursorSize;
+
+ if (const QPlatformTheme *platformTheme = QGuiApplicationPrivate::platformTheme()) {
+ cursorThemeName = platformTheme->themeHint(QPlatformTheme::MouseCursorTheme).toString();
+ cursorSize = platformTheme->themeHint(QPlatformTheme::MouseCursorSize).toSize();
+ }
+
+ if (cursorThemeName.isEmpty())
+ cursorThemeName = QStringLiteral("default");
+ if (cursorSize.isEmpty())
+ cursorSize = QSize(24, 24);
+
int scale = idealCursorScale();
- int pixelSize = cursorSize() * scale;
+ int pixelSize = cursorSize.width() * scale;
auto *display = seat()->mQDisplay;
- mCursor.theme = display->loadCursorTheme(cursorThemeName(), pixelSize);
+ mCursor.theme = display->loadCursorTheme(cursorThemeName, pixelSize);
if (!mCursor.theme)
return; // A warning has already been printed in loadCursorTheme
if (auto *arrow = mCursor.theme->cursor(Qt::ArrowCursor)) {
int arrowPixelSize = qMax(arrow->images[0]->width, arrow->images[0]->height); // Not all cursor themes are square
- while (scale > 1 && arrowPixelSize / scale < cursorSize())
+ while (scale > 1 && arrowPixelSize / scale < cursorSize.width())
--scale;
} else {
qCWarning(lcQpaWayland) << "Cursor theme does not support the arrow cursor";
@@ -285,7 +282,8 @@ void QWaylandInputDevice::Pointer::updateCursor()
if (shape == Qt::BlankCursor) {
if (mCursor.surface)
- mCursor.surface->hide();
+ mCursor.surface->reset();
+ set_cursor(mEnterSerial, nullptr, 0, 0);
return;
}
@@ -301,6 +299,14 @@ void QWaylandInputDevice::Pointer::updateCursor()
return;
}
+ if (mCursor.shape) {
+ if (mCursor.surface) {
+ mCursor.surface->reset();
+ }
+ mCursor.shape->setShape(mEnterSerial, shape);
+ return;
+ }
+
if (!mCursor.theme || idealCursorScale() != mCursor.themeBufferScale)
updateCursorTheme();
@@ -364,6 +370,7 @@ void QWaylandInputDevice::Pointer::cursorFrameCallback()
QWaylandInputDevice::Touch::Touch(QWaylandInputDevice *p)
: mParent(p)
{
+ init(p->get_touch());
}
QWaylandInputDevice::Touch::~Touch()
@@ -375,7 +382,7 @@ QWaylandInputDevice::Touch::~Touch()
}
QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version, uint32_t id)
- : QtWayland::wl_seat(display->wl_registry(), id, qMin(version, 7))
+ : QtWayland::wl_seat(display->wl_registry(), id, qMin(version, 9))
, mQDisplay(display)
, mDisplay(display->wl_display())
{
@@ -400,10 +407,8 @@ QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version,
if (mQDisplay->textInputManagerv2())
mTextInput.reset(new QWaylandTextInputv2(mQDisplay, mQDisplay->textInputManagerv2()->get_text_input(wl_seat())));
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- if (mQDisplay->textInputManagerv4())
- mTextInput.reset(new QWaylandTextInputv4(mQDisplay, mQDisplay->textInputManagerv4()->get_text_input(wl_seat())));
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
+ if (mQDisplay->textInputManagerv3())
+ mTextInput.reset(new QWaylandTextInputv3(mQDisplay, mQDisplay->textInputManagerv3()->get_text_input(wl_seat())));
if (mQDisplay->textInputMethodManager())
mTextInputMethod.reset(new QWaylandTextInputMethod(mQDisplay, mQDisplay->textInputMethodManager()->get_text_input_method(wl_seat())));
@@ -414,8 +419,13 @@ QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version,
#endif
}
-// Can't be in header because dtors for scoped pointers aren't known there.
-QWaylandInputDevice::~QWaylandInputDevice() = default;
+QWaylandInputDevice::~QWaylandInputDevice()
+{
+ if (version() >= WL_SEAT_RELEASE_SINCE_VERSION)
+ release();
+ else
+ wl_seat_destroy(object());
+}
void QWaylandInputDevice::seat_capabilities(uint32_t caps)
{
@@ -423,14 +433,12 @@ void QWaylandInputDevice::seat_capabilities(uint32_t caps)
if (caps & WL_SEAT_CAPABILITY_KEYBOARD && !mKeyboard) {
mKeyboard.reset(createKeyboard(this));
- mKeyboard->init(get_keyboard());
} else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && mKeyboard) {
mKeyboard.reset();
}
if (caps & WL_SEAT_CAPABILITY_POINTER && !mPointer) {
mPointer.reset(createPointer(this));
- mPointer->init(get_pointer());
auto *pointerGestures = mQDisplay->pointerGestures();
if (pointerGestures) {
@@ -441,9 +449,9 @@ void QWaylandInputDevice::seat_capabilities(uint32_t caps)
MaxTouchPoints, 0, QString(), QPointingDeviceUniqueId(), this);
QWindowSystemInterface::registerInputDevice(mTouchPadDevice);
mPointerGesturePinch.reset(pointerGestures->createPointerGesturePinch(this));
- mPointerGesturePinch->init(pointerGestures->get_pinch_gesture(get_pointer()));
+ mPointerGesturePinch->init(pointerGestures->get_pinch_gesture(mPointer->object()));
mPointerGestureSwipe.reset(pointerGestures->createPointerGestureSwipe(this));
- mPointerGestureSwipe->init(pointerGestures->get_swipe_gesture(get_pointer()));
+ mPointerGestureSwipe->init(pointerGestures->get_swipe_gesture(mPointer->object()));
}
} else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && mPointer) {
mPointer.reset();
@@ -453,7 +461,6 @@ void QWaylandInputDevice::seat_capabilities(uint32_t caps)
if (caps & WL_SEAT_CAPABILITY_TOUCH && !mTouch) {
mTouch.reset(createTouch(this));
- mTouch->init(get_touch());
if (!mTouchDevice) {
// TODO number of touchpoints, actual name and ID
@@ -468,6 +475,11 @@ void QWaylandInputDevice::seat_capabilities(uint32_t caps)
}
}
+void QWaylandInputDevice::seat_name(const QString &name)
+{
+ mSeatName = name;
+}
+
QWaylandInputDevice::Keyboard *QWaylandInputDevice::createKeyboard(QWaylandInputDevice *device)
{
return new Keyboard(device);
@@ -823,6 +835,8 @@ void QWaylandInputDevice::Pointer::pointer_button(uint32_t serial, uint32_t time
default: return; // invalid button number (as far as Qt is concerned)
}
+ mLastButton = qt_button;
+
if (state)
mButtons |= qt_button;
else
@@ -861,10 +875,13 @@ void QWaylandInputDevice::Pointer::invalidateFocus()
void QWaylandInputDevice::Pointer::releaseButtons()
{
+ if (mButtons == Qt::NoButton)
+ return;
+
mButtons = Qt::NoButton;
if (auto *window = focusWindow()) {
- MotionEvent e(focusWindow(), mParent->mTime, mSurfacePos, mGlobalPos, mButtons, mParent->modifiers());
+ ReleaseEvent e(focusWindow(), mParent->mTime, mSurfacePos, mGlobalPos, mButtons, mLastButton, mParent->modifiers());
window->handleMouse(mParent, e);
}
}
@@ -874,9 +891,9 @@ class WheelEvent : public QWaylandPointerEvent
public:
WheelEvent(QWaylandWindow *surface, Qt::ScrollPhase phase, ulong timestamp, const QPointF &local,
const QPointF &global, const QPoint &pixelDelta, const QPoint &angleDelta,
- Qt::MouseEventSource source, Qt::KeyboardModifiers modifiers)
+ Qt::MouseEventSource source, Qt::KeyboardModifiers modifiers, bool inverted)
: QWaylandPointerEvent(QEvent::Wheel, phase, surface, timestamp,
- local, global, pixelDelta, angleDelta, source, modifiers)
+ local, global, pixelDelta, angleDelta, source, modifiers, inverted)
{
}
};
@@ -970,8 +987,9 @@ void QWaylandInputDevice::Pointer::pointer_axis_stop(uint32_t time, uint32_t axi
if (!target)
target = focusWindow();
Qt::KeyboardModifiers mods = mParent->modifiers();
+ const bool inverted = mFrameData.verticalAxisInverted || mFrameData.horizontalAxisInverted;
WheelEvent wheelEvent(focusWindow(), Qt::ScrollEnd, mParent->mTime, mSurfacePos, mGlobalPos,
- QPoint(), QPoint(), Qt::MouseEventNotSynthesized, mods);
+ QPoint(), QPoint(), Qt::MouseEventNotSynthesized, mods, inverted);
target->handleMouse(mParent, wheelEvent);
mScrollBeginSent = false;
mScrollDeltaRemainder = QPointF();
@@ -982,14 +1000,16 @@ void QWaylandInputDevice::Pointer::pointer_axis_discrete(uint32_t axis, int32_t
if (!focusWindow())
return;
+ const int32_t delta120 = value * 15 * 8;
+
switch (axis) {
case axis_vertical_scroll:
qCDebug(lcQpaWaylandInput) << "wl_pointer.axis_discrete vertical:" << value;
- mFrameData.discreteDelta.ry() += value;
+ mFrameData.delta120.ry() += delta120;
break;
case axis_horizontal_scroll:
qCDebug(lcQpaWaylandInput) << "wl_pointer.axis_discrete horizontal:" << value;
- mFrameData.discreteDelta.rx() += value;
+ mFrameData.delta120.rx() += delta120;
break;
default:
//TODO: is this really needed?
@@ -998,6 +1018,41 @@ void QWaylandInputDevice::Pointer::pointer_axis_discrete(uint32_t axis, int32_t
}
}
+void QWaylandInputDevice::Pointer::pointer_axis_value120(uint32_t axis, int32_t value)
+{
+ if (!focusWindow())
+ return;
+
+ switch (axis) {
+ case axis_vertical_scroll:
+ qCDebug(lcQpaWaylandInput) << "wl_pointer.axis_value120 vertical:" << value;
+ mFrameData.delta120.ry() += value;
+ break;
+ case axis_horizontal_scroll:
+ qCDebug(lcQpaWaylandInput) << "wl_pointer.axis_value120 horizontal:" << value;
+ mFrameData.delta120.rx() += value;
+ break;
+ default:
+ qCWarning(lcQpaWaylandInput) << "wl_pointer.axis_value120: Unknown axis:" << axis;
+ return;
+ }
+}
+
+void QWaylandInputDevice::Pointer::pointer_axis_relative_direction(uint32_t axis, uint32_t direction)
+{
+ const bool inverted = direction == axis_relative_direction_inverted;
+ switch (axis) {
+ case axis_vertical_scroll:
+ mFrameData.verticalAxisInverted = inverted;
+ break;
+ case axis_horizontal_scroll:
+ mFrameData.horizontalAxisInverted = inverted;
+ break;
+ default:
+ qCWarning(lcQpaWaylandInput) << "wl_pointer.axis_relative_direction: Unknown axis:" << axis;
+ }
+}
+
void QWaylandInputDevice::Pointer::setFrameEvent(QWaylandPointerEvent *event)
{
qCDebug(lcQpaWaylandInput) << "Setting frame event " << event->type;
@@ -1016,9 +1071,11 @@ void QWaylandInputDevice::Pointer::setFrameEvent(QWaylandPointerEvent *event)
void QWaylandInputDevice::Pointer::FrameData::resetScrollData()
{
- discreteDelta = QPoint();
+ delta120 = QPoint();
delta = QPointF();
axisSource = axis_source_wheel;
+ horizontalAxisInverted = false;
+ verticalAxisInverted = false;
}
bool QWaylandInputDevice::Pointer::FrameData::hasPixelDelta() const
@@ -1060,15 +1117,16 @@ QPoint QWaylandInputDevice::Pointer::FrameData::pixelDeltaAndError(QPointF *accu
QPoint QWaylandInputDevice::Pointer::FrameData::angleDelta() const
{
- if (discreteDelta.isNull()) {
+ if (delta120.isNull()) {
// If we didn't get any discrete events, then we need to fall back to
// the continuous information.
return (delta * -12).toPoint(); //TODO: why multiply by 12?
}
// The angle delta is in eights of degrees, and our docs says most mice have
- // 1 click = 15 degrees. It's also in the opposite direction of surface space.
- return -discreteDelta * 15 * 8;
+ // 1 click = 15 degrees, i.e. 120 is one click. It's also in the opposite
+ // direction of surface space.
+ return -delta120;
}
Qt::MouseEventSource QWaylandInputDevice::Pointer::FrameData::wheelEventSource() const
@@ -1099,7 +1157,7 @@ void QWaylandInputDevice::Pointer::flushScrollEvent()
target->handleMouse(mParent, WheelEvent(focusWindow(), Qt::ScrollBegin, mParent->mTime,
mSurfacePos, mGlobalPos, QPoint(), QPoint(),
Qt::MouseEventNotSynthesized,
- mParent->modifiers()));
+ mParent->modifiers(), false));
mScrollBeginSent = true;
mScrollDeltaRemainder = QPointF();
}
@@ -1108,11 +1166,15 @@ void QWaylandInputDevice::Pointer::flushScrollEvent()
QPoint pixelDelta = mFrameData.pixelDeltaAndError(&mScrollDeltaRemainder);
Qt::MouseEventSource source = mFrameData.wheelEventSource();
+
+ // The wayland protocol has separate horizontal and vertical axes, Qt has just the one inverted flag
+ // Pragmatically it should't come up
+ const bool inverted = mFrameData.verticalAxisInverted || mFrameData.horizontalAxisInverted;
+
qCDebug(lcQpaWaylandInput) << "Flushing scroll event" << phase << pixelDelta << angleDelta;
target->handleMouse(mParent, WheelEvent(focusWindow(), phase, mParent->mTime, mSurfacePos, mGlobalPos,
- pixelDelta, angleDelta, source, mParent->modifiers()));
+ pixelDelta, angleDelta, source, mParent->modifiers(), inverted));
}
-
mFrameData.resetScrollData();
}
@@ -1187,13 +1249,17 @@ void QWaylandInputDevice::Keyboard::keyboard_enter(uint32_t time, struct wl_surf
return;
}
+ QWaylandWindow *window = QWaylandWindow::fromWlSurface(surface);
+ if (!window)
+ return;
+
if (mFocus) {
qCWarning(lcQpaWayland()) << "Unexpected wl_keyboard.enter event. Keyboard already has focus";
- disconnect(focusWindow(), &QWaylandWindow::wlSurfaceDestroyed, this, &Keyboard::handleFocusDestroyed);
+ disconnect(mFocus, &QWaylandSurface::destroyed, this, &Keyboard::handleFocusDestroyed);
}
- mFocus = surface;
- connect(focusWindow(), &QWaylandWindow::wlSurfaceDestroyed, this, &Keyboard::handleFocusDestroyed);
+ mFocus = window->waylandSurface();
+ connect(mFocus, &QWaylandSurface::destroyed, this, &Keyboard::handleFocusDestroyed);
mParent->mQDisplay->handleKeyboardFocusChanged(mParent);
}
@@ -1207,13 +1273,17 @@ void QWaylandInputDevice::Keyboard::keyboard_leave(uint32_t time, struct wl_surf
return;
}
- if (surface != mFocus) {
+ QWaylandWindow *window = QWaylandWindow::fromWlSurface(surface);
+ if (!window)
+ return;
+
+ if (window->waylandSurface() != mFocus) {
qCWarning(lcQpaWayland) << "Ignoring unexpected wl_keyboard.leave event."
<< "wl_surface argument does not match the current focus"
<< "This is most likely a compositor bug";
return;
}
- disconnect(focusWindow(), &QWaylandWindow::wlSurfaceDestroyed, this, &Keyboard::handleFocusDestroyed);
+ disconnect(mFocus, &QWaylandSurface::destroyed, this, &Keyboard::handleFocusDestroyed);
handleFocusLost();
}
@@ -1277,8 +1347,7 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time,
auto code = key + 8; // map to wl_keyboard::keymap_format::keymap_format_xkb_v1
xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState.get(), code);
-
- Qt::KeyboardModifiers modifiers = mParent->modifiers();
+ Qt::KeyboardModifiers modifiers = QXkbCommon::modifiers(mXkbState.get(), sym);
int qtkey = keysymToQtKey(sym, modifiers, mXkbState.get(), code);
QString text = QXkbCommon::lookupString(mXkbState.get(), code);
@@ -1291,8 +1360,6 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time,
mRepeatKey.code = code;
mRepeatKey.time = time;
mRepeatKey.text = text;
- mRepeatKey.modifiers = modifiers;
- mRepeatKey.nativeModifiers = mNativeModifiers;
mRepeatKey.nativeVirtualKey = sym;
mRepeatTimer.setInterval(mRepeatDelay);
mRepeatTimer.start();
@@ -1313,11 +1380,6 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time,
void QWaylandInputDevice::Keyboard::handleFocusDestroyed()
{
- // The signal is emitted by QWaylandWindow, which is not necessarily destroyed along with the
- // surface, so we still need to disconnect the signal
- auto *window = qobject_cast<QWaylandWindow *>(sender());
- disconnect(window, &QWaylandWindow::wlSurfaceDestroyed, this, &Keyboard::handleFocusDestroyed);
- Q_ASSERT(window->wlSurface() == mFocus);
handleFocusLost();
}
@@ -1412,6 +1474,7 @@ void QWaylandInputDevice::Touch::touch_cancel()
if (touchExt)
touchExt->touchCanceled();
+ mFocus = nullptr;
QWindowSystemInterface::handleTouchCancelEvent(nullptr, mParent->mTouchDevice);
}
@@ -1464,7 +1527,7 @@ void QWaylandInputDevice::handleTouchPoint(int id, QEventPoint::State state, con
bool QWaylandInputDevice::Touch::allTouchPointsReleased()
{
- for (const auto &tp : qAsConst(mPendingTouchPoints)) {
+ for (const auto &tp : std::as_const(mPendingTouchPoints)) {
if (tp.state != QEventPoint::Released)
return false;
}
@@ -1489,12 +1552,17 @@ void QWaylandInputDevice::Touch::touch_frame()
QWindow *window = mFocus ? mFocus->window() : nullptr;
if (mFocus) {
- const QWindowSystemInterface::TouchPoint &tp = mPendingTouchPoints.last();
+ // Returns a reference to the last item in the list. The list must not be empty.
+ // If the list can be empty, call isEmpty() before calling this function.
+ // See: https://doc.qt.io/qt-5.15/qlist.html#last
+ if (mPendingTouchPoints.empty())
+ return;
+ const QWindowSystemInterface::TouchPoint &tp = mPendingTouchPoints.constLast();
// When the touch event is received, the global pos is calculated with the margins
// in mind. Now we need to adjust again to get the correct local pos back.
- QMargins margins = window->frameMargins();
+ QMargins margins = mFocus->clientSideMargins();
QPoint p = tp.area.center().toPoint();
- QPointF localPos(window->mapFromGlobal(QPoint(p.x() + margins.left(), p.y() + margins.top())));
+ QPointF localPos(mFocus->mapFromGlobal(p) + QPoint(margins.left(), margins.top()));
if (mFocus->touchDragDecoration(mParent, localPos, tp.area.center(), tp.state, mParent->modifiers()))
return;
}
diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h
index b9c69ee14..becd5f9be 100644
--- a/src/client/qwaylandinputdevice_p.h
+++ b/src/client/qwaylandinputdevice_p.h
@@ -64,6 +64,7 @@ class QWaylandTextInputInterface;
class QWaylandTextInputMethod;
#if QT_CONFIG(cursor)
class QWaylandCursorTheme;
+class QWaylandCursorShape;
class CursorSurface;
#endif
@@ -83,7 +84,9 @@ public:
~QWaylandInputDevice() override;
uint32_t capabilities() const { return mCaps; }
+ QString seatname() const { return mSeatName; }
+ QWaylandDisplay *display() const { return mQDisplay; }
struct ::wl_seat *wl_seat() { return QtWayland::wl_seat::object(); }
#if QT_CONFIG(cursor)
@@ -141,6 +144,7 @@ protected:
struct wl_display *mDisplay = nullptr;
uint32_t mCaps = 0;
+ QString mSeatName;
#if QT_CONFIG(cursor)
struct CursorState {
@@ -177,6 +181,7 @@ protected:
uint32_t mSerial = 0;
void seat_capabilities(uint32_t caps) override;
+ void seat_name(const QString &name) override;
void handleTouchPoint(int id, QEventPoint::State state, const QPointF &surfacePosition = QPoint());
QPointingDevice *mTouchDevice = nullptr;
@@ -223,18 +228,16 @@ public:
void keyboard_repeat_info(int32_t rate, int32_t delay) override;
QWaylandInputDevice *mParent = nullptr;
- ::wl_surface *mFocus = nullptr;
+ QPointer<QWaylandSurface> mFocus;
uint32_t mNativeModifiers = 0;
struct repeatKey {
- int key;
- uint32_t code;
- uint32_t time;
+ int key = 0;
+ uint32_t code = 0;
+ uint32_t time = 0 ;
QString text;
- Qt::KeyboardModifiers modifiers;
- uint32_t nativeVirtualKey;
- uint32_t nativeModifiers;
+ uint32_t nativeVirtualKey = 0;
} mRepeatKey;
QTimer mRepeatTimer;
@@ -253,7 +256,7 @@ public:
}
#endif
-private slots:
+private Q_SLOTS:
void handleFocusDestroyed();
void handleFocusLost();
@@ -280,8 +283,6 @@ public:
~Pointer() override;
QWaylandWindow *focusWindow() const;
#if QT_CONFIG(cursor)
- QString cursorThemeName() const;
- int cursorSize() const; // in surface coordinates
int idealCursorScale() const;
void updateCursorTheme();
void updateCursor();
@@ -308,8 +309,10 @@ protected:
void pointer_axis_stop(uint32_t time, uint32_t axis) override;
void pointer_axis_discrete(uint32_t axis, int32_t value) override;
void pointer_frame() override;
+ void pointer_axis_value120(uint32_t axis, int32_t value120) override;
+ void pointer_axis_relative_direction(uint32_t axis, uint32_t direction) override;
-private slots:
+private Q_SLOTS:
void handleFocusDestroyed() { invalidateFocus(); }
private:
@@ -323,6 +326,7 @@ public:
uint32_t mEnterSerial = 0;
#if QT_CONFIG(cursor)
struct {
+ QScopedPointer<QWaylandCursorShape> shape;
QWaylandCursorTheme *theme = nullptr;
int themeBufferScale = 0;
QScopedPointer<CursorSurface> surface;
@@ -334,17 +338,16 @@ public:
QPointF mSurfacePos;
QPointF mGlobalPos;
Qt::MouseButtons mButtons = Qt::NoButton;
-#if QT_CONFIG(cursor)
- wl_buffer *mCursorBuffer = nullptr;
- Qt::CursorShape mCursorShape = Qt::BitmapCursor;
-#endif
+ Qt::MouseButton mLastButton = Qt::NoButton;
struct FrameData {
QWaylandPointerEvent *event = nullptr;
QPointF delta;
- QPoint discreteDelta;
+ QPoint delta120;
axis_source axisSource = axis_source_wheel;
+ bool verticalAxisInverted = false;
+ bool horizontalAxisInverted = false;
void resetScrollData();
bool hasPixelDelta() const;
@@ -418,7 +421,7 @@ public:
ulong timestamp, const QPointF &local, const QPointF &global,
const QPoint &pixelDelta, const QPoint &angleDelta,
Qt::MouseEventSource source,
- Qt::KeyboardModifiers modifiers)
+ Qt::KeyboardModifiers modifiers, bool inverted)
: type(type)
, phase(phase)
, timestamp(timestamp)
@@ -429,6 +432,7 @@ public:
, angleDelta(angleDelta)
, source(source)
, surface(surface)
+ , inverted(inverted)
{}
QEvent::Type type = QEvent::None;
@@ -443,6 +447,7 @@ public:
QPoint angleDelta;
Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
QPointer<QWaylandWindow> surface;
+ bool inverted = false;
};
#ifndef QT_NO_GESTURES
diff --git a/src/client/qwaylandinputmethodcontext.cpp b/src/client/qwaylandinputmethodcontext.cpp
index 383725d1f..2733e4f3a 100644
--- a/src/client/qwaylandinputmethodcontext.cpp
+++ b/src/client/qwaylandinputmethodcontext.cpp
@@ -25,6 +25,7 @@ QWaylandTextInputMethod::QWaylandTextInputMethod(QWaylandDisplay *display, struc
QWaylandTextInputMethod::~QWaylandTextInputMethod()
{
+ qt_text_input_method_v1_destroy(object());
}
void QWaylandTextInputMethod::text_input_method_v1_visible_changed(int32_t visible)
@@ -110,7 +111,7 @@ void QWaylandTextInputMethod::text_input_method_v1_input_method_event_attribute(
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::AttributeType(type), startMapped, length));
break;
case QInputMethodEvent::Cursor:
- attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::AttributeType(type), start, length, QColor(value)));
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::AttributeType(type), start, length, QColor::fromString(value)));
break;
case QInputMethodEvent::TextFormat:
{
@@ -361,6 +362,9 @@ void QWaylandInputMethodContext::setFocusObject(QObject *)
if (inputMethod == nullptr)
return;
+ if (inputMethod->isVisible() && !inputMethodAccepted())
+ inputMethod->hide_input_panel();
+
QWindow *window = QGuiApplication::focusWindow();
if (m_currentWindow != nullptr && m_currentWindow->handle() != nullptr) {
@@ -387,7 +391,7 @@ void QWaylandInputMethodContext::setFocusObject(QObject *)
QWaylandTextInputMethod *QWaylandInputMethodContext::textInputMethod() const
{
- return m_display->defaultInputDevice()->textInputMethod();
+ return m_display->defaultInputDevice() ? m_display->defaultInputDevice()->textInputMethod() : nullptr;
}
} // QtWaylandClient
diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp
index a874c55a3..eb19be45d 100644
--- a/src/client/qwaylandintegration.cpp
+++ b/src/client/qwaylandintegration.cpp
@@ -73,6 +73,8 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
+QWaylandIntegration *QWaylandIntegration::sInstance = nullptr;
+
QWaylandIntegration::QWaylandIntegration()
#if defined(Q_OS_MACOS)
: mFontDb(new QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>)
@@ -81,30 +83,21 @@ QWaylandIntegration::QWaylandIntegration()
#endif
{
mDisplay.reset(new QWaylandDisplay(this));
- if (!mDisplay->isInitialized()) {
- mFailed = true;
- return;
- }
QWaylandWindow::fixedToplevelPositions =
!qEnvironmentVariableIsSet("QT_WAYLAND_DISABLE_FIXED_POSITIONS");
- // ### Not ideal...
- // We don't want to use QPlatformWindow::requestActivate here, since that gives a warning
- // for most shells. Also, we don't want to put this into the specific shells that can use
- // it, since we want to support more than one shell in one client.
- // In addition, this will send a new requestActivate when the focus object changes, even if
- // the focus window stays the same.
- QObject::connect(qApp, &QGuiApplication::focusObjectChanged, qApp, [](){
- QWindow *fw = QGuiApplication::focusWindow();
- auto *w = fw ? static_cast<QWaylandWindow*>(fw->handle()) : nullptr;
- if (w && w->shellSurface())
- w->shellSurface()->requestActivate();
- });
+ sInstance = this;
}
QWaylandIntegration::~QWaylandIntegration()
{
+ sInstance = nullptr;
+}
+
+bool QWaylandIntegration::init()
+{
+ return mDisplay->initialize();
}
QPlatformNativeInterface * QWaylandIntegration::nativeInterface() const
@@ -176,7 +169,7 @@ QPlatformNativeInterface *QWaylandIntegration::createPlatformNativeInterface()
// Support platform specific initialization
void QWaylandIntegration::initializePlatform()
{
- mDisplay->initialize();
+ mDisplay->initEventThread();
mNativeInterface.reset(createPlatformNativeInterface());
initializeInputDeviceIntegration();
@@ -192,14 +185,9 @@ void QWaylandIntegration::initializePlatform()
void QWaylandIntegration::initialize()
{
- mDisplay->initEventThread();
-
- // Call this after initializing event thread for QWaylandDisplay::forceRoundTrip()
initializePlatform();
- // But the aboutToBlock() and awake() should be connected after initializePlatform().
- // Otherwise the connected flushRequests() may consumes up all events before processEvents starts to wait,
- // so that processEvents(QEventLoop::WaitForMoreEvents) may be blocked in the forceRoundTrip().
+ // Call this after initializing event thread for QWaylandDisplay::flushRequests()
QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher;
QObject::connect(dispatcher, SIGNAL(aboutToBlock()), mDisplay.data(), SLOT(flushRequests()));
QObject::connect(dispatcher, SIGNAL(awake()), mDisplay.data(), SLOT(flushRequests()));
@@ -422,7 +410,7 @@ void QWaylandIntegration::initializeShellIntegration()
preferredShells << QLatin1String("qt-shell");
}
- for (const QString &preferredShell : qAsConst(preferredShells)) {
+ for (const QString &preferredShell : std::as_const(preferredShells)) {
mShellIntegration.reset(createShellIntegration(preferredShell));
if (mShellIntegration) {
qCDebug(lcQpaWayland, "Using the '%s' shell integration", qPrintable(preferredShell));
@@ -474,27 +462,35 @@ void QWaylandIntegration::reconfigureInputContext()
return;
}
- const QString &requested = QPlatformInputContextFactory::requested();
- if (requested == QLatin1String("qtvirtualkeyboard"))
+ auto requested = QPlatformInputContextFactory::requested();
+ if (requested.contains(QLatin1String("qtvirtualkeyboard")))
qCWarning(lcQpaWayland) << "qtvirtualkeyboard currently is not supported at client-side,"
- " use QT_IM_MODULE=qtvirtualkeyboard at compositor-side.";
-
- if (requested.isNull()) {
- if (mDisplay->textInputMethodManager() != nullptr)
- mInputContext.reset(new QWaylandInputMethodContext(mDisplay.data()));
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- else if (mDisplay->textInputManagerv1() != nullptr || mDisplay->textInputManagerv2() != nullptr || mDisplay->textInputManagerv4() != nullptr)
-#else // QT_WAYLAND_TEXT_INPUT_V4_WIP
- else if (mDisplay->textInputManagerv1() != nullptr || mDisplay->textInputManagerv2() != nullptr)
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
- mInputContext.reset(new QWaylandInputContext(mDisplay.data()));
- } else {
- mInputContext.reset(QPlatformInputContextFactory::create(requested));
- }
+ " use QT_IM_MODULES=qtvirtualkeyboard at compositor-side.";
+
+ if (mDisplay->isWaylandInputContextRequested()
+ && !requested.contains(QLatin1String(WAYLAND_IM_KEY)))
+ requested.append(QLatin1String(WAYLAND_IM_KEY));
const QString defaultInputContext(QStringLiteral("compose"));
- if ((!mInputContext || !mInputContext->isValid()) && requested != defaultInputContext)
- mInputContext.reset(QPlatformInputContextFactory::create(defaultInputContext));
+ if (!requested.contains(defaultInputContext))
+ requested.append(defaultInputContext);
+
+ for (const QString &imKey : requested) {
+ if (imKey == QLatin1String(WAYLAND_IM_KEY)) {
+ Q_ASSERT(mDisplay->isWaylandInputContextRequested());
+ if (mDisplay->textInputMethodManager() != nullptr)
+ mInputContext.reset(new QWaylandInputMethodContext(mDisplay.data()));
+ else if (mDisplay->textInputManagerv1() != nullptr
+ || mDisplay->textInputManagerv2() != nullptr
+ || mDisplay->textInputManagerv3() != nullptr)
+ mInputContext.reset(new QWaylandInputContext(mDisplay.data()));
+ } else {
+ mInputContext.reset(QPlatformInputContextFactory::create(imKey));
+ }
+
+ if (mInputContext && mInputContext->isValid())
+ break;
+ }
#if QT_CONFIG(xkbcommon)
QXkbCommon::setXkbContext(mInputContext.data(), mDisplay->xkbContext());
@@ -516,6 +512,22 @@ QWaylandShellIntegration *QWaylandIntegration::createShellIntegration(const QStr
}
}
+void QWaylandIntegration::reset()
+{
+ mServerBufferIntegration.reset();
+ mServerBufferIntegrationInitialized = false;
+
+ mInputDeviceIntegration.reset();
+
+ mClientBufferIntegration.reset();
+ mClientBufferIntegrationInitialized = false;
+}
+
+void QWaylandIntegration::setApplicationBadge(qint64 number)
+{
+ auto unixServices = mDisplay->windowManagerIntegration();
+ unixServices->setApplicationBadge(number);
+}
}
QT_END_NAMESPACE
diff --git a/src/client/qwaylandintegration_p.h b/src/client/qwaylandintegration_p.h
index 6221e6893..81d1ae6d2 100644
--- a/src/client/qwaylandintegration_p.h
+++ b/src/client/qwaylandintegration_p.h
@@ -41,7 +41,9 @@ public:
QWaylandIntegration();
~QWaylandIntegration() override;
- bool hasFailed() { return mFailed; }
+ static QWaylandIntegration *instance() { return sInstance; }
+
+ bool init();
bool hasCapability(QPlatformIntegration::Capability cap) const override;
QPlatformWindow *createPlatformWindow(QWindow *window) const override;
@@ -86,6 +88,8 @@ public:
QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const override;
#endif
+ void setApplicationBadge(qint64 number) override;
+
virtual QWaylandInputDevice *createInputDevice(QWaylandDisplay *display, int version, uint32_t id) const;
virtual QWaylandScreen *createPlatformScreen(QWaylandDisplay *waylandDisplay, int version, uint32_t id) const;
virtual QWaylandCursor *createPlatformCursor(QWaylandDisplay *display) const;
@@ -103,6 +107,7 @@ protected:
QScopedPointer<QWaylandDisplay> mDisplay;
protected:
+ void reset();
virtual QPlatformNativeInterface *createPlatformNativeInterface();
QScopedPointer<QWaylandClientBufferIntegration> mClientBufferIntegration;
@@ -131,12 +136,13 @@ private:
#if QT_CONFIG(accessibility)
mutable QScopedPointer<QPlatformAccessibility> mAccessibility;
#endif
- bool mFailed = false;
QMutex mClientBufferInitLock;
bool mClientBufferIntegrationInitialized = false;
bool mServerBufferIntegrationInitialized = false;
bool mShellIntegrationInitialized = false;
+ static QWaylandIntegration *sInstance;
+
friend class QWaylandDisplay;
};
diff --git a/src/client/qwaylandnativeinterface.cpp b/src/client/qwaylandnativeinterface.cpp
index 6d8583480..601f833aa 100644
--- a/src/client/qwaylandnativeinterface.cpp
+++ b/src/client/qwaylandnativeinterface.cpp
@@ -12,6 +12,7 @@
#include "qwaylandwindowmanagerintegration_p.h"
#include "qwaylandscreen_p.h"
#include "qwaylandinputdevice_p.h"
+#include <QtCore/private/qnativeinterface_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/QScreen>
#include <QtWaylandClient/private/qwaylandclientbufferintegration_p.h>
@@ -34,8 +35,10 @@ void *QWaylandNativeInterface::nativeResourceForIntegration(const QByteArray &re
if (lowerCaseResource == "display" || lowerCaseResource == "wl_display" || lowerCaseResource == "nativedisplay")
return m_integration->display()->wl_display();
- if (lowerCaseResource == "compositor")
- return const_cast<wl_compositor *>(m_integration->display()->wl_compositor());
+ if (lowerCaseResource == "compositor") {
+ if (auto compositor = m_integration->display()->compositor())
+ return compositor->object();
+ }
if (lowerCaseResource == "server_buffer_integration")
return m_integration->serverBufferIntegration();
@@ -68,14 +71,72 @@ void *QWaylandNativeInterface::nativeResourceForIntegration(const QByteArray &re
return nullptr;
}
+wl_display *QtWaylandClient::QWaylandNativeInterface::display() const
+{
+ return m_integration->display()->wl_display();
+}
+
+wl_compositor *QtWaylandClient::QWaylandNativeInterface::compositor() const
+{
+ if (auto compositor = m_integration->display()->compositor())
+ return compositor->object();
+ return nullptr;
+}
+
+wl_seat *QtWaylandClient::QWaylandNativeInterface::seat() const
+{
+ if (auto inputDevice = m_integration->display()->defaultInputDevice()) {
+ return inputDevice->wl_seat();
+ }
+ return nullptr;
+}
+
+wl_keyboard *QtWaylandClient::QWaylandNativeInterface::keyboard() const
+{
+ if (auto inputDevice = m_integration->display()->defaultInputDevice())
+ if (auto keyboard = inputDevice->keyboard())
+ return keyboard->wl_keyboard();
+ return nullptr;
+}
+
+wl_pointer *QtWaylandClient::QWaylandNativeInterface::pointer() const
+{
+ if (auto inputDevice = m_integration->display()->defaultInputDevice())
+ if (auto pointer = inputDevice->pointer())
+ return pointer->wl_pointer();
+ return nullptr;
+}
+
+wl_touch *QtWaylandClient::QWaylandNativeInterface::touch() const
+{
+ if (auto inputDevice = m_integration->display()->defaultInputDevice())
+ if (auto touch = inputDevice->touch())
+ return touch->wl_touch();
+ return nullptr;
+}
+
+uint QtWaylandClient::QWaylandNativeInterface::lastInputSerial() const
+{
+ return m_integration->display()->lastInputSerial();
+}
+
+wl_seat *QtWaylandClient::QWaylandNativeInterface::lastInputSeat() const
+{
+ if (auto inputDevice = m_integration->display()->lastInputDevice())
+ return inputDevice->wl_seat();
+ return nullptr;
+}
+
void *QWaylandNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window)
{
QByteArray lowerCaseResource = resourceString.toLower();
if (lowerCaseResource == "display")
return m_integration->display()->wl_display();
- if (lowerCaseResource == "compositor")
- return const_cast<wl_compositor *>(m_integration->display()->wl_compositor());
+ if (lowerCaseResource == "compositor") {
+ if (auto compositor = m_integration->display()->compositor())
+ return compositor->object();
+ }
if (lowerCaseResource == "surface") {
QWaylandWindow *w = static_cast<QWaylandWindow*>(window->handle());
return w ? w->wlSurface() : nullptr;
@@ -88,13 +149,14 @@ void *QWaylandNativeInterface::nativeResourceForWindow(const QByteArray &resourc
if (lowerCaseResource == "vksurface") {
if (window->surfaceType() == QSurface::VulkanSurface && window->handle()) {
// return a pointer to the VkSurfaceKHR value, not the value itself
- return static_cast<QWaylandVulkanWindow *>(window->handle())->surface();
+ return static_cast<QWaylandVulkanWindow *>(window->handle())->vkSurface();
}
}
#endif
- if (auto shellIntegration = m_integration->shellIntegration())
- return shellIntegration->nativeResourceForWindow(resourceString, window);
+ QWaylandWindow *platformWindow = static_cast<QWaylandWindow *>(window->handle());
+ if (platformWindow && platformWindow->shellIntegration())
+ return platformWindow->shellIntegration()->nativeResourceForWindow(resourceString, window);
return nullptr;
}
@@ -103,7 +165,7 @@ void *QWaylandNativeInterface::nativeResourceForScreen(const QByteArray &resourc
{
QByteArray lowerCaseResource = resourceString.toLower();
- if (lowerCaseResource == "output")
+ if (lowerCaseResource == "output" && !screen->handle()->isPlaceholder())
return ((QWaylandScreen *) screen->handle())->output();
return nullptr;
@@ -129,6 +191,17 @@ void *QWaylandNativeInterface::nativeResourceForContext(const QByteArray &resour
}
#endif // opengl
+QPlatformNativeInterface::NativeResourceForWindowFunction QWaylandNativeInterface::nativeResourceFunctionForWindow(const QByteArray &resource)
+{
+ QByteArray lowerCaseResource = resource.toLower();
+
+ if (lowerCaseResource == "setmargins") {
+ return NativeResourceForWindowFunction(reinterpret_cast<void *>(setWindowMargins));
+ }
+
+ return nullptr;
+}
+
QVariantMap QWaylandNativeInterface::windowProperties(QPlatformWindow *window) const
{
QWaylandWindow *waylandWindow = static_cast<QWaylandWindow *>(window);
@@ -158,6 +231,12 @@ void QWaylandNativeInterface::emitWindowPropertyChanged(QPlatformWindow *window,
emit windowPropertyChanged(window,name);
}
+void QWaylandNativeInterface::setWindowMargins(QWindow *window, const QMargins &margins)
+{
+ QWaylandWindow *wlWindow = static_cast<QWaylandWindow*>(window->handle());
+ wlWindow->setCustomMargins(margins);
+}
+
}
QT_END_NAMESPACE
diff --git a/src/client/qwaylandnativeinterface_p.h b/src/client/qwaylandnativeinterface_p.h
index d05d7c38f..ce8c6bec3 100644
--- a/src/client/qwaylandnativeinterface_p.h
+++ b/src/client/qwaylandnativeinterface_p.h
@@ -1,8 +1,8 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QWAYLANDNATIVEINTERFACE_H
-#define QWAYLANDNATIVEINTERFACE_H
+#ifndef QWAYLANDNATIVEINTERFACE_P_H
+#define QWAYLANDNATIVEINTERFACE_P_H
//
// W A R N I N G
@@ -21,15 +21,19 @@
#include <QtWaylandClient/qtwaylandclientglobal.h>
#include <QtCore/private/qglobal_p.h>
#include <QtCore/qhash.h>
+#include <QtGui/qguiapplication_platform.h>
QT_BEGIN_NAMESPACE
+class QMargins;
+
namespace QtWaylandClient {
class QWaylandIntegration;
class QWaylandScreen;
-class Q_WAYLANDCLIENT_EXPORT QWaylandNativeInterface : public QPlatformNativeInterface
+class Q_WAYLANDCLIENT_EXPORT QWaylandNativeInterface : public QPlatformNativeInterface,
+ public QNativeInterface::QWaylandApplication
{
public:
QWaylandNativeInterface(QWaylandIntegration *integration);
@@ -41,6 +45,7 @@ public:
#if QT_CONFIG(opengl)
void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) override;
#endif
+ NativeResourceForWindowFunction nativeResourceFunctionForWindow(const QByteArray &resource) override;
QVariantMap windowProperties(QPlatformWindow *window) const override;
QVariant windowProperty(QPlatformWindow *window, const QString &name) const override;
QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const override;
@@ -48,7 +53,19 @@ public:
void emitWindowPropertyChanged(QPlatformWindow *window, const QString &name);
+ // QWaylandApplication interface
+ wl_display *display() const override;
+ wl_compositor *compositor() const override;
+ wl_seat *seat() const override;
+ wl_keyboard *keyboard() const override;
+ wl_pointer *pointer() const override;
+ wl_touch *touch() const override;
+ uint lastInputSerial() const override;
+ wl_seat *lastInputSeat() const override;
+
private:
+ static void setWindowMargins(QWindow *window, const QMargins &margins);
+
QWaylandIntegration *m_integration = nullptr;
QHash<QPlatformWindow*, QVariantMap> m_windowProperties;
};
@@ -57,4 +74,4 @@ private:
QT_END_NAMESPACE
-#endif // QWAYLANDNATIVEINTERFACE_H
+#endif // QWAYLANDNATIVEINTERFACE_P_H
diff --git a/src/client/qwaylandpointergestures.cpp b/src/client/qwaylandpointergestures.cpp
index df43c31e9..87079d800 100644
--- a/src/client/qwaylandpointergestures.cpp
+++ b/src/client/qwaylandpointergestures.cpp
@@ -14,6 +14,14 @@ QWaylandPointerGestures::QWaylandPointerGestures(QWaylandDisplay *display, uint
{
}
+QWaylandPointerGestures::~QWaylandPointerGestures() noexcept
+{
+ if (version() >= ZWP_POINTER_GESTURES_V1_RELEASE_SINCE_VERSION)
+ release();
+ else
+ zwp_pointer_gestures_v1_destroy(object());
+}
+
QWaylandPointerGestureSwipe *
QWaylandPointerGestures::createPointerGestureSwipe(QWaylandInputDevice *device)
{
@@ -41,8 +49,11 @@ void QWaylandPointerGestureSwipe::zwp_pointer_gesture_swipe_v1_begin(uint32_t se
uint32_t fingers)
{
#ifndef QT_NO_GESTURES
- mParent->mSerial = serial;
mFocus = QWaylandWindow::fromWlSurface(surface);
+ if (!mFocus) {
+ return;
+ }
+ mParent->mSerial = serial;
mFingers = fingers;
const auto* pointer = mParent->pointer();
@@ -62,6 +73,9 @@ void QWaylandPointerGestureSwipe::zwp_pointer_gesture_swipe_v1_update(uint32_t t
wl_fixed_t dx, wl_fixed_t dy)
{
#ifndef QT_NO_GESTURES
+ if (!mFocus) {
+ return;
+ }
const auto* pointer = mParent->pointer();
const QPointF delta = QPointF(wl_fixed_to_double(dx), wl_fixed_to_double(dy));
@@ -79,6 +93,9 @@ void QWaylandPointerGestureSwipe::zwp_pointer_gesture_swipe_v1_end(uint32_t seri
int32_t cancelled)
{
#ifndef QT_NO_GESTURES
+ if (!mFocus) {
+ return;
+ }
mParent->mSerial = serial;
const auto* pointer = mParent->pointer();
@@ -113,11 +130,13 @@ void QWaylandPointerGesturePinch::zwp_pointer_gesture_pinch_v1_begin(uint32_t se
uint32_t fingers)
{
#ifndef QT_NO_GESTURES
- mParent->mSerial = serial;
mFocus = QWaylandWindow::fromWlSurface(surface);
+ if (!mFocus) {
+ return;
+ }
+ mParent->mSerial = serial;
mFingers = fingers;
mLastScale = 1;
-
const auto* pointer = mParent->pointer();
qCDebug(lcQpaWaylandInput) << "zwp_pointer_gesture_pinch_v1_begin @ "
@@ -137,6 +156,9 @@ void QWaylandPointerGesturePinch::zwp_pointer_gesture_pinch_v1_update(uint32_t t
wl_fixed_t rotation)
{
#ifndef QT_NO_GESTURES
+ if (!mFocus) {
+ return;
+ }
const auto* pointer = mParent->pointer();
const qreal rscale = wl_fixed_to_double(scale);
@@ -161,6 +183,9 @@ void QWaylandPointerGesturePinch::zwp_pointer_gesture_pinch_v1_end(uint32_t seri
int32_t cancelled)
{
#ifndef QT_NO_GESTURES
+ if (!mFocus) {
+ return;
+ }
mParent->mSerial = serial;
const auto* pointer = mParent->pointer();
diff --git a/src/client/qwaylandpointergestures_p.h b/src/client/qwaylandpointergestures_p.h
index 7e5a7e06f..06ee4a6ed 100644
--- a/src/client/qwaylandpointergestures_p.h
+++ b/src/client/qwaylandpointergestures_p.h
@@ -36,6 +36,7 @@ class Q_WAYLANDCLIENT_EXPORT QWaylandPointerGestures : public QtWayland::zwp_poi
{
public:
explicit QWaylandPointerGestures(QWaylandDisplay *display, uint id, uint version);
+ ~QWaylandPointerGestures();
QWaylandPointerGestureSwipe *createPointerGestureSwipe(QWaylandInputDevice *device);
QWaylandPointerGesturePinch *createPointerGesturePinch(QWaylandInputDevice *device);
diff --git a/src/client/qwaylandprimaryselectionv1.cpp b/src/client/qwaylandprimaryselectionv1.cpp
index 1eb1fcff3..d72b8f749 100644
--- a/src/client/qwaylandprimaryselectionv1.cpp
+++ b/src/client/qwaylandprimaryselectionv1.cpp
@@ -18,11 +18,11 @@ QWaylandPrimarySelectionDeviceManagerV1::QWaylandPrimarySelectionDeviceManagerV1
: zwp_primary_selection_device_manager_v1(display->wl_registry(), id, qMin(version, uint(1)))
, m_display(display)
{
- // Create devices for all seats.
- // This only works if we get the global before all devices
- const auto seats = m_display->inputDevices();
- for (auto *seat : seats)
- seat->setPrimarySelectionDevice(createDevice(seat));
+}
+
+QWaylandPrimarySelectionDeviceManagerV1::~QWaylandPrimarySelectionDeviceManagerV1()
+{
+ destroy();
}
QWaylandPrimarySelectionDeviceV1 *QWaylandPrimarySelectionDeviceManagerV1::createDevice(QWaylandInputDevice *seat)
diff --git a/src/client/qwaylandprimaryselectionv1_p.h b/src/client/qwaylandprimaryselectionv1_p.h
index 59bb62116..f39aec526 100644
--- a/src/client/qwaylandprimaryselectionv1_p.h
+++ b/src/client/qwaylandprimaryselectionv1_p.h
@@ -37,6 +37,7 @@ class QWaylandPrimarySelectionDeviceManagerV1 : public QtWayland::zwp_primary_se
{
public:
explicit QWaylandPrimarySelectionDeviceManagerV1(QWaylandDisplay *display, uint id, uint version);
+ ~QWaylandPrimarySelectionDeviceManagerV1();
QWaylandPrimarySelectionDeviceV1 *createDevice(QWaylandInputDevice *seat);
QWaylandDisplay *display() const { return m_display; }
@@ -69,7 +70,7 @@ public:
QMimeData *mimeData() const { return m_mimeData; }
-signals:
+Q_SIGNALS:
void cancelled();
protected:
diff --git a/src/client/qwaylandqtkey.cpp b/src/client/qwaylandqtkey.cpp
index f6bda97d8..079a03e0d 100644
--- a/src/client/qwaylandqtkey.cpp
+++ b/src/client/qwaylandqtkey.cpp
@@ -15,6 +15,11 @@ QWaylandQtKeyExtension::QWaylandQtKeyExtension(QWaylandDisplay *display, uint32_
{
}
+QWaylandQtKeyExtension::~QWaylandQtKeyExtension()
+{
+ zqt_key_v1_destroy(object());
+}
+
void QWaylandQtKeyExtension::zqt_key_v1_key(struct wl_surface *surface,
uint32_t time,
uint32_t type,
diff --git a/src/client/qwaylandqtkey_p.h b/src/client/qwaylandqtkey_p.h
index 223b05026..1544a0166 100644
--- a/src/client/qwaylandqtkey_p.h
+++ b/src/client/qwaylandqtkey_p.h
@@ -31,6 +31,7 @@ class Q_WAYLANDCLIENT_EXPORT QWaylandQtKeyExtension : public QtWayland::zqt_key_
{
public:
QWaylandQtKeyExtension(QWaylandDisplay *display, uint32_t id);
+ ~QWaylandQtKeyExtension();
private:
QWaylandDisplay *m_display = nullptr;
diff --git a/src/client/qwaylandscreen.cpp b/src/client/qwaylandscreen.cpp
index 57bccde38..d51e8c6a0 100644
--- a/src/client/qwaylandscreen.cpp
+++ b/src/client/qwaylandscreen.cpp
@@ -22,8 +22,13 @@ QWaylandXdgOutputManagerV1::QWaylandXdgOutputManagerV1(QWaylandDisplay* display,
{
}
+QWaylandXdgOutputManagerV1::~QWaylandXdgOutputManagerV1()
+{
+ destroy();
+}
+
QWaylandScreen::QWaylandScreen(QWaylandDisplay *waylandDisplay, int version, uint32_t id)
- : QtWayland::wl_output(waylandDisplay->wl_registry(), id, qMin(version, 2))
+ : QtWayland::wl_output(waylandDisplay->wl_registry(), id, qMin(version, 3))
, m_outputId(id)
, mWaylandDisplay(waylandDisplay)
, mOutputName(QStringLiteral("Screen%1").arg(id))
@@ -44,6 +49,10 @@ QWaylandScreen::~QWaylandScreen()
{
if (zxdg_output_v1::isInitialized())
zxdg_output_v1::destroy();
+ if (wl_output::version() >= WL_OUTPUT_RELEASE_SINCE_VERSION)
+ wl_output::release();
+ else
+ wl_output_destroy(wl_output::object());
}
uint QWaylandScreen::requiredEvents() const
@@ -148,9 +157,9 @@ QList<QPlatformScreen *> QWaylandScreen::virtualSiblings() const
const QList<QWaylandScreen*> screens = mWaylandDisplay->screens();
auto *placeholder = mWaylandDisplay->placeholderScreen();
- list.reserve(screens.count() + (placeholder ? 1 : 0));
+ list.reserve(screens.size() + (placeholder ? 1 : 0));
- for (QWaylandScreen *screen : qAsConst(screens)) {
+ for (QWaylandScreen *screen : std::as_const(screens)) {
if (screen->screen())
list << screen;
}
@@ -161,6 +170,16 @@ QList<QPlatformScreen *> QWaylandScreen::virtualSiblings() const
return list;
}
+QWindow *QWaylandScreen::topLevelAt(const QPoint & pos) const
+{
+ if (QWaylandWindow::fixedToplevelPositions) {
+ Q_UNUSED(pos);
+ return nullptr;
+ }
+
+ return QPlatformScreen::topLevelAt(pos);
+}
+
Qt::ScreenOrientation QWaylandScreen::orientation() const
{
return m_orientation;
@@ -188,6 +207,32 @@ QPlatformCursor *QWaylandScreen::cursor() const
}
#endif // QT_CONFIG(cursor)
+QPlatformScreen::SubpixelAntialiasingType QWaylandScreen::subpixelAntialiasingTypeHint() const
+{
+ QPlatformScreen::SubpixelAntialiasingType type = QPlatformScreen::subpixelAntialiasingTypeHint();
+ if (type == QPlatformScreen::Subpixel_None) {
+ switch (mSubpixel) {
+ case wl_output::subpixel_unknown:
+ case wl_output::subpixel_none:
+ type = QPlatformScreen::Subpixel_None;
+ break;
+ case wl_output::subpixel_horizontal_rgb:
+ type = QPlatformScreen::Subpixel_RGB;
+ break;
+ case wl_output::subpixel_horizontal_bgr:
+ type = QPlatformScreen::Subpixel_BGR;
+ break;
+ case wl_output::subpixel_vertical_rgb:
+ type = QPlatformScreen::Subpixel_VRGB;
+ break;
+ case wl_output::subpixel_vertical_bgr:
+ type = QPlatformScreen::Subpixel_VBGR;
+ break;
+ }
+ }
+ return type;
+}
+
QWaylandScreen *QWaylandScreen::waylandScreenFromWindow(QWindow *window)
{
QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWindow(window);
@@ -203,6 +248,35 @@ QWaylandScreen *QWaylandScreen::fromWlOutput(::wl_output *output)
return nullptr;
}
+Qt::ScreenOrientation QWaylandScreen::toScreenOrientation(int wlTransform,
+ Qt::ScreenOrientation fallback) const
+{
+ auto orientation = fallback;
+ bool isPortrait = mGeometry.height() > mGeometry.width();
+ switch (wlTransform) {
+ case WL_OUTPUT_TRANSFORM_NORMAL:
+ orientation = isPortrait ? Qt::PortraitOrientation : Qt::LandscapeOrientation;
+ break;
+ case WL_OUTPUT_TRANSFORM_90:
+ orientation = isPortrait ? Qt::InvertedLandscapeOrientation : Qt::PortraitOrientation;
+ break;
+ case WL_OUTPUT_TRANSFORM_180:
+ orientation = isPortrait ? Qt::InvertedPortraitOrientation : Qt::InvertedLandscapeOrientation;
+ break;
+ case WL_OUTPUT_TRANSFORM_270:
+ orientation = isPortrait ? Qt::LandscapeOrientation : Qt::InvertedPortraitOrientation;
+ break;
+ // Ignore these ones, at least for now
+ case WL_OUTPUT_TRANSFORM_FLIPPED:
+ case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+ case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ break;
+ }
+
+ return orientation;
+}
+
void QWaylandScreen::output_mode(uint32_t flags, int width, int height, int refresh)
{
if (!(flags & WL_OUTPUT_MODE_CURRENT))
@@ -223,11 +297,10 @@ void QWaylandScreen::output_geometry(int32_t x, int32_t y,
const QString &model,
int32_t transform)
{
- Q_UNUSED(subpixel);
-
mManufacturer = make;
mModel = model;
+ mSubpixel = subpixel;
mTransform = transform;
mPhysicalSize = QSize(width, height);
@@ -255,29 +328,11 @@ void QWaylandScreen::output_done()
void QWaylandScreen::updateOutputProperties()
{
if (mTransform >= 0) {
- bool isPortrait = mGeometry.height() > mGeometry.width();
- switch (mTransform) {
- case WL_OUTPUT_TRANSFORM_NORMAL:
- m_orientation = isPortrait ? Qt::PortraitOrientation : Qt::LandscapeOrientation;
- break;
- case WL_OUTPUT_TRANSFORM_90:
- m_orientation = isPortrait ? Qt::InvertedLandscapeOrientation : Qt::PortraitOrientation;
- break;
- case WL_OUTPUT_TRANSFORM_180:
- m_orientation = isPortrait ? Qt::InvertedPortraitOrientation : Qt::InvertedLandscapeOrientation;
- break;
- case WL_OUTPUT_TRANSFORM_270:
- m_orientation = isPortrait ? Qt::LandscapeOrientation : Qt::InvertedPortraitOrientation;
- break;
- // Ignore these ones, at least for now
- case WL_OUTPUT_TRANSFORM_FLIPPED:
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- case WL_OUTPUT_TRANSFORM_FLIPPED_180:
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- break;
+ auto newOrientation = toScreenOrientation(mTransform, m_orientation);
+ if (m_orientation != newOrientation) {
+ m_orientation = newOrientation;
+ QWindowSystemInterface::handleScreenOrientationChange(screen(), m_orientation);
}
-
- QWindowSystemInterface::handleScreenOrientationChange(screen(), m_orientation);
mTransform = -1;
}
diff --git a/src/client/qwaylandscreen_p.h b/src/client/qwaylandscreen_p.h
index 836dd0392..ce3df3099 100644
--- a/src/client/qwaylandscreen_p.h
+++ b/src/client/qwaylandscreen_p.h
@@ -16,6 +16,7 @@
//
#include <qpa/qplatformscreen.h>
+#include <QtGui/qscreen_platform.h>
#include <QtWaylandClient/qtwaylandclientglobal.h>
#include <QtWaylandClient/private/qwayland-wayland.h>
@@ -32,9 +33,13 @@ class QWaylandCursor;
class Q_WAYLANDCLIENT_EXPORT QWaylandXdgOutputManagerV1 : public QtWayland::zxdg_output_manager_v1 {
public:
QWaylandXdgOutputManagerV1(QWaylandDisplay *display, uint id, uint version);
+ ~QWaylandXdgOutputManagerV1();
};
-class Q_WAYLANDCLIENT_EXPORT QWaylandScreen : public QPlatformScreen, QtWayland::wl_output, QtWayland::zxdg_output_v1
+class Q_WAYLANDCLIENT_EXPORT QWaylandScreen : public QPlatformScreen,
+ QtWayland::wl_output,
+ QtWayland::zxdg_output_v1,
+ public QNativeInterface::QWaylandScreen
{
public:
QWaylandScreen(QWaylandDisplay *waylandDisplay, int version, uint32_t id);
@@ -58,6 +63,8 @@ public:
QDpi logicalDpi() const override;
QList<QPlatformScreen *> virtualSiblings() const override;
+ QWindow *topLevelAt(const QPoint &point) const override;
+
Qt::ScreenOrientation orientation() const override;
int scale() const;
qreal devicePixelRatio() const override;
@@ -69,12 +76,20 @@ public:
QPlatformCursor *cursor() const override;
#endif
+ SubpixelAntialiasingType subpixelAntialiasingTypeHint() const override;
+
uint32_t outputId() const { return m_outputId; }
- ::wl_output *output() { return QtWayland::wl_output::object(); }
+ ::wl_output *output() const override
+ {
+ return const_cast<::wl_output *>(QtWayland::wl_output::object());
+ }
static QWaylandScreen *waylandScreenFromWindow(QWindow *window);
static QWaylandScreen *fromWlOutput(::wl_output *output);
+ Qt::ScreenOrientation toScreenOrientation(int wlTransform,
+ Qt::ScreenOrientation fallback) const;
+
protected:
enum Event : uint {
XdgOutputDoneEvent = 0x1,
@@ -110,6 +125,7 @@ protected:
int mScale = 1;
int mDepth = 32;
int mRefreshRate = 60000;
+ int mSubpixel = -1;
int mTransform = -1;
QImage::Format mFormat = QImage::Format_ARGB32_Premultiplied;
QSize mPhysicalSize;
diff --git a/src/client/qwaylandshellsurface_p.h b/src/client/qwaylandshellsurface_p.h
index c133269a0..8632efd04 100644
--- a/src/client/qwaylandshellsurface_p.h
+++ b/src/client/qwaylandshellsurface_p.h
@@ -21,6 +21,8 @@
#include <QtWaylandClient/qtwaylandclientglobal.h>
#include <QtCore/private/qglobal_p.h>
+#include <any>
+
struct wl_surface;
QT_BEGIN_NAMESPACE
@@ -68,13 +70,24 @@ public:
virtual void setWindowPosition(const QPoint &position) { Q_UNUSED(position); }
virtual bool requestActivate() { return false; }
+ virtual bool requestActivateOnShow() { return false; }
virtual void setXdgActivationToken(const QString &token);
virtual void requestXdgActivationToken(quint32 serial);
+ virtual void setAlertState(bool enabled) { Q_UNUSED(enabled); }
+ virtual bool isAlertState() const { return false; }
+
+ virtual QString externWindowHandle() { return QString(); }
+
inline QWaylandWindow *window() { return m_window; }
QPlatformWindow *platformWindow();
struct wl_surface *wlSurface();
+ virtual std::any surfaceRole() const { return std::any(); };
+
+ virtual void attachPopup(QWaylandShellSurface *popup) { Q_UNUSED(popup); }
+ virtual void detachPopup(QWaylandShellSurface *popup) { Q_UNUSED(popup); }
+
protected:
void resizeFromApplyConfigure(const QSize &sizeWithMargins, const QPoint &offset = {0, 0});
void repositionFromApplyConfigure(const QPoint &position);
diff --git a/src/client/qwaylandshm.cpp b/src/client/qwaylandshm.cpp
index 7c0bc4ddb..9ee7a96bc 100644
--- a/src/client/qwaylandshm.cpp
+++ b/src/client/qwaylandshm.cpp
@@ -16,7 +16,7 @@ QWaylandShm::QWaylandShm(QWaylandDisplay *display, int version, uint32_t id)
QWaylandShm::~QWaylandShm()
{
-
+ wl_shm_destroy(object());
}
void QWaylandShm::shm_format(uint32_t format)
diff --git a/src/client/qwaylandshmbackingstore.cpp b/src/client/qwaylandshmbackingstore.cpp
index a8e59637a..d77c548a0 100644
--- a/src/client/qwaylandshmbackingstore.cpp
+++ b/src/client/qwaylandshmbackingstore.cpp
@@ -16,6 +16,7 @@
#include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
+#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
@@ -25,6 +26,19 @@
# ifndef MFD_CLOEXEC
# define MFD_CLOEXEC 0x0001U
# endif
+# ifndef MFD_ALLOW_SEALING
+# define MFD_ALLOW_SEALING 0x0002U
+# endif
+// from bits/fcntl-linux.h
+# ifndef F_ADD_SEALS
+# define F_ADD_SEALS 1033
+# endif
+# ifndef F_SEAL_SEAL
+# define F_SEAL_SEAL 0x0001
+# endif
+# ifndef F_SEAL_SHRINK
+# define F_SEAL_SHRINK 0x0002
+# endif
#endif
QT_BEGIN_NAMESPACE
@@ -33,13 +47,16 @@ namespace QtWaylandClient {
QWaylandShmBuffer::QWaylandShmBuffer(QWaylandDisplay *display,
const QSize &size, QImage::Format format, qreal scale)
+ : mDirtyRegion(QRect(QPoint(0, 0), size / scale))
{
int stride = size.width() * 4;
int alloc = stride * size.height();
int fd = -1;
#ifdef SYS_memfd_create
- fd = syscall(SYS_memfd_create, "wayland-shm", MFD_CLOEXEC);
+ fd = syscall(SYS_memfd_create, "wayland-shm", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ if (fd >= 0)
+ fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
#endif
QScopedPointer<QFile> filePointer;
@@ -54,6 +71,7 @@ QWaylandShmBuffer::QWaylandShmBuffer(QWaylandDisplay *display,
file->open(fd, QIODevice::ReadWrite | QIODevice::Unbuffered, QFile::AutoCloseHandle);
filePointer.reset(file);
}
+ // NOTE beginPaint assumes a new buffer be all zeroes, which QFile::resize does.
if (!filePointer->isOpen() || !filePointer->resize(alloc)) {
qWarning("QWaylandShmBuffer: failed: %s", qUtf8Printable(filePointer->errorString()));
return;
@@ -90,7 +108,7 @@ QWaylandShmBuffer::~QWaylandShmBuffer(void)
QImage *QWaylandShmBuffer::imageInsideMargins(const QMargins &marginsIn)
{
- QMargins margins = marginsIn * int(mImage.devicePixelRatio());
+ QMargins margins = marginsIn * mImage.devicePixelRatio();
if (!margins.isNull() && margins != mMargins) {
if (mMarginsImage) {
@@ -120,7 +138,18 @@ QWaylandShmBackingStore::QWaylandShmBackingStore(QWindow *window, QWaylandDispla
: QPlatformBackingStore(window)
, mDisplay(display)
{
-
+ QObject::connect(mDisplay, &QWaylandDisplay::connected, window, [this]() {
+ auto copy = mBuffers;
+ // clear available buffers so we create new ones
+ // actual deletion is deferred till after resize call so we can copy
+ // contents from the back buffer
+ mBuffers.clear();
+ mFrontBuffer = nullptr;
+ // recreateBackBufferIfNeeded always resets mBackBuffer
+ if (mRequestedSize.isValid() && waylandWindow())
+ recreateBackBufferIfNeeded();
+ qDeleteAll(copy);
+ });
}
QWaylandShmBackingStore::~QWaylandShmBackingStore()
@@ -139,14 +168,29 @@ QPaintDevice *QWaylandShmBackingStore::paintDevice()
return contentSurface();
}
+void QWaylandShmBackingStore::updateDirtyStates(const QRegion &region)
+{
+ // Update dirty state of buffers based on what was painted. The back buffer will
+ // not be dirty since we already painted on it, while other buffers will become dirty.
+ for (QWaylandShmBuffer *b : std::as_const(mBuffers)) {
+ if (b != mBackBuffer)
+ b->dirtyRegion() += region;
+ }
+}
+
void QWaylandShmBackingStore::beginPaint(const QRegion &region)
{
mPainting = true;
- ensureSize();
+ waylandWindow()->setBackingStore(this);
+ const bool bufferWasRecreated = recreateBackBufferIfNeeded();
- waylandWindow()->setCanResize(false);
+ const QMargins margins = windowDecorationMargins();
+ updateDirtyStates(region.translated(margins.left(), margins.top()));
- if (mBackBuffer->image()->hasAlphaChannel()) {
+ // Although undocumented, QBackingStore::beginPaint expects the painted region
+ // to be cleared before use if the window has a surface format with an alpha.
+ // Fresh QWaylandShmBuffer are already cleared, so we don't need to clear those.
+ if (!bufferWasRecreated && mBackBuffer->image()->hasAlphaChannel()) {
QPainter p(paintDevice());
p.setCompositionMode(QPainter::CompositionMode_Source);
const QColor blank = Qt::transparent;
@@ -160,14 +204,6 @@ void QWaylandShmBackingStore::endPaint()
mPainting = false;
if (mPendingFlush)
flush(window(), mPendingRegion, QPoint());
- waylandWindow()->setCanResize(true);
-}
-
-void QWaylandShmBackingStore::ensureSize()
-{
- waylandWindow()->setBackingStore(this);
- waylandWindow()->createDecoration();
- resize(mRequestedSize);
}
void QWaylandShmBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
@@ -206,8 +242,10 @@ void QWaylandShmBackingStore::resize(const QSize &size, const QRegion &)
mRequestedSize = size;
}
-QWaylandShmBuffer *QWaylandShmBackingStore::getBuffer(const QSize &size)
+QWaylandShmBuffer *QWaylandShmBackingStore::getBuffer(const QSize &size, bool &bufferWasRecreated)
{
+ bufferWasRecreated = false;
+
const auto copy = mBuffers; // remove when ported to vector<unique_ptr> + remove_if
for (QWaylandShmBuffer *b : copy) {
if (!b->busy()) {
@@ -226,40 +264,61 @@ QWaylandShmBuffer *QWaylandShmBackingStore::getBuffer(const QSize &size)
if (mBuffers.size() < MAX_BUFFERS) {
QImage::Format format = QPlatformScreen::platformScreenForWindow(window())->format();
QWaylandShmBuffer *b = new QWaylandShmBuffer(mDisplay, size, format, waylandWindow()->scale());
+ bufferWasRecreated = true;
mBuffers.push_front(b);
return b;
}
return nullptr;
}
-void QWaylandShmBackingStore::resize(const QSize &size)
+bool QWaylandShmBackingStore::recreateBackBufferIfNeeded()
{
+ bool bufferWasRecreated = false;
QMargins margins = windowDecorationMargins();
qreal scale = waylandWindow()->scale();
- QSize sizeWithMargins = (size + QSize(margins.left()+margins.right(),margins.top()+margins.bottom())) * scale;
+ const QSize sizeWithMargins = (mRequestedSize + QSize(margins.left() + margins.right(), margins.top() + margins.bottom())) * scale;
// We look for a free buffer to draw into. If the buffer is not the last buffer we used,
- // that is mBackBuffer, and the size is the same we memcpy the old content into the new
+ // that is mBackBuffer, and the size is the same we copy the damaged content into the new
// buffer so that QPainter is happy to find the stuff it had drawn before. If the new
// buffer has a different size it needs to be redrawn completely anyway, and if the buffer
// is the same the stuff is there already.
// You can exercise the different codepaths with weston, switching between the gl and the
// pixman renderer. With the gl renderer release events are sent early so we can effectively
// run single buffered, while with the pixman renderer we have to use two.
- QWaylandShmBuffer *buffer = getBuffer(sizeWithMargins);
+ QWaylandShmBuffer *buffer = getBuffer(sizeWithMargins, bufferWasRecreated);
while (!buffer) {
qCDebug(lcWaylandBackingstore, "QWaylandShmBackingStore: stalling waiting for a buffer to be released from the compositor...");
mDisplay->blockingReadEvents();
- buffer = getBuffer(sizeWithMargins);
+ buffer = getBuffer(sizeWithMargins, bufferWasRecreated);
}
qsizetype oldSizeInBytes = mBackBuffer ? mBackBuffer->image()->sizeInBytes() : 0;
qsizetype newSizeInBytes = buffer->image()->sizeInBytes();
// mBackBuffer may have been deleted here but if so it means its size was different so we wouldn't copy it anyway
- if (mBackBuffer != buffer && oldSizeInBytes == newSizeInBytes)
- memcpy(buffer->image()->bits(), mBackBuffer->image()->constBits(), newSizeInBytes);
+ if (mBackBuffer != buffer && oldSizeInBytes == newSizeInBytes) {
+ Q_ASSERT(mBackBuffer);
+ const QImage *sourceImage = mBackBuffer->image();
+ QImage *targetImage = buffer->image();
+
+ QPainter painter(targetImage);
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+
+ // Let painter operate in device pixels, to make it easier to compare coordinates
+ const qreal sourceDevicePixelRatio = sourceImage->devicePixelRatio();
+ const qreal targetDevicePixelRatio = painter.device()->devicePixelRatio();
+ painter.scale(1.0 / targetDevicePixelRatio, 1.0 / targetDevicePixelRatio);
+
+ for (const QRect &rect : buffer->dirtyRegion()) {
+ QRectF sourceRect(QPointF(rect.topLeft()) * sourceDevicePixelRatio,
+ QSizeF(rect.size()) * sourceDevicePixelRatio);
+ QRectF targetRect(QPointF(rect.topLeft()) * targetDevicePixelRatio,
+ QSizeF(rect.size()) * targetDevicePixelRatio);
+ painter.drawImage(targetRect, *sourceImage, sourceRect);
+ }
+ }
mBackBuffer = buffer;
@@ -272,6 +331,10 @@ void QWaylandShmBackingStore::resize(const QSize &size)
if (windowDecoration() && window()->isVisible() && oldSizeInBytes != newSizeInBytes)
windowDecoration()->update();
+
+ buffer->dirtyRegion() = QRegion();
+
+ return bufferWasRecreated;
}
QImage *QWaylandShmBackingStore::entireSurface() const
@@ -296,6 +359,7 @@ void QWaylandShmBackingStore::updateDecorations()
QTransform sourceMatrix;
sourceMatrix.scale(dp, dp);
QRect target; // needs to be in device independent pixels
+ QRegion dirtyRegion;
//Top
target.setX(0);
@@ -303,16 +367,19 @@ void QWaylandShmBackingStore::updateDecorations()
target.setWidth(dpWidth);
target.setHeight(windowDecorationMargins().top());
decorationPainter.drawImage(target, sourceImage, sourceMatrix.mapRect(target));
+ dirtyRegion += target;
//Left
target.setWidth(windowDecorationMargins().left());
target.setHeight(dpHeight);
decorationPainter.drawImage(target, sourceImage, sourceMatrix.mapRect(target));
+ dirtyRegion += target;
//Right
target.setX(dpWidth - windowDecorationMargins().right());
target.setWidth(windowDecorationMargins().right());
decorationPainter.drawImage(target, sourceImage, sourceMatrix.mapRect(target));
+ dirtyRegion += target;
//Bottom
target.setX(0);
@@ -320,6 +387,9 @@ void QWaylandShmBackingStore::updateDecorations()
target.setWidth(dpWidth);
target.setHeight(windowDecorationMargins().bottom());
decorationPainter.drawImage(target, sourceImage, sourceMatrix.mapRect(target));
+ dirtyRegion += target;
+
+ updateDirtyStates(dirtyRegion);
}
QWaylandAbstractDecoration *QWaylandShmBackingStore::windowDecoration() const
diff --git a/src/client/qwaylandshmbackingstore_p.h b/src/client/qwaylandshmbackingstore_p.h
index 8a63b3c14..6d276bf7b 100644
--- a/src/client/qwaylandshmbackingstore_p.h
+++ b/src/client/qwaylandshmbackingstore_p.h
@@ -42,11 +42,14 @@ public:
QImage *image() { return &mImage; }
QImage *imageInsideMargins(const QMargins &margins);
+
+ QRegion &dirtyRegion() { return mDirtyRegion; }
private:
QImage mImage;
struct wl_shm_pool *mShmPool = nullptr;
QMargins mMargins;
QImage *mMarginsImage = nullptr;
+ QRegion mDirtyRegion;
};
class Q_WAYLANDCLIENT_EXPORT QWaylandShmBackingStore : public QPlatformBackingStore
@@ -58,7 +61,6 @@ public:
QPaintDevice *paintDevice() override;
void flush(QWindow *window, const QRegion &region, const QPoint &offset) override;
void resize(const QSize &size, const QRegion &staticContents) override;
- void resize(const QSize &size);
void beginPaint(const QRegion &region) override;
void endPaint() override;
@@ -67,7 +69,7 @@ public:
QMargins windowDecorationMargins() const;
QImage *entireSurface() const;
QImage *contentSurface() const;
- void ensureSize();
+ bool recreateBackBufferIfNeeded();
QWaylandWindow *waylandWindow() const;
void iterateBuffer();
@@ -77,8 +79,9 @@ public:
#endif
private:
+ void updateDirtyStates(const QRegion &region);
void updateDecorations();
- QWaylandShmBuffer *getBuffer(const QSize &size);
+ QWaylandShmBuffer *getBuffer(const QSize &size, bool &bufferWasRecreated);
QWaylandDisplay *mDisplay = nullptr;
std::list<QWaylandShmBuffer *> mBuffers;
diff --git a/src/client/qwaylandsurface.cpp b/src/client/qwaylandsurface.cpp
index cd1a561ba..949d7b160 100644
--- a/src/client/qwaylandsurface.cpp
+++ b/src/client/qwaylandsurface.cpp
@@ -85,6 +85,22 @@ void QWaylandSurface::surface_leave(wl_output *output)
emit screensChanged();
}
+void QWaylandSurface::surface_preferred_buffer_scale(int32_t scale)
+{
+ if (m_preferredBufferScale == scale)
+ return;
+ m_preferredBufferScale = scale;
+ Q_EMIT preferredBufferScaleChanged();
+}
+
+void QWaylandSurface::surface_preferred_buffer_transform(uint32_t transform)
+{
+ if (m_preferredBufferTransform == transform)
+ return;
+ m_preferredBufferTransform = static_cast<wl_output_transform>(transform);
+ Q_EMIT preferredBufferTransformChanged();
+}
+
} // namespace QtWaylandClient
QT_END_NAMESPACE
diff --git a/src/client/qwaylandsurface_p.h b/src/client/qwaylandsurface_p.h
index 027c6ca4d..41860297e 100644
--- a/src/client/qwaylandsurface_p.h
+++ b/src/client/qwaylandsurface_p.h
@@ -36,21 +36,29 @@ public:
~QWaylandSurface() override;
QWaylandScreen *oldestEnteredScreen();
QWaylandWindow *waylandWindow() const { return m_window; }
+ std::optional<int32_t> preferredBufferScale() const { return m_preferredBufferScale; }
+ std::optional<wl_output_transform> preferredBufferTransform() const { return m_preferredBufferTransform; }
static QWaylandSurface *fromWlSurface(::wl_surface *surface);
-signals:
+Q_SIGNALS:
void screensChanged();
+ void preferredBufferScaleChanged();
+ void preferredBufferTransformChanged();
-private slots:
+private Q_SLOTS:
void handleScreenRemoved(QScreen *qScreen);
protected:
void surface_enter(struct ::wl_output *output) override;
void surface_leave(struct ::wl_output *output) override;
+ void surface_preferred_buffer_scale(int32_t scale) override;
+ void surface_preferred_buffer_transform(uint32_t transform) override;
QList<QWaylandScreen *> m_screens; //As seen by wl_surface.enter/leave events. Chronological order.
QWaylandWindow *m_window = nullptr;
+ std::optional<int32_t> m_preferredBufferScale;
+ std::optional<wl_output_transform> m_preferredBufferTransform;
friend class QWaylandWindow; // TODO: shouldn't need to be friends
};
diff --git a/src/client/qwaylandtabletv2.cpp b/src/client/qwaylandtabletv2.cpp
index 8a0544aeb..73524c166 100644
--- a/src/client/qwaylandtabletv2.cpp
+++ b/src/client/qwaylandtabletv2.cpp
@@ -20,6 +20,11 @@ QWaylandTabletManagerV2::QWaylandTabletManagerV2(QWaylandDisplay *display, uint
createTabletSeat(seat);
}
+QWaylandTabletManagerV2::~QWaylandTabletManagerV2()
+{
+ destroy();
+}
+
QWaylandTabletSeatV2 *QWaylandTabletManagerV2::createTabletSeat(QWaylandInputDevice *seat)
{
return new QWaylandTabletSeatV2(this, seat);
@@ -27,6 +32,7 @@ QWaylandTabletSeatV2 *QWaylandTabletManagerV2::createTabletSeat(QWaylandInputDev
QWaylandTabletSeatV2::QWaylandTabletSeatV2(QWaylandTabletManagerV2 *manager, QWaylandInputDevice *seat)
: QtWayland::zwp_tablet_seat_v2(manager->get_tablet_seat(seat->wl_seat()))
+ , m_seat(seat)
{
}
@@ -38,6 +44,9 @@ QWaylandTabletSeatV2::~QWaylandTabletSeatV2()
tool->destroy();
for (auto *pad : m_pads)
pad->destroy();
+ qDeleteAll(m_tablets);
+ qDeleteAll(m_tools);
+ qDeleteAll(m_pads);
destroy();
}
@@ -50,7 +59,7 @@ void QWaylandTabletSeatV2::zwp_tablet_seat_v2_tablet_added(zwp_tablet_v2 *id)
void QWaylandTabletSeatV2::zwp_tablet_seat_v2_tool_added(zwp_tablet_tool_v2 *id)
{
- auto *tool = new QWaylandTabletToolV2(id);
+ auto *tool = new QWaylandTabletToolV2(this, id);
m_tools.push_back(tool);
connect(tool, &QWaylandTabletToolV2::destroyed, this, [this, tool] { m_tools.removeOne(tool); });
}
@@ -73,8 +82,9 @@ void QWaylandTabletV2::zwp_tablet_v2_removed()
delete this;
}
-QWaylandTabletToolV2::QWaylandTabletToolV2(::zwp_tablet_tool_v2 *tool)
+QWaylandTabletToolV2::QWaylandTabletToolV2(QWaylandTabletSeatV2 *tabletSeat, ::zwp_tablet_tool_v2 *tool)
: QtWayland::zwp_tablet_tool_v2(tool)
+ , m_tabletSeat(tabletSeat)
{
}
@@ -160,8 +170,14 @@ void QWaylandTabletToolV2::zwp_tablet_tool_v2_proximity_out()
void QWaylandTabletToolV2::zwp_tablet_tool_v2_down(uint32_t serial)
{
- Q_UNUSED(serial);
m_pending.down = true;
+
+ if (m_pending.proximitySurface) {
+ if (QWaylandWindow *window = m_pending.proximitySurface->waylandWindow()) {
+ QWaylandInputDevice *seat = m_tabletSeat->seat();
+ seat->display()->setLastInputDevice(seat, serial, window);
+ }
+ }
}
void QWaylandTabletToolV2::zwp_tablet_tool_v2_up()
diff --git a/src/client/qwaylandtabletv2_p.h b/src/client/qwaylandtabletv2_p.h
index 7ddf02e67..20a8a4f5a 100644
--- a/src/client/qwaylandtabletv2_p.h
+++ b/src/client/qwaylandtabletv2_p.h
@@ -42,6 +42,7 @@ class Q_WAYLANDCLIENT_EXPORT QWaylandTabletManagerV2 : public QtWayland::zwp_tab
{
public:
explicit QWaylandTabletManagerV2(QWaylandDisplay *display, uint id, uint version);
+ ~QWaylandTabletManagerV2() override;
QWaylandTabletSeatV2 *createTabletSeat(QWaylandInputDevice *seat);
};
@@ -52,12 +53,15 @@ public:
explicit QWaylandTabletSeatV2(QWaylandTabletManagerV2 *manager, QWaylandInputDevice *seat);
~QWaylandTabletSeatV2() override;
+ QWaylandInputDevice *seat() const { return m_seat; }
+
protected:
void zwp_tablet_seat_v2_tablet_added(struct ::zwp_tablet_v2 *id) override;
void zwp_tablet_seat_v2_tool_added(struct ::zwp_tablet_tool_v2 *id) override;
void zwp_tablet_seat_v2_pad_added(struct ::zwp_tablet_pad_v2 *id) override;
private:
+ QWaylandInputDevice *m_seat;
QList<QWaylandTabletV2 *> m_tablets;
QList<QWaylandTabletToolV2 *> m_tools;
QList<QWaylandTabletPadV2 *> m_pads;
@@ -81,7 +85,7 @@ class Q_WAYLANDCLIENT_EXPORT QWaylandTabletToolV2 : public QObject, public QtWay
{
Q_OBJECT
public:
- explicit QWaylandTabletToolV2(::zwp_tablet_tool_v2 *tool);
+ QWaylandTabletToolV2(QWaylandTabletSeatV2 *tabletSeat, ::zwp_tablet_tool_v2 *tool);
protected:
void zwp_tablet_tool_v2_type(uint32_t tool_type) override;
@@ -105,6 +109,7 @@ protected:
void zwp_tablet_tool_v2_frame(uint32_t time) override;
private:
+ QWaylandTabletSeatV2 *m_tabletSeat;
// Static state (sent before done event)
QPointingDevice::PointerType m_pointerType = QPointingDevice::PointerType::Unknown;
diff --git a/src/client/qwaylandtextinputv1.cpp b/src/client/qwaylandtextinputv1.cpp
index 52a3a13c0..846ed95c8 100644
--- a/src/client/qwaylandtextinputv1.cpp
+++ b/src/client/qwaylandtextinputv1.cpp
@@ -10,6 +10,7 @@
#include <QtCore/qloggingcategory.h>
#include <QtGui/QGuiApplication>
#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtGui/qpa/qplatformintegration.h>
#include <QtGui/qevent.h>
#include <QtGui/qwindow.h>
@@ -26,7 +27,7 @@ namespace QtWaylandClient {
namespace {
-const Qt::InputMethodQueries supportedQueries = Qt::ImEnabled |
+const Qt::InputMethodQueries supportedQueries1 = Qt::ImEnabled |
Qt::ImSurroundingText |
Qt::ImCursorPosition |
Qt::ImAnchorPosition |
@@ -45,6 +46,7 @@ QWaylandTextInputv1::~QWaylandTextInputv1()
{
if (m_resetCallback)
wl_callback_destroy(m_resetCallback);
+ zwp_text_input_v1_destroy(object());
}
void QWaylandTextInputv1::reset()
@@ -92,7 +94,7 @@ void QWaylandTextInputv1::updateState(Qt::InputMethodQueries queries, uint32_t f
if (!surface || (surface != m_surface))
return;
- queries &= supportedQueries;
+ queries &= supportedQueries1;
// Surrounding text, cursor and anchor positions are transferred together
if ((queries & Qt::ImSurroundingText) || (queries & Qt::ImCursorPosition) || (queries & Qt::ImAnchorPosition))
@@ -127,8 +129,9 @@ void QWaylandTextInputv1::updateState(Qt::InputMethodQueries queries, uint32_t f
if (queries & Qt::ImCursorRectangle) {
const QRect &cRect = event.value(Qt::ImCursorRectangle).toRect();
const QRect &windowRect = QGuiApplication::inputMethod()->inputItemTransform().mapRect(cRect);
- const QMargins margins = window->frameMargins();
- const QRect &surfaceRect = windowRect.translated(margins.left(), margins.top());
+ const QRect &nativeRect = QHighDpi::toNativePixels(windowRect, QGuiApplication::focusWindow());
+ const QMargins margins = window->clientSideMargins();
+ const QRect &surfaceRect = nativeRect.translated(margins.left(), margins.top());
set_cursor_rectangle(surfaceRect.x(), surfaceRect.y(), surfaceRect.width(), surfaceRect.height());
}
diff --git a/src/client/qwaylandtextinputv2.cpp b/src/client/qwaylandtextinputv2.cpp
index 402f5b557..9d462f7d6 100644
--- a/src/client/qwaylandtextinputv2.cpp
+++ b/src/client/qwaylandtextinputv2.cpp
@@ -11,6 +11,7 @@
#include <QtCore/qloggingcategory.h>
#include <QtGui/QGuiApplication>
#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtGui/qpa/qplatformintegration.h>
#include <QtGui/qevent.h>
#include <QtGui/qwindow.h>
@@ -27,7 +28,7 @@ namespace QtWaylandClient {
namespace {
-const Qt::InputMethodQueries supportedQueries = Qt::ImEnabled |
+const Qt::InputMethodQueries supportedQueries2 = Qt::ImEnabled |
Qt::ImSurroundingText |
Qt::ImCursorPosition |
Qt::ImAnchorPosition |
@@ -46,6 +47,7 @@ QWaylandTextInputv2::~QWaylandTextInputv2()
{
if (m_resetCallback)
wl_callback_destroy(m_resetCallback);
+ destroy();
}
void QWaylandTextInputv2::reset()
@@ -58,9 +60,14 @@ void QWaylandTextInputv2::reset()
void QWaylandTextInputv2::commit()
{
if (QObject *o = QGuiApplication::focusObject()) {
- QInputMethodEvent event;
- event.setCommitString(m_preeditCommit);
- QCoreApplication::sendEvent(o, &event);
+ if (!m_preeditCommit.isEmpty()) {
+
+ QInputMethodEvent event;
+ event.setCommitString(m_preeditCommit);
+ m_preeditCommit = QString();
+
+ QCoreApplication::sendEvent(o, &event);
+ }
}
reset();
@@ -93,7 +100,7 @@ void QWaylandTextInputv2::updateState(Qt::InputMethodQueries queries, uint32_t f
if (!surface || (surface != m_surface))
return;
- queries &= supportedQueries;
+ queries &= supportedQueries2;
// Surrounding text, cursor and anchor positions are transferred together
if ((queries & Qt::ImSurroundingText) || (queries & Qt::ImCursorPosition) || (queries & Qt::ImAnchorPosition))
@@ -128,8 +135,9 @@ void QWaylandTextInputv2::updateState(Qt::InputMethodQueries queries, uint32_t f
if (queries & Qt::ImCursorRectangle) {
const QRect &cRect = event.value(Qt::ImCursorRectangle).toRect();
const QRect &windowRect = QGuiApplication::inputMethod()->inputItemTransform().mapRect(cRect);
- const QMargins margins = window->frameMargins();
- const QRect &surfaceRect = windowRect.translated(margins.left(), margins.top());
+ const QRect &nativeRect = QHighDpi::toNativePixels(windowRect, QGuiApplication::focusWindow());
+ const QMargins margins = window->clientSideMargins();
+ const QRect &surfaceRect = nativeRect.translated(margins.left(), margins.top());
set_cursor_rectangle(surfaceRect.x(), surfaceRect.y(), surfaceRect.width(), surfaceRect.height());
}
diff --git a/src/client/qwaylandtextinputv4.cpp b/src/client/qwaylandtextinputv3.cpp
index 4b3e6eb5f..017456ac2 100644
--- a/src/client/qwaylandtextinputv4.cpp
+++ b/src/client/qwaylandtextinputv3.cpp
@@ -1,13 +1,14 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qwaylandtextinputv4_p.h"
+#include "qwaylandtextinputv3_p.h"
#include "qwaylandwindow_p.h"
#include "qwaylandinputmethodeventbuilder_p.h"
#include <QtCore/qloggingcategory.h>
#include <QtGui/qguiapplication.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtGui/qevent.h>
#include <QtGui/qwindow.h>
#include <QTextCharFormat>
@@ -18,20 +19,20 @@ Q_LOGGING_CATEGORY(qLcQpaWaylandTextInput, "qt.qpa.wayland.textinput")
namespace QtWaylandClient {
-QWaylandTextInputv4::QWaylandTextInputv4(QWaylandDisplay *display,
- struct ::zwp_text_input_v4 *text_input)
- : QtWayland::zwp_text_input_v4(text_input)
- , m_display(display)
+QWaylandTextInputv3::QWaylandTextInputv3(QWaylandDisplay *display,
+ struct ::zwp_text_input_v3 *text_input)
+ : QtWayland::zwp_text_input_v3(text_input)
{
-
+ Q_UNUSED(display)
}
-QWaylandTextInputv4::~QWaylandTextInputv4()
+QWaylandTextInputv3::~QWaylandTextInputv3()
{
+ destroy();
}
namespace {
-const Qt::InputMethodQueries supportedQueries = Qt::ImEnabled |
+const Qt::InputMethodQueries supportedQueries3 = Qt::ImEnabled |
Qt::ImSurroundingText |
Qt::ImCursorPosition |
Qt::ImAnchorPosition |
@@ -39,9 +40,9 @@ const Qt::InputMethodQueries supportedQueries = Qt::ImEnabled |
Qt::ImCursorRectangle;
}
-void QWaylandTextInputv4::zwp_text_input_v4_enter(struct ::wl_surface *surface)
+void QWaylandTextInputv3::zwp_text_input_v3_enter(struct ::wl_surface *surface)
{
- qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO;
+ qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO << m_surface << surface;
m_surface = surface;
@@ -51,10 +52,10 @@ void QWaylandTextInputv4::zwp_text_input_v4_enter(struct ::wl_surface *surface)
m_pendingDeleteAfterText = 0;
enable();
- updateState(supportedQueries, update_state_enter);
+ updateState(supportedQueries3, update_state_enter);
}
-void QWaylandTextInputv4::zwp_text_input_v4_leave(struct ::wl_surface *surface)
+void QWaylandTextInputv3::zwp_text_input_v3_leave(struct ::wl_surface *surface)
{
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO;
@@ -63,20 +64,15 @@ void QWaylandTextInputv4::zwp_text_input_v4_leave(struct ::wl_surface *surface)
return;
}
- // QTBUG-97248: check commit_mode
- // Currently text-input-unstable-v4-wip is implemented with preedit_commit_mode
- // 'commit'
-
m_currentPreeditString.clear();
m_surface = nullptr;
- m_currentSerial = 0U;
disable();
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO << "Done";
}
-void QWaylandTextInputv4::zwp_text_input_v4_preedit_string(const QString &text, int32_t cursorBegin, int32_t cursorEnd)
+void QWaylandTextInputv3::zwp_text_input_v3_preedit_string(const QString &text, int32_t cursorBegin, int32_t cursorEnd)
{
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO << text << cursorBegin << cursorEnd;
@@ -88,7 +84,7 @@ void QWaylandTextInputv4::zwp_text_input_v4_preedit_string(const QString &text,
m_pendingPreeditString.cursorEnd = cursorEnd;
}
-void QWaylandTextInputv4::zwp_text_input_v4_commit_string(const QString &text)
+void QWaylandTextInputv3::zwp_text_input_v3_commit_string(const QString &text)
{
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO << text;
@@ -98,7 +94,7 @@ void QWaylandTextInputv4::zwp_text_input_v4_commit_string(const QString &text)
m_pendingCommitString = text;
}
-void QWaylandTextInputv4::zwp_text_input_v4_delete_surrounding_text(uint32_t beforeText, uint32_t afterText)
+void QWaylandTextInputv3::zwp_text_input_v3_delete_surrounding_text(uint32_t beforeText, uint32_t afterText)
{
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO << beforeText << afterText;
@@ -109,12 +105,12 @@ void QWaylandTextInputv4::zwp_text_input_v4_delete_surrounding_text(uint32_t bef
m_pendingDeleteAfterText = QWaylandInputMethodEventBuilder::indexFromWayland(m_surroundingText, afterText);
}
-void QWaylandTextInputv4::zwp_text_input_v4_done(uint32_t serial)
+void QWaylandTextInputv3::zwp_text_input_v3_done(uint32_t serial)
{
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO << "with serial" << serial << m_currentSerial;
// This is a case of double click.
- // text_input_v4 will ignore this done signal and just keep the selection of the clicked word.
+ // text_input_v3 will ignore this done signal and just keep the selection of the clicked word.
if (m_cursorPos != m_anchorPos && (m_pendingDeleteBeforeText != 0 || m_pendingDeleteAfterText != 0)) {
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO << "Ignore done";
m_pendingDeleteBeforeText = 0;
@@ -177,40 +173,25 @@ void QWaylandTextInputv4::zwp_text_input_v4_done(uint32_t serial)
QCoreApplication::sendEvent(focusObject, &event);
if (serial == m_currentSerial)
- updateState(supportedQueries, update_state_full);
+ updateState(supportedQueries3, update_state_full);
}
-void QWaylandTextInputv4::reset()
+void QWaylandTextInputv3::reset()
{
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO;
m_pendingPreeditString.clear();
}
-void QWaylandTextInputv4::enableSurface(::wl_surface *)
-{
- qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO;
-}
-
-void QWaylandTextInputv4::disableSurface(::wl_surface *surface)
-{
- qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO;
-
- if (m_surface != surface) {
- qCWarning(qLcQpaWaylandTextInput()) << Q_FUNC_INFO << "for surface" << surface << "focused surface" << m_surface;
- return;
- }
-}
-
-void QWaylandTextInputv4::commit()
+void QWaylandTextInputv3::commit()
{
m_currentSerial = (m_currentSerial < UINT_MAX) ? m_currentSerial + 1U: 0U;
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO << "with serial" << m_currentSerial;
- QtWayland::zwp_text_input_v4::commit();
+ QtWayland::zwp_text_input_v3::commit();
}
-void QWaylandTextInputv4::updateState(Qt::InputMethodQueries queries, uint32_t flags)
+void QWaylandTextInputv3::updateState(Qt::InputMethodQueries queries, uint32_t flags)
{
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO << queries << flags;
@@ -225,7 +206,7 @@ void QWaylandTextInputv4::updateState(Qt::InputMethodQueries queries, uint32_t f
if (!surface || (surface != m_surface))
return;
- queries &= supportedQueries;
+ queries &= supportedQueries3;
bool needsCommit = false;
QInputMethodQueryEvent event(queries);
@@ -239,8 +220,9 @@ void QWaylandTextInputv4::updateState(Qt::InputMethodQueries queries, uint32_t f
if (queries & Qt::ImCursorRectangle) {
const QRect &cRect = event.value(Qt::ImCursorRectangle).toRect();
const QRect &windowRect = QGuiApplication::inputMethod()->inputItemTransform().mapRect(cRect);
- const QMargins margins = window->frameMargins();
- const QRect &surfaceRect = windowRect.translated(margins.left(), margins.top());
+ const QRect &nativeRect = QHighDpi::toNativePixels(windowRect, QGuiApplication::focusWindow());
+ const QMargins margins = window->clientSideMargins();
+ const QRect &surfaceRect = nativeRect.translated(margins.left(), margins.top());
if (surfaceRect != m_cursorRect) {
set_cursor_rectangle(surfaceRect.x(), surfaceRect.y(), surfaceRect.width(), surfaceRect.height());
m_cursorRect = surfaceRect;
@@ -319,7 +301,7 @@ void QWaylandTextInputv4::updateState(Qt::InputMethodQueries queries, uint32_t f
}
if (queries & Qt::ImHints) {
- QWaylandInputMethodContentType contentType = QWaylandInputMethodContentType::convertV4(static_cast<Qt::InputMethodHints>(event.value(Qt::ImHints).toInt()));
+ QWaylandInputMethodContentType contentType = QWaylandInputMethodContentType::convertV3(static_cast<Qt::InputMethodHints>(event.value(Qt::ImHints).toInt()));
qCDebug(qLcQpaWaylandTextInput) << m_contentHint << contentType.hint;
qCDebug(qLcQpaWaylandTextInput) << m_contentPurpose << contentType.purpose;
@@ -338,33 +320,29 @@ void QWaylandTextInputv4::updateState(Qt::InputMethodQueries queries, uint32_t f
commit();
}
-void QWaylandTextInputv4::setCursorInsidePreedit(int cursor)
+void QWaylandTextInputv3::setCursorInsidePreedit(int cursor)
{
Q_UNUSED(cursor);
- qCWarning(qLcQpaWaylandTextInput) << "QWaylandTextInputV4: Input protocol \"text-input-unstable-v4-wip\" does not support setting cursor inside preedit. Use qt-text-input-method-unstable-v1 instead for full support of Qt input method events.";
}
-bool QWaylandTextInputv4::isInputPanelVisible() const
+bool QWaylandTextInputv3::isInputPanelVisible() const
{
- qCWarning(qLcQpaWaylandTextInput) << "QWaylandTextInputV4: Input protocol \"text-input-unstable-v4-wip\" does not support querying input method visibility. Use qt-text-input-method-unstable-v1 instead for full support of Qt input method events.";
return false;
}
-QRectF QWaylandTextInputv4::keyboardRect() const
+QRectF QWaylandTextInputv3::keyboardRect() const
{
qCDebug(qLcQpaWaylandTextInput) << Q_FUNC_INFO;
return m_cursorRect;
}
-QLocale QWaylandTextInputv4::locale() const
+QLocale QWaylandTextInputv3::locale() const
{
- qCWarning(qLcQpaWaylandTextInput) << "QWaylandTextInputV4: Input protocol \"text-input-unstable-v4-wip\" does not support querying input language. Use qt-text-input-method-unstable-v1 instead for full support of Qt input method events.";
return QLocale();
}
-Qt::LayoutDirection QWaylandTextInputv4::inputDirection() const
+Qt::LayoutDirection QWaylandTextInputv3::inputDirection() const
{
- qCWarning(qLcQpaWaylandTextInput) << "QWaylandTextInputV4: Input protocol \"text-input-unstable-v4-wip\" does not support querying input direction. Use qt-text-input-method-unstable-v1 instead for full support of Qt input method events.";
return Qt::LeftToRight;
}
diff --git a/src/client/qwaylandtextinputv4_p.h b/src/client/qwaylandtextinputv3_p.h
index cad6d6c32..e8b7aa027 100644
--- a/src/client/qwaylandtextinputv4_p.h
+++ b/src/client/qwaylandtextinputv3_p.h
@@ -1,8 +1,8 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QWAYLANDTEXTINPUTV4_P_H
-#define QWAYLANDTEXTINPUTV4_P_H
+#ifndef QWAYLANDTEXTINPUTV3_P_H
+#define QWAYLANDTEXTINPUTV3_P_H
//
// W A R N I N G
@@ -16,8 +16,9 @@
//
#include "qwaylandtextinputinterface_p.h"
-#include <QtWaylandClient/private/qwayland-text-input-unstable-v4-wip.h>
+#include <QtWaylandClient/private/qwayland-text-input-unstable-v3.h>
#include <qwaylandinputmethodeventbuilder_p.h>
+#include <QLoggingCategory>
struct wl_callback;
struct wl_callback_listener;
@@ -30,11 +31,11 @@ namespace QtWaylandClient {
class QWaylandDisplay;
-class QWaylandTextInputv4 : public QtWayland::zwp_text_input_v4, public QWaylandTextInputInterface
+class QWaylandTextInputv3 : public QtWayland::zwp_text_input_v3, public QWaylandTextInputInterface
{
public:
- QWaylandTextInputv4(QWaylandDisplay *display, struct ::zwp_text_input_v4 *text_input);
- ~QWaylandTextInputv4() override;
+ QWaylandTextInputv3(QWaylandDisplay *display, struct ::zwp_text_input_v3 *text_input);
+ ~QWaylandTextInputv3() override;
void reset() override;
void commit() override;
@@ -48,19 +49,20 @@ public:
QLocale locale() const override;
Qt::LayoutDirection inputDirection() const override;
- void enableSurface(::wl_surface *surface) override;
- void disableSurface(::wl_surface *surface) override;
+ // doing nothing in zwp_text_input_v3.
+ // enter() and leave() takes the role to enable/disable the surface
+ void enableSurface(::wl_surface *) override {};
+ void disableSurface(::wl_surface *) override {};
protected:
- void zwp_text_input_v4_enter(struct ::wl_surface *surface) override;
- void zwp_text_input_v4_leave(struct ::wl_surface *surface) override;
- void zwp_text_input_v4_preedit_string(const QString &text, int32_t cursor_begin, int32_t cursor_end) override;
- void zwp_text_input_v4_commit_string(const QString &text) override;
- void zwp_text_input_v4_delete_surrounding_text(uint32_t before_length, uint32_t after_length) override;
- void zwp_text_input_v4_done(uint32_t serial) override;
+ void zwp_text_input_v3_enter(struct ::wl_surface *surface) override;
+ void zwp_text_input_v3_leave(struct ::wl_surface *surface) override;
+ void zwp_text_input_v3_preedit_string(const QString &text, int32_t cursor_begin, int32_t cursor_end) override;
+ void zwp_text_input_v3_commit_string(const QString &text) override;
+ void zwp_text_input_v3_delete_surrounding_text(uint32_t before_length, uint32_t after_length) override;
+ void zwp_text_input_v3_done(uint32_t serial) override;
private:
- QWaylandDisplay *m_display;
QWaylandInputMethodEventBuilder m_builder;
::wl_surface *m_surface = nullptr; // ### Here for debugging purposes
@@ -100,4 +102,4 @@ private:
QT_END_NAMESPACE
-#endif // QWAYLANDTEXTINPUTV4_P_H
+#endif // QWAYLANDTEXTINPUTV3_P_H
diff --git a/src/client/qwaylandtouch.cpp b/src/client/qwaylandtouch.cpp
index 41dfd0855..dfd04d446 100644
--- a/src/client/qwaylandtouch.cpp
+++ b/src/client/qwaylandtouch.cpp
@@ -23,6 +23,11 @@ QWaylandTouchExtension::QWaylandTouchExtension(QWaylandDisplay *display, uint32_
{
}
+QWaylandTouchExtension::~QWaylandTouchExtension()
+{
+ qt_touch_extension_destroy(object());
+}
+
void QWaylandTouchExtension::registerDevice(int caps)
{
// TODO number of touchpoints, actual name and ID
@@ -107,12 +112,12 @@ void QWaylandTouchExtension::touch_extension_touch(uint32_t time,
void QWaylandTouchExtension::sendTouchEvent()
{
// Copy all points, that are in the previous but not in the current list, as stationary.
- for (int i = 0; i < mPrevTouchPoints.count(); ++i) {
+ for (int i = 0; i < mPrevTouchPoints.size(); ++i) {
const QWindowSystemInterface::TouchPoint &prevPoint(mPrevTouchPoints.at(i));
if (prevPoint.state == QEventPoint::Released)
continue;
bool found = false;
- for (int j = 0; j < mTouchPoints.count(); ++j)
+ for (int j = 0; j < mTouchPoints.size(); ++j)
if (mTouchPoints.at(j).id == prevPoint.id) {
found = true;
break;
@@ -132,14 +137,14 @@ void QWaylandTouchExtension::sendTouchEvent()
QWindowSystemInterface::handleTouchEvent(mTargetWindow, mTimestamp, mTouchDevice, mTouchPoints);
QEventPoint::States states = {};
- for (int i = 0; i < mTouchPoints.count(); ++i)
+ for (int i = 0; i < mTouchPoints.size(); ++i)
states |= mTouchPoints.at(i).state;
if (mFlags & QT_TOUCH_EXTENSION_FLAGS_MOUSE_FROM_TOUCH) {
const bool firstPress = states == QEventPoint::Pressed;
if (firstPress)
mMouseSourceId = mTouchPoints.first().id;
- for (int i = 0; i < mTouchPoints.count(); ++i) {
+ for (int i = 0; i < mTouchPoints.size(); ++i) {
const QWindowSystemInterface::TouchPoint &tp(mTouchPoints.at(i));
if (tp.id == mMouseSourceId) {
const bool released = tp.state == QEventPoint::Released;
diff --git a/src/client/qwaylandtouch_p.h b/src/client/qwaylandtouch_p.h
index 8927f4e7e..e283f9009 100644
--- a/src/client/qwaylandtouch_p.h
+++ b/src/client/qwaylandtouch_p.h
@@ -32,6 +32,7 @@ class Q_WAYLANDCLIENT_EXPORT QWaylandTouchExtension : public QtWayland::qt_touch
{
public:
QWaylandTouchExtension(QWaylandDisplay *display, uint32_t id);
+ ~QWaylandTouchExtension() override;
void touchCanceled();
diff --git a/src/client/qwaylandviewport.cpp b/src/client/qwaylandviewport.cpp
new file mode 100644
index 000000000..3252718c0
--- /dev/null
+++ b/src/client/qwaylandviewport.cpp
@@ -0,0 +1,35 @@
+// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwaylandviewport_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+QWaylandViewport::QWaylandViewport(::wp_viewport *viewport)
+ : QtWayland::wp_viewport(viewport)
+{
+}
+
+QWaylandViewport::~QWaylandViewport()
+{
+ destroy();
+}
+
+void QWaylandViewport::setSource(const QRectF &source)
+{
+ set_source(wl_fixed_from_double(source.x()),
+ wl_fixed_from_double(source.y()),
+ wl_fixed_from_double(source.width()),
+ wl_fixed_from_double(source.height()));
+}
+
+void QWaylandViewport::setDestination(const QSize &destination)
+{
+ set_destination(destination.width(), destination.height());
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/client/qwaylandviewport_p.h b/src/client/qwaylandviewport_p.h
new file mode 100644
index 000000000..e1dfeb3a7
--- /dev/null
+++ b/src/client/qwaylandviewport_p.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWAYLANDVIEWPORT_P_H
+#define QWAYLANDVIEWPORT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtWaylandClient/private/qwayland-viewporter.h>
+#include <QtWaylandClient/qtwaylandclientglobal.h>
+
+#include <QRect>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+class QWaylandViewport : public QtWayland::wp_viewport
+{
+public:
+ explicit QWaylandViewport(::wp_viewport *viewport);
+ ~QWaylandViewport() override;
+
+ void setSource(const QRectF &source);
+ void setDestination(const QSize &destination);
+
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDVIEWPORT_P_H
diff --git a/src/client/qwaylandvulkaninstance.cpp b/src/client/qwaylandvulkaninstance.cpp
index 2f95ff307..be55130a4 100644
--- a/src/client/qwaylandvulkaninstance.cpp
+++ b/src/client/qwaylandvulkaninstance.cpp
@@ -101,6 +101,26 @@ void QWaylandVulkanInstance::presentAboutToBeQueued(QWindow *window)
w->handleUpdate();
}
+void QWaylandVulkanInstance::beginFrame(QWindow *window)
+{
+ auto *w = static_cast<QWaylandWindow *>(window->handle());
+ if (!w) {
+ qWarning() << "Attempted to call beginFrame() without a valid platform window";
+ return;
+ }
+ w->beginFrame();
+}
+
+void QWaylandVulkanInstance::endFrame(QWindow *window)
+{
+ auto *w = static_cast<QWaylandWindow *>(window->handle());
+ if (!w) {
+ qWarning() << "Attempted to call endFrame() without a valid platform window";
+ return;
+ }
+ w->endFrame();
+}
+
} // namespace QtWaylandClient
QT_END_NAMESPACE
diff --git a/src/client/qwaylandvulkaninstance_p.h b/src/client/qwaylandvulkaninstance_p.h
index abeca95db..7683ce566 100644
--- a/src/client/qwaylandvulkaninstance_p.h
+++ b/src/client/qwaylandvulkaninstance_p.h
@@ -42,6 +42,9 @@ public:
VkSurfaceKHR createSurface(QWaylandWindow *window);
+ void beginFrame(QWindow *window) override;
+ void endFrame(QWindow *window) override;
+
private:
QVulkanInstance *m_instance = nullptr;
PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR m_getPhysDevPresSupport = nullptr;
diff --git a/src/client/qwaylandvulkanwindow.cpp b/src/client/qwaylandvulkanwindow.cpp
index 228bf5ced..2bc52829d 100644
--- a/src/client/qwaylandvulkanwindow.cpp
+++ b/src/client/qwaylandvulkanwindow.cpp
@@ -14,11 +14,7 @@ QWaylandVulkanWindow::QWaylandVulkanWindow(QWindow *window, QWaylandDisplay *dis
QWaylandVulkanWindow::~QWaylandVulkanWindow()
{
- if (m_surface) {
- QVulkanInstance *inst = window()->vulkanInstance();
- if (inst)
- static_cast<QWaylandVulkanInstance *>(inst->handle())->destroySurface(m_surface);
- }
+ invalidateSurface();
}
QWaylandWindow::WindowType QWaylandVulkanWindow::windowType() const
@@ -26,7 +22,18 @@ QWaylandWindow::WindowType QWaylandVulkanWindow::windowType() const
return QWaylandWindow::Vulkan;
}
-VkSurfaceKHR *QWaylandVulkanWindow::surface()
+void QWaylandVulkanWindow::invalidateSurface()
+{
+ if (m_surface) {
+ QVulkanInstance *inst = window()->vulkanInstance();
+ if (inst)
+ static_cast<QWaylandVulkanInstance *>(inst->handle())->destroySurface(m_surface);
+ }
+ m_surface = VK_NULL_HANDLE;
+ QWaylandWindow::invalidateSurface();
+}
+
+VkSurfaceKHR *QWaylandVulkanWindow::vkSurface()
{
if (m_surface)
return &m_surface;
diff --git a/src/client/qwaylandvulkanwindow_p.h b/src/client/qwaylandvulkanwindow_p.h
index d71fb277c..c5692bc7f 100644
--- a/src/client/qwaylandvulkanwindow_p.h
+++ b/src/client/qwaylandvulkanwindow_p.h
@@ -29,8 +29,9 @@ public:
~QWaylandVulkanWindow() override;
WindowType windowType() const override;
+ void invalidateSurface() override;
- VkSurfaceKHR *surface();
+ VkSurfaceKHR *vkSurface();
private:
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
index a740559b7..081110f83 100644
--- a/src/client/qwaylandwindow.cpp
+++ b/src/client/qwaylandwindow.cpp
@@ -7,6 +7,7 @@
#include "qwaylanddisplay_p.h"
#include "qwaylandsurface_p.h"
#include "qwaylandinputdevice_p.h"
+#include "qwaylandfractionalscale_p.h"
#include "qwaylandscreen_p.h"
#include "qwaylandshellsurface_p.h"
#include "qwaylandsubsurface_p.h"
@@ -16,6 +17,7 @@
#include "qwaylanddecorationfactory_p.h"
#include "qwaylandshmbackingstore_p.h"
#include "qwaylandshellintegration_p.h"
+#include "qwaylandviewport_p.h"
#include <QtCore/QFileInfo>
#include <QtCore/QPointer>
@@ -24,23 +26,31 @@
#include <QGuiApplication>
#include <qpa/qwindowsysteminterface.h>
+#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qwindow_p.h>
#include <QtCore/QDebug>
#include <QtCore/QThread>
+#include <QtCore/private/qthread_p.h>
+
+#include <QtWaylandClient/private/qwayland-fractional-scale-v1.h>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
namespace QtWaylandClient {
Q_LOGGING_CATEGORY(lcWaylandBackingstore, "qt.qpa.wayland.backingstore")
QWaylandWindow *QWaylandWindow::mMouseGrab = nullptr;
+QWaylandWindow *QWaylandWindow::mTopPopup = nullptr;
QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
: QPlatformWindow(window)
, mDisplay(display)
, mSurfaceLock(QReadWriteLock::Recursive)
+ , mShellIntegration(display->shellIntegration())
, mResizeAfterSwap(qEnvironmentVariableIsSet("QT_WAYLAND_RESIZE_AFTER_SWAP"))
{
{
@@ -55,6 +65,11 @@ QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
static WId id = 1;
mWindowId = id++;
initializeWlSurface();
+
+ connect(this, &QWaylandWindow::wlSurfaceCreated, this,
+ &QNativeInterface::Private::QWaylandWindow::surfaceCreated);
+ connect(this, &QWaylandWindow::wlSurfaceDestroyed, this,
+ &QNativeInterface::Private::QWaylandWindow::surfaceDestroyed);
}
QWaylandWindow::~QWaylandWindow()
@@ -78,8 +93,10 @@ QWaylandWindow::~QWaylandWindow()
void QWaylandWindow::ensureSize()
{
- if (mBackingStore)
- mBackingStore->ensureSize();
+ if (mBackingStore) {
+ setBackingStore(mBackingStore);
+ mBackingStore->recreateBackBufferIfNeeded();
+ }
}
void QWaylandWindow::initWindow()
@@ -91,37 +108,63 @@ void QWaylandWindow::initWindow()
initializeWlSurface();
}
+ if (mDisplay->fractionalScaleManager() && qApp->highDpiScaleFactorRoundingPolicy() == Qt::HighDpiScaleFactorRoundingPolicy::PassThrough) {
+ mFractionalScale.reset(new QWaylandFractionalScale(mDisplay->fractionalScaleManager()->get_fractional_scale(mSurface->object())));
+
+ connect(mFractionalScale.data(), &QWaylandFractionalScale::preferredScaleChanged,
+ this, &QWaylandWindow::updateScale);
+ }
+
if (shouldCreateSubSurface()) {
Q_ASSERT(!mSubSurfaceWindow);
auto *parent = static_cast<QWaylandWindow *>(QPlatformWindow::parent());
+ if (!parent->mSurface)
+ parent->initializeWlSurface();
if (parent->wlSurface()) {
if (::wl_subsurface *subsurface = mDisplay->createSubSurface(this, parent))
mSubSurfaceWindow = new QWaylandSubSurface(this, parent, subsurface);
}
} else if (shouldCreateShellSurface()) {
Q_ASSERT(!mShellSurface);
- Q_ASSERT(mDisplay->shellIntegration());
+ Q_ASSERT(mShellIntegration);
+ mTransientParent = guessTransientParent();
+ if (mTransientParent) {
+ if (window()->type() == Qt::Popup) {
+ if (mTopPopup && mTopPopup != mTransientParent) {
+ qCWarning(lcQpaWayland) << "Creating a popup with a parent," << mTransientParent->window()
+ << "which does not match the current topmost grabbing popup,"
+ << mTopPopup->window() << "With some shell surface protocols, this"
+ << "is not allowed. The wayland QPA plugin is currently handling"
+ << "it by setting the parent to the topmost grabbing popup."
+ << "Note, however, that this may cause positioning errors and"
+ << "popups closing unxpectedly. Please fix the transient parent of the popup.";
+ mTransientParent = mTopPopup;
+ }
+ mTopPopup = this;
+ }
+ }
- mShellSurface = mDisplay->shellIntegration()->createShellSurface(this);
+ mShellSurface = mShellIntegration->createShellSurface(this);
if (mShellSurface) {
+ if (mTransientParent) {
+ if (window()->type() == Qt::ToolTip || window()->type() == Qt::Popup)
+ mTransientParent->addChildPopup(this);
+ }
+
// Set initial surface title
setWindowTitle(window()->title());
// The appId is the desktop entry identifier that should follow the
- // reverse DNS convention (see http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s02.html).
- // According to xdg-shell the appId is only the name, without
- // the .desktop suffix.
+ // reverse DNS convention (see
+ // http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s02.html). According
+ // to xdg-shell the appId is only the name, without the .desktop suffix.
//
- // If the application specifies the desktop file name use that
- // removing the ".desktop" suffix, otherwise fall back to the
- // executable name and prepend the reversed organization domain
- // when available.
+ // If the application specifies the desktop file name use that,
+ // otherwise fall back to the executable name and prepend the
+ // reversed organization domain when available.
if (!QGuiApplication::desktopFileName().isEmpty()) {
- QString name = QGuiApplication::desktopFileName();
- if (name.endsWith(QLatin1String(".desktop")))
- name.chop(8);
- mShellSurface->setAppId(name);
+ mShellSurface->setAppId(QGuiApplication::desktopFileName());
} else {
QFileInfo fi = QFileInfo(QCoreApplication::instance()->applicationFilePath());
QStringList domainName =
@@ -132,7 +175,7 @@ void QWaylandWindow::initWindow()
mShellSurface->setAppId(fi.baseName());
} else {
QString appId;
- for (int i = 0; i < domainName.count(); ++i)
+ for (int i = 0; i < domainName.size(); ++i)
appId.prepend(QLatin1Char('.')).prepend(domainName.at(i));
appId.append(fi.baseName());
mShellSurface->setAppId(appId);
@@ -141,16 +184,26 @@ void QWaylandWindow::initWindow()
// the user may have already set some window properties, so make sure to send them out
for (auto it = m_properties.cbegin(); it != m_properties.cend(); ++it)
mShellSurface->sendProperty(it.key(), it.value());
+
+ emit surfaceRoleCreated();
} else {
qWarning("Could not create a shell surface object.");
}
}
+ // The fractional scale manager check is needed to work around Gnome < 36 where viewports don't work
+ // Right now viewports are only necessary when a fractional scale manager is used
+ if (display()->viewporter() && display()->fractionalScaleManager()) {
+ mViewport.reset(new QWaylandViewport(display()->createViewport(this)));
+ }
+
// Enable high-dpi rendering. Scale() returns the screen scale factor and will
// typically be integer 1 (normal-dpi) or 2 (high-dpi). Call set_buffer_scale()
// to inform the compositor that high-resolution buffers will be provided.
- if (mSurface->version() >= 3)
- mSurface->set_buffer_scale(mScale);
+ if (mViewport)
+ updateViewport();
+ else if (mSurface->version() >= 3)
+ mSurface->set_buffer_scale(std::ceil(scale()));
setWindowFlags(window()->flags());
QRect geometry = windowGeometry();
@@ -166,6 +219,8 @@ void QWaylandWindow::initWindow()
mShellSurface->requestWindowStates(window()->windowStates());
handleContentOrientationChange(window()->contentOrientation());
mFlags = window()->flags();
+
+ mSurface->commit();
}
void QWaylandWindow::initializeWlSurface()
@@ -176,14 +231,28 @@ void QWaylandWindow::initializeWlSurface()
mSurface.reset(new QWaylandSurface(mDisplay));
connect(mSurface.data(), &QWaylandSurface::screensChanged,
this, &QWaylandWindow::handleScreensChanged);
+ connect(mSurface.data(), &QWaylandSurface::preferredBufferScaleChanged,
+ this, &QWaylandWindow::updateScale);
+ connect(mSurface.data(), &QWaylandSurface::preferredBufferTransformChanged,
+ this, &QWaylandWindow::updateBufferTransform);
mSurface->m_window = this;
}
emit wlSurfaceCreated();
}
+void QWaylandWindow::setShellIntegration(QWaylandShellIntegration *shellIntegration)
+{
+ Q_ASSERT(shellIntegration);
+ if (mShellSurface) {
+ qCWarning(lcQpaWayland) << "Cannot set shell integration while there's already a shell surface created";
+ return;
+ }
+ mShellIntegration = shellIntegration;
+}
+
bool QWaylandWindow::shouldCreateShellSurface() const
{
- if (!mDisplay->shellIntegration())
+ if (!shellIntegration())
return false;
if (shouldCreateSubSurface())
@@ -215,30 +284,61 @@ void QWaylandWindow::endFrame()
void QWaylandWindow::reset()
{
- delete mShellSurface;
- mShellSurface = nullptr;
- delete mSubSurfaceWindow;
- mSubSurfaceWindow = nullptr;
+ closeChildPopups();
+
+ if (mTopPopup == this)
+ mTopPopup = mTransientParent && (mTransientParent->window()->type() == Qt::Popup) ? mTransientParent : nullptr;
if (mSurface) {
+ {
+ QWriteLocker lock(&mSurfaceLock);
+ invalidateSurface();
+ if (mTransientParent)
+ mTransientParent->removeChildPopup(this);
+ delete mShellSurface;
+ mShellSurface = nullptr;
+ emit surfaceRoleDestroyed();
+ delete mSubSurfaceWindow;
+ mSubSurfaceWindow = nullptr;
+ mTransientParent = nullptr;
+ mSurface.reset();
+ mViewport.reset();
+ mFractionalScale.reset();
+ }
emit wlSurfaceDestroyed();
- QWriteLocker lock(&mSurfaceLock);
- invalidateSurface();
- mSurface.reset();
}
- if (mFrameCallback) {
- wl_callback_destroy(mFrameCallback);
- mFrameCallback = nullptr;
+ {
+ QMutexLocker lock(&mFrameSyncMutex);
+ if (mFrameCallback) {
+ wl_callback_destroy(mFrameCallback);
+ mFrameCallback = nullptr;
+ }
+
+ mFrameCallbackElapsedTimer.invalidate();
+ mWaitingForFrameCallback = false;
+ }
+ if (mFrameCallbackCheckIntervalTimerId != -1) {
+ killTimer(mFrameCallbackCheckIntervalTimerId);
+ mFrameCallbackCheckIntervalTimerId = -1;
}
- mFrameCallbackElapsedTimer.invalidate();
- mWaitingForFrameCallback = false;
mFrameCallbackTimedOut = false;
mWaitingToApplyConfigure = false;
+ mCanResize = true;
+ mResizeDirty = false;
+ mOpaqueArea = QRegion();
mMask = QRegion();
+
+ mInputRegion = QRegion();
+ mTransparentInputRegion = false;
+
+ if (mQueuedBuffer) {
+ mQueuedBuffer->setBusy(false);
+ }
mQueuedBuffer = nullptr;
+ mQueuedBufferDamage = QRegion();
mDisplay->handleWindowDestroyed(this);
}
@@ -274,26 +374,33 @@ void QWaylandWindow::setParent(const QPlatformWindow *parent)
}
}
+QString QWaylandWindow::windowTitle() const
+{
+ return mWindowTitle;
+}
+
void QWaylandWindow::setWindowTitle(const QString &title)
{
- if (mShellSurface) {
- const QString separator = QString::fromUtf8(" \xe2\x80\x94 "); // unicode character U+2014, EM DASH
- const QString formatted = formatWindowTitle(title, separator);
-
- const int libwaylandMaxBufferSize = 4096;
- // Some parts of the buffer is used for metadata, so subtract 100 to be on the safe side.
- // Also, QString is in utf-16, which means that in the worst case each character will be
- // three bytes when converted to utf-8 (which is what libwayland uses), so divide by three.
- const int maxLength = libwaylandMaxBufferSize / 3 - 100;
-
- auto truncated = QStringView{formatted}.left(maxLength);
- if (truncated.length() < formatted.length()) {
- qCWarning(lcQpaWayland) << "Window titles longer than" << maxLength << "characters are not supported."
- << "Truncating window title (from" << formatted.length() << "chars)";
- }
- mShellSurface->setTitle(truncated.toString());
+ const QString separator = QString::fromUtf8(" \xe2\x80\x94 "); // unicode character U+2014, EM DASH
+ const QString formatted = formatWindowTitle(title, separator);
+
+ const int libwaylandMaxBufferSize = 4096;
+ // Some parts of the buffer is used for metadata, so subtract 100 to be on the safe side.
+ // Also, QString is in utf-16, which means that in the worst case each character will be
+ // three bytes when converted to utf-8 (which is what libwayland uses), so divide by three.
+ const int maxLength = libwaylandMaxBufferSize / 3 - 100;
+
+ auto truncated = QStringView{formatted}.left(maxLength);
+ if (truncated.size() < formatted.size()) {
+ qCWarning(lcQpaWayland) << "Window titles longer than" << maxLength << "characters are not supported."
+ << "Truncating window title (from" << formatted.size() << "chars)";
}
+ mWindowTitle = truncated.toString();
+
+ if (mShellSurface)
+ mShellSurface->setTitle(mWindowTitle);
+
if (mWindowDecorationEnabled && window()->isVisible())
mWindowDecoration->update();
}
@@ -313,11 +420,9 @@ QRect QWaylandWindow::defaultGeometry() const
void QWaylandWindow::setGeometry_helper(const QRect &rect)
{
- QSize minimum = windowMinimumSize();
- QSize maximum = windowMaximumSize();
- QPlatformWindow::setGeometry(QRect(rect.x(), rect.y(),
- qBound(minimum.width(), rect.width(), maximum.width()),
- qBound(minimum.height(), rect.height(), maximum.height())));
+ QPlatformWindow::setGeometry(rect);
+ if (mViewport)
+ updateViewport();
if (mSubSurfaceWindow) {
QMargins m = static_cast<QWaylandWindow *>(QPlatformWindow::parent())->clientSideMargins();
@@ -356,7 +461,7 @@ void QWaylandWindow::setGeometry(const QRect &r)
if (isExposed() && !mInResizeFromApplyConfigure && exposeGeometry != mLastExposeGeometry)
sendExposeEvent(exposeGeometry);
- if (mShellSurface && isExposed()) {
+ if (mShellSurface) {
mShellSurface->setWindowGeometry(windowContentGeometry());
if (!qt_window_private(window())->positionAutomatic)
mShellSurface->setWindowPosition(windowGeometry().topLeft());
@@ -366,6 +471,38 @@ void QWaylandWindow::setGeometry(const QRect &r)
setOpaqueArea(QRect(QPoint(0, 0), rect.size()));
}
+void QWaylandWindow::updateInputRegion()
+{
+ if (!mSurface)
+ return;
+
+ const bool transparentInputRegion = mFlags.testFlag(Qt::WindowTransparentForInput);
+
+ QRegion inputRegion;
+ if (!transparentInputRegion)
+ inputRegion = mMask;
+
+ if (mInputRegion == inputRegion && mTransparentInputRegion == transparentInputRegion)
+ return;
+
+ mInputRegion = inputRegion;
+ mTransparentInputRegion = transparentInputRegion;
+
+ if (mInputRegion.isEmpty() && !mTransparentInputRegion) {
+ mSurface->set_input_region(nullptr);
+ } else {
+ struct ::wl_region *region = mDisplay->createRegion(mInputRegion);
+ mSurface->set_input_region(region);
+ wl_region_destroy(region);
+ }
+}
+
+void QWaylandWindow::updateViewport()
+{
+ if (!surfaceSize().isEmpty())
+ mViewport->setDestination(surfaceSize());
+}
+
void QWaylandWindow::setGeometryFromApplyConfigure(const QPoint &globalPosition, const QSize &sizeWithMargins)
{
QMargins margins = clientSideMargins();
@@ -395,20 +532,9 @@ void QWaylandWindow::repositionFromApplyConfigure(const QPoint &globalPosition)
void QWaylandWindow::resizeFromApplyConfigure(const QSize &sizeWithMargins, const QPoint &offset)
{
QMargins margins = clientSideMargins();
-
- // Exclude shadows from margins once they are excluded from window geometry
- // 1) First resizeFromApplyConfigure() call will have sizeWithMargins equal to surfaceSize()
- // which has full margins (shadows included).
- // 2) Following resizeFromApplyConfigure() calls should have sizeWithMargins equal to
- // windowContentGeometry() which excludes shadows, therefore in this case we have to
- // exclude them too in order not to accidentally apply smaller size to the window.
- if (mWindowDecorationEnabled && (sizeWithMargins != surfaceSize()))
- margins = mWindowDecoration->margins(QWaylandAbstractDecoration::ShadowsExcluded);
-
int widthWithoutMargins = qMax(sizeWithMargins.width() - (margins.left() + margins.right()), 1);
int heightWithoutMargins = qMax(sizeWithMargins.height() - (margins.top() + margins.bottom()), 1);
- QRect geometry(windowGeometry().topLeft() + QPoint(margins.left(), margins.top()),
- QSize(widthWithoutMargins, heightWithoutMargins));
+ QRect geometry(windowGeometry().topLeft(), QSize(widthWithoutMargins, heightWithoutMargins));
mOffset += offset;
mInResizeFromApplyConfigure = true;
@@ -425,20 +551,6 @@ void QWaylandWindow::sendExposeEvent(const QRect &rect)
mLastExposeGeometry = rect;
}
-static QList<QPointer<QWaylandWindow>> activePopups;
-
-void QWaylandWindow::closePopups(QWaylandWindow *parent)
-{
- while (!activePopups.isEmpty()) {
- auto popup = activePopups.takeLast();
- if (popup.isNull())
- continue;
- if (popup.data() == parent)
- return;
- popup->reset();
- }
-}
-
QPlatformScreen *QWaylandWindow::calculateScreenFromSurfaceEvents() const
{
QReadLocker lock(&mSurfaceLock);
@@ -458,17 +570,17 @@ void QWaylandWindow::setVisible(bool visible)
lastVisible = visible;
if (visible) {
- if (window()->type() == Qt::Popup || window()->type() == Qt::ToolTip)
- activePopups << this;
initWindow();
setGeometry(windowGeometry());
// Don't flush the events here, or else the newly visible window may start drawing, but since
// there was no frame before it will be stuck at the waitForFrameSync() in
// QWaylandShmBackingStore::beginPaint().
+
+ if (mShellSurface)
+ mShellSurface->requestActivateOnShow();
} else {
sendExposeEvent(QRect());
- closePopups(this);
reset();
}
}
@@ -498,21 +610,28 @@ void QWaylandWindow::setMask(const QRegion &mask)
mMask = mask;
- if (mMask.isEmpty()) {
- mSurface->set_input_region(nullptr);
+ updateInputRegion();
- if (isOpaque())
+ if (isOpaque()) {
+ if (mMask.isEmpty())
setOpaqueArea(QRect(QPoint(0, 0), geometry().size()));
- } else {
- struct ::wl_region *region = mDisplay->createRegion(mMask);
- mSurface->set_input_region(region);
- wl_region_destroy(region);
-
- if (isOpaque())
+ else
setOpaqueArea(mMask);
}
+}
- mSurface->commit();
+void QWaylandWindow::setAlertState(bool enabled)
+{
+ if (mShellSurface)
+ mShellSurface->setAlertState(enabled);
+}
+
+bool QWaylandWindow::isAlertState() const
+{
+ if (mShellSurface)
+ return mShellSurface->isAlertState();
+
+ return false;
}
void QWaylandWindow::applyConfigureWhenPossible()
@@ -529,12 +648,24 @@ void QWaylandWindow::doApplyConfigure()
if (!mWaitingToApplyConfigure)
return;
+ Q_ASSERT_X(QThread::currentThreadId() == QThreadData::get2(thread())->threadId.loadRelaxed(),
+ "QWaylandWindow::doApplyConfigure", "not called from main thread");
+
if (mShellSurface)
mShellSurface->applyConfigure();
mWaitingToApplyConfigure = false;
}
+void QWaylandWindow::doApplyConfigureFromOtherThread()
+{
+ QMutexLocker lock(&mResizeLock);
+ if (!mCanResize || !mWaitingToApplyConfigure)
+ return;
+ doApplyConfigure();
+ sendRecursiveExposeEvent();
+}
+
void QWaylandWindow::setCanResize(bool canResize)
{
QMutexLocker lock(&mResizeLock);
@@ -545,8 +676,13 @@ void QWaylandWindow::setCanResize(bool canResize)
QWindowSystemInterface::handleGeometryChange(window(), geometry());
}
if (mWaitingToApplyConfigure) {
- doApplyConfigure();
- sendExposeEvent(QRect(QPoint(), geometry().size()));
+ bool inGuiThread = QThread::currentThreadId() == QThreadData::get2(thread())->threadId.loadRelaxed();
+ if (inGuiThread) {
+ doApplyConfigure();
+ sendRecursiveExposeEvent();
+ } else {
+ QMetaObject::invokeMethod(this, &QWaylandWindow::doApplyConfigureFromOtherThread, Qt::QueuedConnection);
+ }
} else if (mResizeDirty) {
mResizeDirty = false;
sendExposeEvent(QRect(QPoint(), geometry().size()));
@@ -568,11 +704,12 @@ void QWaylandWindow::applyConfigure()
void QWaylandWindow::sendRecursiveExposeEvent()
{
- if (!window()->isVisible())
- return;
- sendExposeEvent(QRect(QPoint(), geometry().size()));
+ if (!isExposed())
+ sendExposeEvent(QRect());
+ else
+ sendExposeEvent(QRect(QPoint(), geometry().size()));
- for (QWaylandSubSurface *subSurface : qAsConst(mChildren)) {
+ for (QWaylandSubSurface *subSurface : std::as_const(mChildren)) {
auto subWindow = subSurface->window();
subWindow->sendRecursiveExposeEvent();
}
@@ -587,9 +724,13 @@ void QWaylandWindow::attach(QWaylandBuffer *buffer, int x, int y)
if (buffer) {
Q_ASSERT(!buffer->committed());
handleUpdate();
- buffer->setBusy();
-
- mSurface->attach(buffer->buffer(), x, y);
+ buffer->setBusy(true);
+ if (mSurface->version() >= WL_SURFACE_OFFSET_SINCE_VERSION) {
+ mSurface->offset(x, y);
+ mSurface->attach(buffer->buffer(), 0, 0);
+ } else {
+ mSurface->attach(buffer->buffer(), x, y);
+ }
} else {
mSurface->attach(nullptr, 0, 0);
}
@@ -608,10 +749,15 @@ void QWaylandWindow::damage(const QRect &rect)
return;
const qreal s = scale();
- if (mSurface->version() >= 4)
- mSurface->damage_buffer(qFloor(s * rect.x()), qFloor(s * rect.y()), qCeil(s * rect.width()), qCeil(s * rect.height()));
- else
+ if (mSurface->version() >= 4) {
+ const QRect bufferRect =
+ QRectF(s * rect.x(), s * rect.y(), s * rect.width(), s * rect.height())
+ .toAlignedRect();
+ mSurface->damage_buffer(bufferRect.x(), bufferRect.y(), bufferRect.width(),
+ bufferRect.height());
+ } else {
mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
+ }
}
void QWaylandWindow::safeCommit(QWaylandBuffer *buffer, const QRegion &damage)
@@ -619,21 +765,15 @@ void QWaylandWindow::safeCommit(QWaylandBuffer *buffer, const QRegion &damage)
if (isExposed()) {
commit(buffer, damage);
} else {
+ if (mQueuedBuffer) {
+ mQueuedBuffer->setBusy(false);
+ }
mQueuedBuffer = buffer;
+ mQueuedBuffer->setBusy(true);
mQueuedBufferDamage = damage;
}
}
-void QWaylandWindow::handleExpose(const QRegion &region)
-{
- QWindowSystemInterface::handleExposeEvent(window(), region);
- if (mQueuedBuffer) {
- commit(mQueuedBuffer, mQueuedBufferDamage);
- mQueuedBuffer = nullptr;
- mQueuedBufferDamage = QRegion();
- }
-}
-
void QWaylandWindow::commit(QWaylandBuffer *buffer, const QRegion &damage)
{
Q_ASSERT(isExposed());
@@ -649,8 +789,13 @@ void QWaylandWindow::commit(QWaylandBuffer *buffer, const QRegion &damage)
attachOffset(buffer);
if (mSurface->version() >= 4) {
const qreal s = scale();
- for (const QRect &rect: damage)
- mSurface->damage_buffer(qFloor(s * rect.x()), qFloor(s * rect.y()), qCeil(s * rect.width()), qCeil(s * rect.height()));
+ for (const QRect &rect : damage) {
+ const QRect bufferRect =
+ QRectF(s * rect.x(), s * rect.y(), s * rect.width(), s * rect.height())
+ .toAlignedRect();
+ mSurface->damage_buffer(bufferRect.x(), bufferRect.y(), bufferRect.width(),
+ bufferRect.height());
+ }
} else {
for (const QRect &rect: damage)
mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height());
@@ -671,18 +816,21 @@ const wl_callback_listener QWaylandWindow::callbackListener = {
[](void *data, wl_callback *callback, uint32_t time) {
Q_UNUSED(time);
auto *window = static_cast<QWaylandWindow*>(data);
-
- Q_ASSERT(callback == window->mFrameCallback);
- wl_callback_destroy(callback);
- window->mFrameCallback = nullptr;
-
- window->handleFrameCallback();
+ window->handleFrameCallback(callback);
}
};
-void QWaylandWindow::handleFrameCallback()
+void QWaylandWindow::handleFrameCallback(wl_callback* callback)
{
QMutexLocker locker(&mFrameSyncMutex);
+ if (!mFrameCallback) {
+ // This means the callback is already unset by QWaylandWindow::reset.
+ // The wl_callback object will be destroyed there too.
+ return;
+ }
+ Q_ASSERT(callback == mFrameCallback);
+ wl_callback_destroy(callback);
+ mFrameCallback = nullptr;
mWaitingForFrameCallback = false;
mFrameCallbackElapsedTimer.invalidate();
@@ -740,6 +888,12 @@ QMargins QWaylandWindow::clientSideMargins() const
return mWindowDecorationEnabled ? mWindowDecoration->margins() : QMargins{};
}
+void QWaylandWindow::setCustomMargins(const QMargins &margins) {
+ const QMargins oldMargins = mCustomMargins;
+ mCustomMargins = margins;
+ setGeometry(geometry().marginsRemoved(oldMargins).marginsAdded(margins));
+}
+
/*!
* Size, with decorations (including including eventual shadows) in wl_surface coordinates
*/
@@ -748,18 +902,27 @@ QSize QWaylandWindow::surfaceSize() const
return geometry().marginsAdded(clientSideMargins()).size();
}
-/*!
- * Window geometry as defined by the xdg-shell spec (in wl_surface coordinates)
- * topLeft is where the shadow stops and the decorations border start.
- */
-QRect QWaylandWindow::windowContentGeometry() const
+QMargins QWaylandWindow::windowContentMargins() const
{
QMargins shadowMargins;
if (mWindowDecorationEnabled)
shadowMargins = mWindowDecoration->margins(QWaylandAbstractDecoration::ShadowsOnly);
- return QRect(QPoint(shadowMargins.left(), shadowMargins.top()), surfaceSize().shrunkBy(shadowMargins));
+ if (!mCustomMargins.isNull())
+ shadowMargins += mCustomMargins;
+
+ return shadowMargins;
+}
+
+/*!
+ * Window geometry as defined by the xdg-shell spec (in wl_surface coordinates)
+ * topLeft is where the shadow stops and the decorations border start.
+ */
+QRect QWaylandWindow::windowContentGeometry() const
+{
+ const QMargins margins = windowContentMargins();
+ return QRect(QPoint(margins.left(), margins.top()), surfaceSize().shrunkBy(margins));
}
/*!
@@ -775,7 +938,7 @@ QPointF QWaylandWindow::mapFromWlSurface(const QPointF &surfacePosition) const
return QPointF(surfacePosition.x() - margins.left(), surfacePosition.y() - margins.top());
}
-wl_surface *QWaylandWindow::wlSurface()
+wl_surface *QWaylandWindow::wlSurface() const
{
QReadLocker locker(&mSurfaceLock);
return mSurface ? mSurface->object() : nullptr;
@@ -786,6 +949,15 @@ QWaylandShellSurface *QWaylandWindow::shellSurface() const
return mShellSurface;
}
+std::any QWaylandWindow::_surfaceRole() const
+{
+ if (mSubSurfaceWindow)
+ return mSubSurfaceWindow->object();
+ if (mShellSurface)
+ return mShellSurface->surfaceRole();
+ return {};
+}
+
QWaylandSubSurface *QWaylandWindow::subSurfaceWindow() const
{
return mSubSurfaceWindow;
@@ -802,34 +974,50 @@ QWaylandScreen *QWaylandWindow::waylandScreen() const
void QWaylandWindow::handleContentOrientationChange(Qt::ScreenOrientation orientation)
{
+ mLastReportedContentOrientation = orientation;
+ updateBufferTransform();
+}
+
+void QWaylandWindow::updateBufferTransform()
+{
QReadLocker locker(&mSurfaceLock);
if (mSurface == nullptr || mSurface->version() < 2)
return;
wl_output_transform transform;
- bool isPortrait = window()->screen() && window()->screen()->primaryOrientation() == Qt::PortraitOrientation;
- switch (orientation) {
- case Qt::PrimaryOrientation:
- transform = WL_OUTPUT_TRANSFORM_NORMAL;
- break;
- case Qt::LandscapeOrientation:
- transform = isPortrait ? WL_OUTPUT_TRANSFORM_270 : WL_OUTPUT_TRANSFORM_NORMAL;
- break;
- case Qt::PortraitOrientation:
- transform = isPortrait ? WL_OUTPUT_TRANSFORM_NORMAL : WL_OUTPUT_TRANSFORM_90;
- break;
- case Qt::InvertedLandscapeOrientation:
- transform = isPortrait ? WL_OUTPUT_TRANSFORM_90 : WL_OUTPUT_TRANSFORM_180;
- break;
- case Qt::InvertedPortraitOrientation:
- transform = isPortrait ? WL_OUTPUT_TRANSFORM_180 : WL_OUTPUT_TRANSFORM_270;
- break;
- default:
- Q_UNREACHABLE();
+ Qt::ScreenOrientation screenOrientation = Qt::PrimaryOrientation;
+
+ if (mSurface->version() >= 6) {
+ const auto transform = mSurface->preferredBufferTransform().value_or(WL_OUTPUT_TRANSFORM_NORMAL);
+ if (auto screen = waylandScreen())
+ screenOrientation = screen->toScreenOrientation(transform, Qt::PrimaryOrientation);
+ } else {
+ if (auto screen = window()->screen())
+ screenOrientation = screen->primaryOrientation();
+ }
+
+ const bool isPortrait = (screenOrientation == Qt::PortraitOrientation);
+
+ switch (mLastReportedContentOrientation) {
+ case Qt::PrimaryOrientation:
+ transform = WL_OUTPUT_TRANSFORM_NORMAL;
+ break;
+ case Qt::LandscapeOrientation:
+ transform = isPortrait ? WL_OUTPUT_TRANSFORM_270 : WL_OUTPUT_TRANSFORM_NORMAL;
+ break;
+ case Qt::PortraitOrientation:
+ transform = isPortrait ? WL_OUTPUT_TRANSFORM_NORMAL : WL_OUTPUT_TRANSFORM_90;
+ break;
+ case Qt::InvertedLandscapeOrientation:
+ transform = isPortrait ? WL_OUTPUT_TRANSFORM_90 : WL_OUTPUT_TRANSFORM_180;
+ break;
+ case Qt::InvertedPortraitOrientation:
+ transform = isPortrait ? WL_OUTPUT_TRANSFORM_180 : WL_OUTPUT_TRANSFORM_270;
+ break;
+ default:
+ Q_UNREACHABLE();
}
mSurface->set_buffer_transform(transform);
- // set_buffer_transform is double buffered, we need to commit.
- mSurface->commit();
}
void QWaylandWindow::setOrientationMask(Qt::ScreenOrientations mask)
@@ -851,10 +1039,18 @@ void QWaylandWindow::setWindowFlags(Qt::WindowFlags flags)
mFlags = flags;
createDecoration();
+
+ QReadLocker locker(&mSurfaceLock);
+ updateInputRegion();
}
bool QWaylandWindow::createDecoration()
{
+ Q_ASSERT_X(QThread::currentThreadId() == QThreadData::get2(thread())->threadId.loadRelaxed(),
+ "QWaylandWindow::createDecoration", "not called from main thread");
+ // TODO: client side decorations do not work with Vulkan backend.
+ if (window()->surfaceType() == QSurface::VulkanSurface)
+ return false;
if (!mDisplay->supportsWindowDecoration())
return false;
@@ -905,6 +1101,22 @@ bool QWaylandWindow::createDecoration()
}
}
+ if (targetKey.isEmpty()) {
+ auto unixServices = dynamic_cast<QGenericUnixServices *>(
+ QGuiApplicationPrivate::platformIntegration()->services());
+ const QByteArray currentDesktop = unixServices->desktopEnvironment();
+ if (currentDesktop == "GNOME") {
+ if (decorations.contains("adwaita"_L1))
+ targetKey = "adwaita"_L1;
+ else if (decorations.contains("gnome"_L1))
+ targetKey = "gnome"_L1;
+ } else {
+ // Do not use Adwaita/GNOME decorations on other DEs
+ decorations.removeAll("adwaita"_L1);
+ decorations.removeAll("gnome"_L1);
+ }
+ }
+
if (targetKey.isEmpty())
targetKey = decorations.first(); // first come, first served.
@@ -923,13 +1135,16 @@ bool QWaylandWindow::createDecoration()
}
if (hadDecoration != mWindowDecorationEnabled) {
- for (QWaylandSubSurface *subsurf : qAsConst(mChildren)) {
+ for (QWaylandSubSurface *subsurf : std::as_const(mChildren)) {
QPoint pos = subsurf->window()->geometry().topLeft();
QMargins m = frameMargins();
subsurf->set_position(pos.x() + m.left(), pos.y() + m.top());
}
setGeometry(geometry());
+ // creating a decoration changes our margins which in turn change size hints
+ propagateSizeHints();
+
// This is a special case where the buffer is recreated, but since
// the content rect remains the same, the widgets remain the same
// size and are not redrawn, leaving the new buffer empty. As a simple
@@ -959,6 +1174,11 @@ static QWaylandWindow *closestShellSurfaceWindow(QWindow *window)
QWaylandWindow *QWaylandWindow::transientParent() const
{
+ return mTransientParent;
+}
+
+QWaylandWindow *QWaylandWindow::guessTransientParent() const
+{
// Take the closest window with a shell surface, since the transient parent may be a
// QWidgetWindow or some other window without a shell surface, which is then not able to
// get mouse events.
@@ -1001,7 +1221,7 @@ void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, const QWaylan
case QEvent::Wheel:
QWindowSystemInterface::handleWheelEvent(window(), e.timestamp, e.local, e.global,
e.pixelDelta, e.angleDelta, e.modifiers,
- e.phase, e.source, false);
+ e.phase, e.source, e.inverted);
break;
default:
Q_UNREACHABLE();
@@ -1162,11 +1382,11 @@ void QWaylandWindow::handleMouseEventWithDecoration(QWaylandInputDevice *inputDe
return;
}
- QMargins marg = frameMargins();
+ QMargins marg = clientSideMargins();
QRect windowRect(0 + marg.left(),
0 + marg.top(),
- geometry().size().width() - marg.right(),
- geometry().size().height() - marg.bottom());
+ geometry().size().width(),
+ geometry().size().height());
if (windowRect.contains(e.local.toPoint()) || mMousePressedInContentArea != Qt::NoButton) {
const QPointF localTranslated = mapFromWlSurface(e.local);
QPointF globalTranslated = e.global;
@@ -1192,7 +1412,7 @@ void QWaylandWindow::handleMouseEventWithDecoration(QWaylandInputDevice *inputDe
QWindowSystemInterface::handleWheelEvent(window(), e.timestamp,
localTranslated, globalTranslated,
e.pixelDelta, e.angleDelta, e.modifiers,
- e.phase, e.source, false);
+ e.phase, e.source, e.inverted);
break;
}
default:
@@ -1216,7 +1436,10 @@ void QWaylandWindow::handleScreensChanged()
if (newScreen == mLastReportedScreen)
return;
+ if (!newScreen->isPlaceholder() && !newScreen->QPlatformScreen::screen())
+ mDisplay->forceRoundTrip();
QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen());
+
mLastReportedScreen = newScreen;
if (fixedToplevelPositions && !QPlatformWindow::parent() && window()->type() != Qt::Popup
&& window()->type() != Qt::ToolTip
@@ -1226,12 +1449,50 @@ void QWaylandWindow::handleScreensChanged()
setGeometry(geometry);
}
- int scale = newScreen->isPlaceholder() ? 1 : static_cast<QWaylandScreen *>(newScreen)->scale();
- if (scale != mScale) {
- mScale = scale;
- if (mSurface && mSurface->version() >= 3)
- mSurface->set_buffer_scale(mScale);
- ensureSize();
+ updateScale();
+ updateBufferTransform();
+}
+
+void QWaylandWindow::updateScale()
+{
+ if (mFractionalScale) {
+ auto preferredScale = mFractionalScale->preferredScale().value_or(1.0);
+ preferredScale = std::max(1.0, preferredScale);
+ Q_ASSERT(mViewport);
+ setScale(preferredScale);
+ return;
+ }
+
+ if (mSurface && mSurface->version() >= 6) {
+ auto preferredScale = mSurface->preferredBufferScale().value_or(1);
+ preferredScale = std::max(1, preferredScale);
+ setScale(preferredScale);
+ return;
+ }
+
+ int scale = mLastReportedScreen->isPlaceholder() ? 1 : static_cast<QWaylandScreen *>(mLastReportedScreen)->scale();
+ setScale(scale);
+}
+
+void QWaylandWindow::setScale(qreal newScale)
+{
+ if (qFuzzyCompare(mScale, newScale))
+ return;
+ mScale = newScale;
+
+ QWindowSystemInterface::handleWindowDevicePixelRatioChanged(window());
+ if (mSurface) {
+ if (mViewport)
+ updateViewport();
+ else if (mSurface->version() >= 3)
+ mSurface->set_buffer_scale(std::ceil(mScale));
+ }
+ ensureSize();
+
+ if (isExposed()) {
+ // redraw at the new DPR
+ window()->requestUpdate();
+ sendExposeEvent(QRect(QPoint(), geometry().size()));
}
}
@@ -1244,7 +1505,10 @@ void QWaylandWindow::setMouseCursor(QWaylandInputDevice *device, const QCursor &
void QWaylandWindow::restoreMouseCursor(QWaylandInputDevice *device)
{
- setMouseCursor(device, window()->cursor());
+ if (const QCursor *overrideCursor = QGuiApplication::overrideCursor())
+ setMouseCursor(device, *overrideCursor);
+ else
+ setMouseCursor(device, window()->cursor());
}
#endif
@@ -1355,24 +1619,36 @@ QVariant QWaylandWindow::property(const QString &name, const QVariant &defaultVa
return m_properties.value(name, defaultValue);
}
+#ifdef QT_PLATFORM_WINDOW_HAS_VIRTUAL_SET_BACKING_STORE
+void QWaylandWindow::setBackingStore(QPlatformBackingStore *store)
+{
+ mBackingStore = dynamic_cast<QWaylandShmBackingStore *>(store);
+}
+#endif
+
void QWaylandWindow::timerEvent(QTimerEvent *event)
{
if (event->timerId() != mFrameCallbackCheckIntervalTimerId)
return;
- bool callbackTimerExpired = mFrameCallbackElapsedTimer.hasExpired(mFrameCallbackTimeout);
- if (!mFrameCallbackElapsedTimer.isValid() || callbackTimerExpired ) {
- killTimer(mFrameCallbackCheckIntervalTimerId);
- mFrameCallbackCheckIntervalTimerId = -1;
- }
- if (mFrameCallbackElapsedTimer.isValid() && callbackTimerExpired) {
- mFrameCallbackElapsedTimer.invalidate();
+ {
+ QMutexLocker lock(&mFrameSyncMutex);
- qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
- mFrameCallbackTimedOut = true;
- mWaitingForUpdate = false;
- sendExposeEvent(QRect());
+ bool callbackTimerExpired = mFrameCallbackElapsedTimer.hasExpired(mFrameCallbackTimeout);
+ if (!mFrameCallbackElapsedTimer.isValid() || callbackTimerExpired ) {
+ killTimer(mFrameCallbackCheckIntervalTimerId);
+ mFrameCallbackCheckIntervalTimerId = -1;
+ }
+ if (!mFrameCallbackElapsedTimer.isValid() || !callbackTimerExpired) {
+ return;
+ }
+ mFrameCallbackElapsedTimer.invalidate();
}
+
+ qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
+ mFrameCallbackTimedOut = true;
+ mWaitingForUpdate = false;
+ sendExposeEvent(QRect());
}
void QWaylandWindow::requestUpdate()
@@ -1415,15 +1691,14 @@ void QWaylandWindow::handleUpdate()
{
qCDebug(lcWaylandBackingstore) << "handleUpdate" << QThread::currentThread();
- if (mWaitingForFrameCallback)
- return;
-
// TODO: Should sync subsurfaces avoid requesting frame callbacks?
QReadLocker lock(&mSurfaceLock);
if (!mSurface)
return;
QMutexLocker locker(&mFrameSyncMutex);
+ if (mWaitingForFrameCallback)
+ return;
struct ::wl_surface *wrappedSurface = reinterpret_cast<struct ::wl_surface *>(wl_proxy_create_wrapper(mSurface->object()));
wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(wrappedSurface), mDisplay->frameEventQueue());
@@ -1467,15 +1742,21 @@ void QWaylandWindow::propagateSizeHints()
bool QWaylandWindow::startSystemResize(Qt::Edges edges)
{
- if (auto *seat = display()->lastInputDevice())
- return mShellSurface && mShellSurface->resize(seat, edges);
+ if (auto *seat = display()->lastInputDevice()) {
+ bool rc = mShellSurface && mShellSurface->resize(seat, edges);
+ seat->handleEndDrag();
+ return rc;
+ }
return false;
}
bool QtWaylandClient::QWaylandWindow::startSystemMove()
{
- if (auto seat = display()->lastInputDevice())
- return mShellSurface && mShellSurface->move(seat);
+ if (auto seat = display()->lastInputDevice()) {
+ bool rc = mShellSurface && mShellSurface->move(seat);
+ seat->handleEndDrag();
+ return rc;
+ }
return false;
}
@@ -1507,6 +1788,48 @@ void QWaylandWindow::setXdgActivationToken(const QString &token)
{
mShellSurface->setXdgActivationToken(token);
}
+
+void QWaylandWindow::addChildPopup(QWaylandWindow *child)
+{
+ if (mShellSurface)
+ mShellSurface->attachPopup(child->shellSurface());
+ mChildPopups.append(child);
+}
+
+void QWaylandWindow::removeChildPopup(QWaylandWindow *child)
+{
+ if (mShellSurface)
+ mShellSurface->detachPopup(child->shellSurface());
+ mChildPopups.removeAll(child);
+}
+
+void QWaylandWindow::closeChildPopups() {
+ while (!mChildPopups.isEmpty()) {
+ auto popup = mChildPopups.takeLast();
+ popup->reset();
+ }
+}
+
+void QWaylandWindow::reinit()
+{
+ if (window()->isVisible()) {
+ initWindow();
+ if (hasPendingUpdateRequest())
+ deliverUpdateRequest();
+ }
+}
+
+bool QWaylandWindow::windowEvent(QEvent *event)
+{
+ if (event->type() == QEvent::ApplicationPaletteChange
+ || event->type() == QEvent::ApplicationFontChange) {
+ if (mWindowDecorationEnabled && window()->isVisible())
+ mWindowDecoration->update();
+ }
+
+ return QPlatformWindow::windowEvent(event);
+}
+
}
QT_END_NAMESPACE
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
index 66d5bdade..b78c8ce4e 100644
--- a/src/client/qwaylandwindow_p.h
+++ b/src/client/qwaylandwindow_p.h
@@ -28,10 +28,14 @@
#include <QtCore/QMap> // for QVariantMap
#include <qpa/qplatformwindow.h>
+#include <qpa/qplatformwindow_p.h>
#include <QtWaylandClient/private/qwayland-wayland.h>
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtWaylandClient/qtwaylandclientglobal.h>
+#include <QtWaylandClient/private/qwaylandshellsurface_p.h>
+
+#include <QtCore/qpointer.h>
struct wl_egl_window;
@@ -48,13 +52,17 @@ class QWaylandSubSurface;
class QWaylandAbstractDecoration;
class QWaylandInputDevice;
class QWaylandScreen;
+class QWaylandShellIntegration;
class QWaylandShmBackingStore;
class QWaylandPointerEvent;
class QWaylandPointerGestureSwipeEvent;
class QWaylandPointerGesturePinchEvent;
class QWaylandSurface;
+class QWaylandFractionalScale;
+class QWaylandViewport;
-class Q_WAYLANDCLIENT_EXPORT QWaylandWindow : public QObject, public QPlatformWindow
+class Q_WAYLANDCLIENT_EXPORT QWaylandWindow : public QNativeInterface::Private::QWaylandWindow,
+ public QPlatformWindow
{
Q_OBJECT
public:
@@ -85,6 +93,7 @@ public:
void setVisible(bool visible) override;
void setParent(const QPlatformWindow *parent) override;
+ QString windowTitle() const;
void setWindowTitle(const QString &title) override;
inline QIcon windowIcon() const;
@@ -104,7 +113,6 @@ public:
void damage(const QRect &rect);
void safeCommit(QWaylandBuffer *buffer, const QRegion &damage);
- void handleExpose(const QRegion &region);
void commit(QWaylandBuffer *buffer, const QRegion &damage);
void commit();
@@ -112,20 +120,29 @@ public:
bool waitForFrameSync(int timeout);
QMargins frameMargins() const override;
+ QMargins clientSideMargins() const;
+ void setCustomMargins(const QMargins &margins) override;
QSize surfaceSize() const;
+ QMargins windowContentMargins() const;
QRect windowContentGeometry() const;
QPointF mapFromWlSurface(const QPointF &surfacePosition) const;
QWaylandSurface *waylandSurface() const { return mSurface.data(); }
- ::wl_surface *wlSurface();
+ ::wl_surface *wlSurface() const;
+ ::wl_surface *surface() const override
+ {
+ return wlSurface();
+ }
static QWaylandWindow *fromWlSurface(::wl_surface *surface);
QWaylandDisplay *display() const { return mDisplay; }
QWaylandShellSurface *shellSurface() const;
+ std::any _surfaceRole() const override;
QWaylandSubSurface *subSurfaceWindow() const;
QWaylandScreen *waylandScreen() const;
void handleContentOrientationChange(Qt::ScreenOrientation orientation) override;
+ void updateBufferTransform();
void setOrientationMask(Qt::ScreenOrientations mask);
ToplevelWindowTilingStates toplevelWindowTilingStates() const;
@@ -141,6 +158,9 @@ public:
void setMask(const QRegion &region) override;
+ void setAlertState(bool enabled) override;
+ bool isAlertState() const override;
+
qreal scale() const;
qreal devicePixelRatio() const override;
@@ -170,7 +190,6 @@ public:
QWaylandWindow *transientParent() const;
- QMutex *resizeMutex() { return &mResizeLock; }
void doApplyConfigure();
void setCanResize(bool canResize);
@@ -184,9 +203,16 @@ public:
QVariant property(const QString &name);
QVariant property(const QString &name, const QVariant &defaultValue);
+#ifdef QT_PLATFORM_WINDOW_HAS_VIRTUAL_SET_BACKING_STORE
+ void setBackingStore(QPlatformBackingStore *store) override;
+#else
void setBackingStore(QWaylandShmBackingStore *backingStore) { mBackingStore = backingStore; }
+#endif
QWaylandShmBackingStore *backingStore() const { return mBackingStore; }
+ void setShellIntegration(QWaylandShellIntegration *shellIntegration);
+ QWaylandShellIntegration *shellIntegration() const { return mShellIntegration; }
+
bool setKeyboardGrabEnabled(bool) override { return false; }
void propagateSizeHints() override;
void addAttachOffset(const QPoint point);
@@ -200,31 +226,40 @@ public:
void deliverUpdateRequest() override;
void setXdgActivationToken(const QString &token);
- void requestXdgActivationToken(uint serial);
+ void requestXdgActivationToken(uint serial) override;
void beginFrame();
void endFrame();
-public slots:
+ void closeChildPopups();
+ void sendRecursiveExposeEvent();
+
+ virtual void reinit();
+ void reset();
+
+ bool windowEvent(QEvent *event) override;
+
+public Q_SLOTS:
void applyConfigure();
-signals:
+Q_SIGNALS:
void wlSurfaceCreated();
void wlSurfaceDestroyed();
- void xdgActivationTokenCreated(const QString &token);
protected:
virtual void doHandleFrameCallback();
virtual QRect defaultGeometry() const;
void sendExposeEvent(const QRect &rect);
- QMargins clientSideMargins() const;
QWaylandDisplay *mDisplay = nullptr;
// mSurface can be written by the main thread. Other threads should claim a read lock for access
mutable QReadWriteLock mSurfaceLock;
QScopedPointer<QWaylandSurface> mSurface;
+ QScopedPointer<QWaylandFractionalScale> mFractionalScale;
+ QScopedPointer<QWaylandViewport> mViewport;
+ QWaylandShellIntegration *mShellIntegration = nullptr;
QWaylandShellSurface *mShellSurface = nullptr;
QWaylandSubSurface *mSubSurfaceWindow = nullptr;
QList<QWaylandSubSurface *> mChildren;
@@ -252,19 +287,20 @@ protected:
#endif
WId mWindowId;
- bool mWaitingForFrameCallback = false;
bool mFrameCallbackTimedOut = false; // Whether the frame callback has timed out
- QAtomicInt mWaitingForUpdateDelivery = false;
int mFrameCallbackCheckIntervalTimerId = -1;
- QElapsedTimer mFrameCallbackElapsedTimer;
- struct ::wl_callback *mFrameCallback = nullptr;
+ QAtomicInt mWaitingForUpdateDelivery = false;
+
+ bool mWaitingForFrameCallback = false; // Protected by mFrameSyncMutex
+ QElapsedTimer mFrameCallbackElapsedTimer; // Protected by mFrameSyncMutex
+ struct ::wl_callback *mFrameCallback = nullptr; // Protected by mFrameSyncMutex
QMutex mFrameSyncMutex;
QWaitCondition mFrameSyncWait;
// True when we have called deliverRequestUpdate, but the client has not yet attached a new buffer
bool mWaitingForUpdate = false;
- QMutex mResizeLock;
+ QRecursiveMutex mResizeLock;
bool mWaitingToApplyConfigure = false;
bool mCanResize = true;
bool mResizeDirty = false;
@@ -274,13 +310,19 @@ protected:
bool mSentInitialResize = false;
QPoint mOffset;
- int mScale = 1;
+ qreal mScale = 1;
QPlatformScreen *mLastReportedScreen = nullptr;
+ QString mWindowTitle;
QIcon mWindowIcon;
Qt::WindowFlags mFlags;
QRegion mMask;
+
+ // Empty QRegion maps to "infinite" input region, needs a dedicated "deliberately empty" state.
+ QRegion mInputRegion;
+ bool mTransparentInputRegion = false;
+
QRegion mOpaqueArea;
Qt::WindowStates mLastReportedWindowStates = Qt::WindowNoState;
ToplevelWindowTilingStates mLastReportedToplevelWindowTilingStates = WindowNoState;
@@ -289,30 +331,46 @@ protected:
QWaylandBuffer *mQueuedBuffer = nullptr;
QRegion mQueuedBufferDamage;
+ QMargins mCustomMargins;
+
+ QPointer<QWaylandWindow> mTransientParent;
+ QList<QPointer<QWaylandWindow>> mChildPopups;
+
+ Qt::ScreenOrientation mLastReportedContentOrientation = Qt::PrimaryOrientation;
+
+private Q_SLOTS:
+ void doApplyConfigureFromOtherThread();
+
private:
void setGeometry_helper(const QRect &rect);
void initWindow();
void initializeWlSurface();
bool shouldCreateShellSurface() const;
bool shouldCreateSubSurface() const;
- void reset();
- static void closePopups(QWaylandWindow *parent);
QPlatformScreen *calculateScreenFromSurfaceEvents() const;
void setOpaqueArea(const QRegion &opaqueArea);
bool isOpaque() const;
+ void updateInputRegion();
+ void updateViewport();
void handleMouseEventWithDecoration(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e);
void handleScreensChanged();
- void sendRecursiveExposeEvent();
+ void updateScale();
+ void setScale(qreal newScale);
+
+ QWaylandWindow *guessTransientParent() const;
+ void addChildPopup(QWaylandWindow *child);
+ void removeChildPopup(QWaylandWindow *child);
bool mInResizeFromApplyConfigure = false;
bool lastVisible = false;
QRect mLastExposeGeometry;
static const wl_callback_listener callbackListener;
- void handleFrameCallback();
+ void handleFrameCallback(struct ::wl_callback* callback);
static QWaylandWindow *mMouseGrab;
+ static QWaylandWindow *mTopPopup;
friend class QWaylandSubSurface;
};
diff --git a/src/client/qwaylandwindowmanagerintegration.cpp b/src/client/qwaylandwindowmanagerintegration.cpp
index b394d69b8..149190420 100644
--- a/src/client/qwaylandwindowmanagerintegration.cpp
+++ b/src/client/qwaylandwindowmanagerintegration.cpp
@@ -5,6 +5,7 @@
#include "qwaylandscreen_p.h"
#include "qwaylandwindow_p.h"
#include "qwaylanddisplay_p.h"
+#include "qwaylandshellsurface_p.h"
#include <stdint.h>
#include <QtCore/QEvent>
@@ -33,7 +34,6 @@ public:
QWaylandWindowManagerIntegrationPrivate::QWaylandWindowManagerIntegrationPrivate(QWaylandDisplay *waylandDisplay)
: m_waylandDisplay(waylandDisplay)
{
-
}
QWaylandWindowManagerIntegration::QWaylandWindowManagerIntegration(QWaylandDisplay *waylandDisplay)
@@ -44,7 +44,8 @@ QWaylandWindowManagerIntegration::QWaylandWindowManagerIntegration(QWaylandDispl
QWaylandWindowManagerIntegration::~QWaylandWindowManagerIntegration()
{
-
+ if (object())
+ qt_windowmanager_destroy(object());
}
bool QWaylandWindowManagerIntegration::showIsFullScreen() const
@@ -106,6 +107,17 @@ bool QWaylandWindowManagerIntegration::openDocument(const QUrl &url)
return QGenericUnixServices::openDocument(url);
}
+QString QWaylandWindowManagerIntegration::portalWindowIdentifier(QWindow *window)
+{
+ if (window && window->handle()) {
+ auto shellSurface = static_cast<QWaylandWindow *>(window->handle())->shellSurface();
+ if (shellSurface) {
+ const QString handle = shellSurface->externWindowHandle();
+ return QLatin1String("wayland:") + handle;
+ }
+ }
+ return QString();
+}
}
QT_END_NAMESPACE
diff --git a/src/client/qwaylandwindowmanagerintegration_p.h b/src/client/qwaylandwindowmanagerintegration_p.h
index ea57911f4..18eb171b6 100644
--- a/src/client/qwaylandwindowmanagerintegration_p.h
+++ b/src/client/qwaylandwindowmanagerintegration_p.h
@@ -42,6 +42,7 @@ public:
bool openUrl(const QUrl &url) override;
bool openDocument(const QUrl &url) override;
+ QString portalWindowIdentifier(QWindow *window) override;
bool showIsFullScreen() const;
diff --git a/src/client/shellintegration/qwaylandshellintegrationfactory.cpp b/src/client/shellintegration/qwaylandshellintegrationfactory.cpp
index c8d29e27c..feedb27c5 100644
--- a/src/client/shellintegration/qwaylandshellintegrationfactory.cpp
+++ b/src/client/shellintegration/qwaylandshellintegrationfactory.cpp
@@ -12,18 +12,18 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
-Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, qwsifLoader,
(QWaylandShellIntegrationFactoryInterface_iid, QLatin1String("/wayland-shell-integration"), Qt::CaseInsensitive))
QStringList QWaylandShellIntegrationFactory::keys()
{
- return loader->keyMap().values();
+ return qwsifLoader->keyMap().values();
}
QWaylandShellIntegration *QWaylandShellIntegrationFactory::create(const QString &name, QWaylandDisplay *display, const QStringList &args)
{
std::unique_ptr<QWaylandShellIntegration> integration;
- integration.reset(qLoadPlugin<QWaylandShellIntegration, QWaylandShellIntegrationPlugin>(loader(), name, args));
+ integration.reset(qLoadPlugin<QWaylandShellIntegration, QWaylandShellIntegrationPlugin>(qwsifLoader(), name, args));
if (integration && !integration->initialize(display))
return nullptr;
diff --git a/src/compositor/CMakeLists.txt b/src/compositor/CMakeLists.txt
index 4ad5f5451..856fd07f9 100644
--- a/src/compositor/CMakeLists.txt
+++ b/src/compositor/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from compositor.pro.
#####################################################################
@@ -33,14 +36,17 @@ qt_internal_add_module(WaylandCompositor
extensions/qwaylandqttextinputmethodmanager.cpp extensions/qwaylandqttextinputmethodmanager.h extensions/qwaylandqttextinputmethodmanager_p.h
extensions/qwaylandqtwindowmanager.cpp extensions/qwaylandqtwindowmanager.h extensions/qwaylandqtwindowmanager_p.h
extensions/qwaylandshell.cpp extensions/qwaylandshell.h extensions/qwaylandshell_p.h
- extensions/qwaylandshellsurface.cpp extensions/qwaylandshellsurface.h
+ extensions/qwaylandshellsurface.cpp extensions/qwaylandshellsurface.h extensions/qwaylandshellsurface_p.h
extensions/qwaylandtextinput.cpp extensions/qwaylandtextinput.h extensions/qwaylandtextinput_p.h
extensions/qwaylandtextinputmanager.cpp extensions/qwaylandtextinputmanager.h extensions/qwaylandtextinputmanager_p.h
+ extensions/qwaylandtextinputv3.cpp extensions/qwaylandtextinputv3.h extensions/qwaylandtextinputv3_p.h
+ extensions/qwaylandtextinputmanagerv3.cpp extensions/qwaylandtextinputmanagerv3.h extensions/qwaylandtextinputmanagerv3_p.h
extensions/qwaylandviewporter.cpp extensions/qwaylandviewporter.h extensions/qwaylandviewporter_p.h
extensions/qwaylandwlshell.cpp extensions/qwaylandwlshell.h extensions/qwaylandwlshell_p.h
extensions/qwaylandxdgdecorationv1.cpp extensions/qwaylandxdgdecorationv1.h extensions/qwaylandxdgdecorationv1_p.h
extensions/qwaylandxdgoutputv1.cpp extensions/qwaylandxdgoutputv1.h extensions/qwaylandxdgoutputv1_p.h
extensions/qwaylandxdgshell.cpp extensions/qwaylandxdgshell.h extensions/qwaylandxdgshell_p.h
+ extensions/qwaylandxdgdialogv1.cpp extensions/qwaylandxdgdialogv1_p.h
extensions/qwlqtkey.cpp extensions/qwlqtkey_p.h
extensions/qwlqttouch.cpp extensions/qwlqttouch_p.h
global/qtwaylandcompositorglobal.h global/qtwaylandcompositorglobal_p.h
@@ -70,6 +76,8 @@ qt_internal_add_module(WaylandCompositor
Qt::CorePrivate
Qt::GuiPrivate
Qt::WaylandGlobalPrivate
+ PRIVATE_HEADER_FILTERS
+ "^qwayland-.*\.h|^wayland-.*-protocol\.h"
)
set(compositor_no_pch_sources
@@ -105,12 +113,13 @@ qt6_generate_wayland_protocol_server_sources(WaylandCompositor
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/presentation-time.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/scaler.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/text-input-unstable-v2.xml
- ${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/text-input-unstable-v4-wip.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/text-input-unstable-v3.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/viewporter.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/wayland.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/xdg-decoration-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/xdg-output-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/xdg-shell.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/protocol/xdg-dialog-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/hardware-integration.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-key-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/qt-text-input-method-unstable-v1.xml
@@ -126,14 +135,6 @@ qt6_generate_wayland_protocol_server_sources(WaylandCompositor
## Scopes:
#####################################################################
-qt_internal_extend_target(WaylandCompositor CONDITION QT_FEATURE_wayland_text_input_v4_wip
- SOURCES
- extensions/qwaylandtextinputv4.cpp extensions/qwaylandtextinputv4.h extensions/qwaylandtextinputv4_p.h
- extensions/qwaylandtextinputmanagerv4.cpp extensions/qwaylandtextinputmanagerv4.h extensions/qwaylandtextinputmanagerv4_p.h
- DEFINES
- QT_WAYLAND_TEXT_INPUT_V4_WIP=1
-)
-
qt_internal_extend_target(WaylandCompositor CONDITION QT_FEATURE_opengl
SOURCES
hardware_integration/qwlclientbufferintegrationfactory.cpp hardware_integration/qwlclientbufferintegrationfactory_p.h
@@ -145,6 +146,7 @@ qt_internal_extend_target(WaylandCompositor CONDITION QT_FEATURE_opengl
hardware_integration/qwlserverbufferintegration.cpp hardware_integration/qwlserverbufferintegration_p.h
hardware_integration/qwlserverbufferintegrationfactory.cpp hardware_integration/qwlserverbufferintegrationfactory_p.h
hardware_integration/qwlserverbufferintegrationplugin.cpp hardware_integration/qwlserverbufferintegrationplugin_p.h
+ hardware_integration/qwltextureorphanage.cpp hardware_integration/qwltextureorphanage_p.h
PUBLIC_LIBRARIES
Qt::OpenGL
)
@@ -222,6 +224,7 @@ if (TARGET Qt::Qml)
qmlfiles/WaylandOutputWindow.qml
DEPENDENCIES
QtQuick
+ NO_GENERATE_CPP_EXPORTS
)
endif()
diff --git a/src/compositor/Qt6WaylandCompositorMacros.cmake b/src/compositor/Qt6WaylandCompositorMacros.cmake
index 91d0d2830..05d16af6c 100644
--- a/src/compositor/Qt6WaylandCompositorMacros.cmake
+++ b/src/compositor/Qt6WaylandCompositorMacros.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
function(qt6_generate_wayland_protocol_server_sources target)
cmake_parse_arguments(arg "" "__QT_INTERNAL_WAYLAND_INCLUDE_DIR" "FILES" ${ARGN})
if(DEFINED arg_UNPARSED_ARGUMENTS)
@@ -30,11 +33,13 @@ function(qt6_generate_wayland_protocol_server_sources target)
add_custom_command(
OUTPUT "${waylandscanner_header_output}"
#TODO: Maybe put the files in ${CMAKE_CURRENT_BINARY_DIR/wayland_generated instead?
- COMMAND Wayland::Scanner --strict --include-core-only server-header < "${protocol_file}" > "${waylandscanner_header_output}"
+ COMMAND Wayland::Scanner --include-core-only server-header < "${protocol_file}" > "${waylandscanner_header_output}"
+ DEPENDS ${protocol_file} Wayland::Scanner
)
add_custom_command(
OUTPUT "${waylandscanner_code_output}"
- COMMAND Wayland::Scanner --strict --include-core-only public-code < "${protocol_file}" > "${waylandscanner_code_output}"
+ COMMAND Wayland::Scanner --include-core-only public-code < "${protocol_file}" > "${waylandscanner_code_output}"
+ DEPENDS ${protocol_file} Wayland::Scanner
)
set(wayland_include_dir "")
@@ -57,6 +62,7 @@ function(qt6_generate_wayland_protocol_server_sources target)
--build-macro=${build_macro}
--header-path='${wayland_include_dir}'
> "${qtwaylandscanner_header_output}"
+ DEPENDS ${protocol_file} Qt6::qtwaylandscanner
)
add_custom_command(
@@ -66,6 +72,7 @@ function(qt6_generate_wayland_protocol_server_sources target)
--build-macro=${build_macro}
--header-path='${wayland_include_dir}'
> "${qtwaylandscanner_code_output}"
+ DEPENDS ${protocol_file} Qt6::qtwaylandscanner
)
target_sources(${target} PRIVATE
diff --git a/src/compositor/compositor_api/qwaylandbufferref.h b/src/compositor/compositor_api/qwaylandbufferref.h
index 60585dbeb..a917726f0 100644
--- a/src/compositor/compositor_api/qwaylandbufferref.h
+++ b/src/compositor/compositor_api/qwaylandbufferref.h
@@ -5,7 +5,7 @@
#define QWAYLANDBUFFERREF_H
#include <QtWaylandCompositor/qtwaylandcompositorglobal.h>
-#include <QImage>
+#include <QtGui/QImage>
#if QT_CONFIG(opengl)
#include <QtGui/qopengl.h>
diff --git a/src/compositor/compositor_api/qwaylandclient.cpp b/src/compositor/compositor_api/qwaylandclient.cpp
index a60d6ce36..9c8bc704f 100644
--- a/src/compositor/compositor_api/qwaylandclient.cpp
+++ b/src/compositor/compositor_api/qwaylandclient.cpp
@@ -134,7 +134,7 @@ QWaylandClient *QWaylandClient::fromWlClient(QWaylandCompositor *compositor, wl_
}
/*!
- * \qmlproperty WaylandCompositor QtWaylandCompositor::WaylandClient::compositor
+ * \qmlproperty WaylandCompositor QtWayland.Compositor::WaylandClient::compositor
*
* This property holds the compositor of this WaylandClient.
*/
@@ -162,7 +162,7 @@ wl_client *QWaylandClient::client() const
}
/*!
- * \qmlproperty int QtWaylandCompositor::WaylandClient::userId
+ * \qmlproperty int QtWayland.Compositor::WaylandClient::userId
*
* This property holds the user id of this WaylandClient.
*/
@@ -181,7 +181,7 @@ qint64 QWaylandClient::userId() const
}
/*!
- * \qmlproperty int QtWaylandCompositor::WaylandClient::groupId
+ * \qmlproperty int QtWayland.Compositor::WaylandClient::groupId
* \readonly
*
* This property holds the group id of this WaylandClient.
@@ -200,7 +200,7 @@ qint64 QWaylandClient::groupId() const
}
/*!
- * \qmlproperty int QtWaylandCompositor::WaylandClient::processId
+ * \qmlproperty int QtWayland.Compositor::WaylandClient::processId
* \readonly
*
* This property holds the process id of this WaylandClient.
@@ -219,7 +219,7 @@ qint64 QWaylandClient::processId() const
}
/*!
- * \qmlmethod void QtWaylandCompositor::WaylandClient::kill(signal)
+ * \qmlmethod void QtWayland.Compositor::WaylandClient::kill(signal)
*
* Kills the client with the specified \a signal.
*/
@@ -235,7 +235,7 @@ void QWaylandClient::kill(int signal)
}
/*!
- * \qmlmethod void QtWaylandCompositor::WaylandClient::close()
+ * \qmlmethod void QtWayland.Compositor::WaylandClient::close()
*
* Closes the client
*/
diff --git a/src/compositor/compositor_api/qwaylandclient.h b/src/compositor/compositor_api/qwaylandclient.h
index eda4a0237..fd6172a4f 100644
--- a/src/compositor/compositor_api/qwaylandclient.h
+++ b/src/compositor/compositor_api/qwaylandclient.h
@@ -7,7 +7,7 @@
#include <QtWaylandCompositor/qtwaylandcompositorglobal.h>
#include <QtWaylandCompositor/qtwaylandqmlinclude.h>
-#include <QObject>
+#include <QtCore/QObject>
#include <signal.h>
@@ -39,7 +39,9 @@ public:
NoProtocol = 0,
QtTextInputMethodV1 = 1,
TextInputV2 = 2,
- TextInputV4 = 4,
+ TextInputV3 = 4,
+
+ TextInputV4 = TextInputV3, // TextInputV4 was an experimental API that is now deprecated
QtTextInputMethod = QtTextInputMethodV1,
TextInput = TextInputV2
diff --git a/src/compositor/compositor_api/qwaylandcompositor.cpp b/src/compositor/compositor_api/qwaylandcompositor.cpp
index 66f5eba4a..e6f5955b8 100644
--- a/src/compositor/compositor_api/qwaylandcompositor.cpp
+++ b/src/compositor/compositor_api/qwaylandcompositor.cpp
@@ -41,6 +41,7 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QStringList>
#include <QtCore/QSocketNotifier>
+#include <QStandardPaths>
#include <QtGui/QDesktopServices>
#include <QtGui/QScreen>
@@ -62,9 +63,7 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(qLcWaylandCompositor, "qt.waylandcompositor")
Q_LOGGING_CATEGORY(qLcWaylandCompositorHardwareIntegration, "qt.waylandcompositor.hardwareintegration")
Q_LOGGING_CATEGORY(qLcWaylandCompositorInputMethods, "qt.waylandcompositor.inputmethods")
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
Q_LOGGING_CATEGORY(qLcWaylandCompositorTextInput, "qt.waylandcompositor.textinput")
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
namespace QtWayland {
@@ -101,13 +100,15 @@ public:
ke->nativeScanCode += offset;
#endif
uint32_t code = ke->nativeScanCode;
+ if (code == 0)
+ code = seat->keyboard()->keyToScanCode(ke->key);
bool isDown = ke->keyType == QEvent::KeyPress;
#if QT_CONFIG(xkbcommon)
xkb_state *xkbState = keyb->xkbState();
- Qt::KeyboardModifiers modifiers = QXkbCommon::modifiers(xkbState);
const xkb_keysym_t sym = xkb_state_key_get_one_sym(xkbState, code);
+ Qt::KeyboardModifiers modifiers = QXkbCommon::modifiers(xkbState, sym);
int qtkey = QXkbCommon::keysymToQtKey(sym, modifiers, xkbState, code);
QString text = QXkbCommon::lookupString(xkbState, code);
@@ -135,6 +136,9 @@ public:
QWaylandCompositorPrivate::QWaylandCompositorPrivate(QWaylandCompositor *compositor)
{
+ // Create XDG_RUNTIME_DIR, if it does not already exist
+ QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
+
if (QGuiApplication::platformNativeInterface())
display = static_cast<wl_display*>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("server_wl_display"));
@@ -166,6 +170,8 @@ void QWaylandCompositorPrivate::init()
const int socketArg = arguments.indexOf(QLatin1String("--wayland-socket-name"));
if (socketArg != -1 && socketArg + 1 < arguments.size())
socket_name = arguments.at(socketArg + 1).toLocal8Bit();
+ if (socket_name.isEmpty())
+ socket_name = qgetenv("WAYLAND_DISPLAY");
}
wl_compositor::init(display, 4);
wl_subcompositor::init(display, 1);
@@ -213,7 +219,7 @@ void QWaylandCompositorPrivate::init()
initialized = true;
- for (const QPointer<QObject> &object : qExchange(polish_objects, {})) {
+ for (const QPointer<QObject> &object : std::exchange(polish_objects, {})) {
if (object) {
QEvent polishEvent(QEvent::Polish);
QCoreApplication::sendEvent(object.data(), &polishEvent);
@@ -289,7 +295,7 @@ void QWaylandCompositorPrivate::addPolishObject(QObject *object)
void QWaylandCompositorPrivate::connectToExternalSockets()
{
// Clear out any backlog of user-supplied external socket descriptors
- for (int fd : qAsConst(externally_added_socket_fds)) {
+ for (int fd : std::as_const(externally_added_socket_fds)) {
if (wl_display_add_socket_fd(display, fd) != 0)
qWarning() << "Failed to integrate user-supplied socket fd into the Wayland event loop";
}
@@ -373,14 +379,14 @@ void QWaylandCompositorPrivate::initializeHardwareIntegration()
loadClientBufferIntegration();
loadServerBufferIntegration();
- for (auto *integration : qAsConst(client_buffer_integrations))
+ for (auto *integration : std::as_const(client_buffer_integrations))
integration->initializeHardware(display);
#endif
}
void QWaylandCompositorPrivate::initializeSeats()
{
- for (QWaylandSeat *seat : qAsConst(seats))
+ for (QWaylandSeat *seat : std::as_const(seats))
seat->initialize();
}
@@ -410,7 +416,7 @@ void QWaylandCompositorPrivate::loadClientBufferIntegration()
QString hwIntegrationName;
- for (auto targetKey : qAsConst(targetKeys)) {
+ for (auto targetKey : std::as_const(targetKeys)) {
auto *integration = QtWayland::ClientBufferIntegrationFactory::create(targetKey, QStringList());
if (integration) {
integration->setCompositor(q);
@@ -504,7 +510,7 @@ QWaylandSeat *QWaylandCompositorPrivate::seatFor(QInputEvent *inputEvent)
*/
/*!
- \qmlsignal void QtWaylandCompositor::WaylandCompositor::surfaceRequested(WaylandClient client, int id, int version)
+ \qmlsignal void QtWayland.Compositor::WaylandCompositor::surfaceRequested(WaylandClient client, int id, int version)
This signal is emitted when a \a client has created a surface with id \a id.
The interface \a version is also available.
@@ -526,7 +532,7 @@ QWaylandSeat *QWaylandCompositorPrivate::seatFor(QInputEvent *inputEvent)
*/
/*!
- \qmlsignal void QtWaylandCompositor::WaylandCompositor::surfaceCreated(WaylandSurface surface)
+ \qmlsignal void QtWayland.Compositor::WaylandCompositor::surfaceCreated(WaylandSurface surface)
This signal is emitted when a new WaylandSurface instance \a surface has been created.
*/
@@ -573,7 +579,7 @@ void QWaylandCompositor::create()
}
/*!
- * \qmlproperty bool QtWaylandCompositor::WaylandCompositor::created
+ * \qmlproperty bool QtWayland.Compositor::WaylandCompositor::created
*
* This property is true if WaylandCompositor has been initialized,
* otherwise it's false.
@@ -592,7 +598,7 @@ bool QWaylandCompositor::isCreated() const
}
/*!
- * \qmlproperty string QtWaylandCompositor::WaylandCompositor::socketName
+ * \qmlproperty string QtWayland.Compositor::WaylandCompositor::socketName
*
* This property holds the socket name used by WaylandCompositor to communicate with
* clients. It must be set before the component is completed.
@@ -635,7 +641,7 @@ QByteArray QWaylandCompositor::socketName() const
}
/*!
- * \qmlmethod QtWaylandCompositor::WaylandCompositor::addSocketDescriptor(fd)
+ * \qmlmethod QtWayland.Compositor::WaylandCompositor::addSocketDescriptor(fd)
* \since 5.12
*
* Listen for client connections on a file descriptor, \a fd, referring to a
@@ -698,7 +704,7 @@ QList<QWaylandClient *>QWaylandCompositor::clients() const
}
/*!
- * \qmlmethod QtWaylandCompositor::WaylandCompositor::destroyClientForSurface(surface)
+ * \qmlmethod QtWayland.Compositor::WaylandCompositor::destroyClientForSurface(surface)
*
* Destroys the client for the WaylandSurface \a surface.
*/
@@ -712,7 +718,7 @@ void QWaylandCompositor::destroyClientForSurface(QWaylandSurface *surface)
}
/*!
- * \qmlmethod QtWaylandCompositor::WaylandCompositor::destroyClient(client)
+ * \qmlmethod QtWayland.Compositor::WaylandCompositor::destroyClient(client)
*
* Destroys the given WaylandClient \a client.
*/
@@ -770,7 +776,7 @@ QWaylandOutput *QWaylandCompositor::outputFor(QWindow *window) const
}
/*!
- * \qmlproperty WaylandOutput QtWaylandCompositor::WaylandCompositor::defaultOutput
+ * \qmlproperty WaylandOutput QtWayland.Compositor::WaylandCompositor::defaultOutput
*
* This property contains the first in the list of outputs added to the
* WaylandCompositor, or null if no outputs have been added.
@@ -871,7 +877,7 @@ QWaylandTouch *QWaylandCompositor::createTouchDevice(QWaylandSeat *seat)
}
/*!
- * \qmlproperty bool QtWaylandCompositor::WaylandCompositor::retainedSelection
+ * \qmlproperty bool QtWayland.Compositor::WaylandCompositor::retainedSelection
*
* This property holds whether retained selection is enabled.
*/
@@ -917,7 +923,7 @@ void QWaylandCompositor::overrideSelection(const QMimeData *data)
}
/*!
- * \qmlproperty WaylandSeat QtWaylandCompositor::WaylandCompositor::defaultSeat
+ * \qmlproperty WaylandSeat QtWayland.Compositor::WaylandCompositor::defaultSeat
*
* This property contains the default seat for this
* WaylandCompositor.
@@ -939,8 +945,7 @@ QWaylandSeat *QWaylandCompositor::defaultSeat() const
/*!
* Select the seat for a given input event \a inputEvent.
- * Currently, Qt only supports a single seat, but you can reimplement
- * QWaylandCompositorPrivate::seatFor for a custom seat selection.
+ * Currently, Qt only supports a single seat.
*/
QWaylandSeat *QWaylandCompositor::seatFor(QInputEvent *inputEvent)
{
@@ -949,7 +954,7 @@ QWaylandSeat *QWaylandCompositor::seatFor(QInputEvent *inputEvent)
}
/*!
- * \qmlproperty bool QtWaylandCompositor::WaylandCompositor::useHardwareIntegrationExtension
+ * \qmlproperty bool QtWayland.Compositor::WaylandCompositor::useHardwareIntegrationExtension
*
* This property holds whether the hardware integration extension should be enabled for
* this WaylandCompositor.
@@ -1035,7 +1040,7 @@ void QWaylandCompositor::grabSurface(QWaylandSurfaceGrabber *grabber, const QWay
}
/*!
- * \qmlproperty list<enum> QtWaylandCompositor::WaylandCompositor::additionalShmFormats
+ * \qmlproperty list<enum> QtWayland.Compositor::WaylandCompositor::additionalShmFormats
*
* This property holds the list of additional wl_shm formats advertised as supported by the
* compositor.
diff --git a/src/compositor/compositor_api/qwaylandcompositor.h b/src/compositor/compositor_api/qwaylandcompositor.h
index dd9029c5c..1dee5cad1 100644
--- a/src/compositor/compositor_api/qwaylandcompositor.h
+++ b/src/compositor/compositor_api/qwaylandcompositor.h
@@ -9,10 +9,10 @@
#include <QtWaylandCompositor/qwaylandcompositorextension.h>
#include <QtWaylandCompositor/QWaylandOutput>
-#include <QObject>
-#include <QImage>
-#include <QRect>
-#include <QLoggingCategory>
+#include <QtCore/QObject>
+#include <QtGui/QImage>
+#include <QtCore/QRect>
+#include <QtCore/QLoggingCategory>
struct wl_display;
@@ -67,6 +67,7 @@ public:
ShmFormat_RGB888 = 0x34324752,
ShmFormat_XBGR8888 = 0x34324258,
ShmFormat_ABGR8888 = 0x34324241,
+ ShmFormat_BGR888 = 0x34324742,
ShmFormat_XRGB2101010 = 0x30335258,
ShmFormat_XBGR2101010 = 0x30334258,
ShmFormat_ARGB2101010 = 0x30335241,
diff --git a/src/compositor/compositor_api/qwaylandcompositor_p.h b/src/compositor/compositor_api/qwaylandcompositor_p.h
index f3021dc4e..a8da8b8c4 100644
--- a/src/compositor/compositor_api/qwaylandcompositor_p.h
+++ b/src/compositor/compositor_api/qwaylandcompositor_p.h
@@ -24,6 +24,8 @@
#include <QtWaylandCompositor/private/qwayland-server-wayland.h>
+#include <QtCore/qpointer.h>
+
#include <vector>
#if QT_CONFIG(xkbcommon)
diff --git a/src/compositor/compositor_api/qwaylandcompositorquickextensions_p.h b/src/compositor/compositor_api/qwaylandcompositorquickextensions_p.h
index fe400d3f9..3150f90ae 100644
--- a/src/compositor/compositor_api/qwaylandcompositorquickextensions_p.h
+++ b/src/compositor/compositor_api/qwaylandcompositorquickextensions_p.h
@@ -24,9 +24,7 @@
#include <QtWaylandCompositor/qwaylandqtwindowmanager.h>
#include <QtWaylandCompositor/qwaylandtextinputmanager.h>
#include <QtCore/private/qglobal_p.h>
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
-#include <QtWaylandCompositor/qwaylandtextinputmanagerv4.h>
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
+#include <QtWaylandCompositor/qwaylandtextinputmanagerv3.h>
#include <QtWaylandCompositor/qwaylandqttextinputmethodmanager.h>
#include <QtWaylandCompositor/qwaylandidleinhibitv1.h>
@@ -85,9 +83,7 @@ private:
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_CLASS(QWaylandQtWindowManager, QtWindowManager)
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_CLASS(QWaylandIdleInhibitManagerV1, IdleInhibitManagerV1)
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_CLASS(QWaylandTextInputManager, TextInputManager)
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
-Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_CLASS(QWaylandTextInputManagerV4, TextInputManagerV4)
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
+Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_CLASS(QWaylandTextInputManagerV3, TextInputManagerV3)
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_NAMED_CLASS(QWaylandQtTextInputMethodManager, QtTextInputMethodManager)
QT_END_NAMESPACE
diff --git a/src/compositor/compositor_api/qwaylandinputmethodcontrol.cpp b/src/compositor/compositor_api/qwaylandinputmethodcontrol.cpp
index 1070faa2f..e9a962d28 100644
--- a/src/compositor/compositor_api/qwaylandinputmethodcontrol.cpp
+++ b/src/compositor/compositor_api/qwaylandinputmethodcontrol.cpp
@@ -9,9 +9,7 @@
#include "qwaylandsurface.h"
#include "qwaylandview.h"
#include "qwaylandtextinput.h"
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
-#include "qwaylandtextinputv4.h"
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
+#include "qwaylandtextinputv3.h"
#include "qwaylandqttextinputmethod.h"
#include <QtGui/QInputMethodEvent>
@@ -24,14 +22,12 @@ QWaylandInputMethodControl::QWaylandInputMethodControl(QWaylandSurface *surface)
updateTextInput();
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- QWaylandTextInputV4 *textInputV4 = d_func()->textInputV4();
- if (textInputV4) {
- connect(textInputV4, &QWaylandTextInputV4::surfaceEnabled, this, &QWaylandInputMethodControl::surfaceEnabled);
- connect(textInputV4, &QWaylandTextInputV4::surfaceDisabled, this, &QWaylandInputMethodControl::surfaceDisabled);
- connect(textInputV4, &QWaylandTextInputV4::updateInputMethod, this, &QWaylandInputMethodControl::updateInputMethod);
+ QWaylandTextInputV3 *textInputV3 = d_func()->textInputV3();
+ if (textInputV3) {
+ connect(textInputV3, &QWaylandTextInputV3::surfaceEnabled, this, &QWaylandInputMethodControl::surfaceEnabled);
+ connect(textInputV3, &QWaylandTextInputV3::surfaceDisabled, this, &QWaylandInputMethodControl::surfaceDisabled);
+ connect(textInputV3, &QWaylandTextInputV3::updateInputMethod, this, &QWaylandInputMethodControl::updateInputMethod);
}
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
QWaylandQtTextInputMethod *textInputMethod = d_func()->textInputMethod();
if (textInputMethod) {
@@ -49,11 +45,9 @@ QVariant QWaylandInputMethodControl::inputMethodQuery(Qt::InputMethodQuery query
if (textInput != nullptr && textInput->focus() == d->surface)
return textInput->inputMethodQuery(query, argument);
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- QWaylandTextInputV4 *textInputV4 = d->textInputV4();
- if (textInputV4 != nullptr && textInputV4->focus() == d->surface)
- return textInputV4->inputMethodQuery(query, argument);
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
+ QWaylandTextInputV3 *textInputV3 = d->textInputV3();
+ if (textInputV3 != nullptr && textInputV3->focus() == d->surface)
+ return textInputV3->inputMethodQuery(query, argument);
QWaylandQtTextInputMethod *textInputMethod = d_func()->textInputMethod();
if (textInputMethod && textInputMethod->focusedSurface() == d->surface)
@@ -68,10 +62,8 @@ void QWaylandInputMethodControl::inputMethodEvent(QInputMethodEvent *event)
if (QWaylandTextInput *textInput = d->textInput()) {
textInput->sendInputMethodEvent(event);
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- } else if (QWaylandTextInputV4 *textInputV4 = d->textInputV4()) {
- textInputV4->sendInputMethodEvent(event);
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
+ } else if (QWaylandTextInputV3 *textInputV3 = d->textInputV3()) {
+ textInputV3->sendInputMethodEvent(event);
} else if (QWaylandQtTextInputMethod *textInputMethod = d->textInputMethod()) {
textInputMethod->sendInputMethodEvent(event);
} else {
@@ -124,14 +116,10 @@ void QWaylandInputMethodControl::setSurface(QWaylandSurface *surface)
d->surface = surface;
QWaylandTextInput *textInput = d->textInput();
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- QWaylandTextInputV4 *textInputV4 = d->textInputV4();
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
+ QWaylandTextInputV3 *textInputV3 = d->textInputV3();
QWaylandQtTextInputMethod *textInputMethod = d->textInputMethod();
setEnabled((textInput && textInput->isSurfaceEnabled(d->surface))
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- || (textInputV4 && textInputV4->isSurfaceEnabled(d->surface))
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
+ || (textInputV3 && textInputV3->isSurfaceEnabled(d->surface))
|| (textInputMethod && textInputMethod->isSurfaceEnabled(d->surface)));
}
@@ -151,16 +139,12 @@ void QWaylandInputMethodControl::defaultSeatChanged()
Q_D(QWaylandInputMethodControl);
disconnect(d->textInput(), nullptr, this, nullptr);
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- disconnect(d->textInputV4(), nullptr, this, nullptr);
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
+ disconnect(d->textInputV3(), nullptr, this, nullptr);
disconnect(d->textInputMethod(), nullptr, this, nullptr);
d->seat = d->compositor->defaultSeat();
QWaylandTextInput *textInput = d->textInput();
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- QWaylandTextInputV4 *textInputV4 = d->textInputV4();
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
+ QWaylandTextInputV3 *textInputV3 = d->textInputV3();
QWaylandQtTextInputMethod *textInputMethod = d->textInputMethod();
if (textInput) {
@@ -168,12 +152,10 @@ void QWaylandInputMethodControl::defaultSeatChanged()
connect(textInput, &QWaylandTextInput::surfaceDisabled, this, &QWaylandInputMethodControl::surfaceDisabled);
}
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- if (textInputV4) {
- connect(textInputV4, &QWaylandTextInputV4::surfaceEnabled, this, &QWaylandInputMethodControl::surfaceEnabled);
- connect(textInputV4, &QWaylandTextInputV4::surfaceDisabled, this, &QWaylandInputMethodControl::surfaceDisabled);
+ if (textInputV3) {
+ connect(textInputV3, &QWaylandTextInputV3::surfaceEnabled, this, &QWaylandInputMethodControl::surfaceEnabled);
+ connect(textInputV3, &QWaylandTextInputV3::surfaceDisabled, this, &QWaylandInputMethodControl::surfaceDisabled);
}
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
if (textInputMethod) {
connect(textInputMethod, &QWaylandQtTextInputMethod::surfaceEnabled, this, &QWaylandInputMethodControl::surfaceEnabled);
@@ -181,9 +163,7 @@ void QWaylandInputMethodControl::defaultSeatChanged()
}
setEnabled((textInput && textInput->isSurfaceEnabled(d->surface))
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- || (textInputV4 && textInputV4->isSurfaceEnabled(d->surface))
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
+ || (textInputV3 && textInputV3->isSurfaceEnabled(d->surface))
|| (textInputMethod && textInputMethod->isSurfaceEnabled(d->surface)));
}
@@ -208,11 +188,9 @@ QWaylandTextInput *QWaylandInputMethodControlPrivate::textInput() const
return QWaylandTextInput::findIn(seat);
}
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
-QWaylandTextInputV4 *QWaylandInputMethodControlPrivate::textInputV4() const
+QWaylandTextInputV3 *QWaylandInputMethodControlPrivate::textInputV3() const
{
- return QWaylandTextInputV4::findIn(seat);
+ return QWaylandTextInputV3::findIn(seat);
}
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
#include "moc_qwaylandinputmethodcontrol.cpp"
diff --git a/src/compositor/compositor_api/qwaylandinputmethodcontrol.h b/src/compositor/compositor_api/qwaylandinputmethodcontrol.h
index 31ee7ff19..3b4d74870 100644
--- a/src/compositor/compositor_api/qwaylandinputmethodcontrol.h
+++ b/src/compositor/compositor_api/qwaylandinputmethodcontrol.h
@@ -5,7 +5,7 @@
#define QWAYLANDINPUTMETHODCONTROL_H
#include <QtGui/qtguiglobal.h>
-#include <QObject>
+#include <QtCore/QObject>
QT_BEGIN_NAMESPACE
diff --git a/src/compositor/compositor_api/qwaylandinputmethodcontrol_p.h b/src/compositor/compositor_api/qwaylandinputmethodcontrol_p.h
index 9f9fc3949..36a0db0c4 100644
--- a/src/compositor/compositor_api/qwaylandinputmethodcontrol_p.h
+++ b/src/compositor/compositor_api/qwaylandinputmethodcontrol_p.h
@@ -26,9 +26,7 @@ class QWaylandCompositor;
class QWaylandSeat;
class QWaylandSurface;
class QWaylandTextInput;
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
-class QWaylandTextInputV4;
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
+class QWaylandTextInputV3;
class QWaylandQtTextInputMethod;
class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandInputMethodControlPrivate : public QObjectPrivate
@@ -39,9 +37,7 @@ public:
explicit QWaylandInputMethodControlPrivate(QWaylandSurface *surface);
QWaylandTextInput *textInput() const;
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- QWaylandTextInputV4 *textInputV4() const;
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
+ QWaylandTextInputV3 *textInputV3() const;
QWaylandQtTextInputMethod *textInputMethod() const;
QWaylandCompositor *compositor = nullptr;
diff --git a/src/compositor/compositor_api/qwaylandkeyboard.cpp b/src/compositor/compositor_api/qwaylandkeyboard.cpp
index f8d494ab1..8af7fbd8c 100644
--- a/src/compositor/compositor_api/qwaylandkeyboard.cpp
+++ b/src/compositor/compositor_api/qwaylandkeyboard.cpp
@@ -163,7 +163,7 @@ void QWaylandKeyboardPrivate::maybeUpdateXkbScanCodeTable()
continue;
Qt::KeyboardModifiers mods = {};
- int qtKey = QXkbCommon::keysymToQtKey(syms[0], mods);
+ int qtKey = QXkbCommon::keysymToQtKey(syms[0], mods, nullptr, 0, false, false);
if (qtKey != 0)
scanCodesByQtKey->insert({layout, qtKey}, keycode);
}
diff --git a/src/compositor/compositor_api/qwaylandkeymap.h b/src/compositor/compositor_api/qwaylandkeymap.h
index 37274e970..a919160b2 100644
--- a/src/compositor/compositor_api/qwaylandkeymap.h
+++ b/src/compositor/compositor_api/qwaylandkeymap.h
@@ -7,7 +7,9 @@
#include <QtCore/QObject>
#include <QtWaylandCompositor/qtwaylandcompositorglobal.h>
#include <QtWaylandCompositor/qtwaylandqmlinclude.h>
+#if QT_CONFIG(wayland_compositor_quick)
#include <QtWaylandCompositor/qwaylandquickchildren.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -17,7 +19,9 @@ class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandKeymap : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QWaylandKeymap)
+#if QT_CONFIG(wayland_compositor_quick)
Q_WAYLAND_COMPOSITOR_DECLARE_QUICK_CHILDREN(QWaylandKeymap)
+#endif
Q_PROPERTY(QString layout READ layout WRITE setLayout NOTIFY layoutChanged)
Q_PROPERTY(QString variant READ variant WRITE setVariant NOTIFY variantChanged)
Q_PROPERTY(QString options READ options WRITE setOptions NOTIFY optionsChanged)
diff --git a/src/compositor/compositor_api/qwaylandmousetracker_p.h b/src/compositor/compositor_api/qwaylandmousetracker_p.h
index 1f243e7d2..efc49c3f5 100644
--- a/src/compositor/compositor_api/qwaylandmousetracker_p.h
+++ b/src/compositor/compositor_api/qwaylandmousetracker_p.h
@@ -44,7 +44,7 @@ public:
bool windowSystemCursorEnabled() const;
bool hovered() const;
-signals:
+Q_SIGNALS:
void mouseXChanged();
void mouseYChanged();
void windowSystemCursorEnabledChanged();
diff --git a/src/compositor/compositor_api/qwaylandoutput.cpp b/src/compositor/compositor_api/qwaylandoutput.cpp
index fc1cd5705..c19e2bd94 100644
--- a/src/compositor/compositor_api/qwaylandoutput.cpp
+++ b/src/compositor/compositor_api/qwaylandoutput.cpp
@@ -358,7 +358,7 @@ void QWaylandOutput::update()
}
/*!
- * \qmlproperty WaylandCompositor QtWaylandCompositor::WaylandOutput::compositor
+ * \qmlproperty WaylandCompositor QtWayland.Compositor::WaylandOutput::compositor
*
* This property holds the compositor displaying content on this WaylandOutput.
*
@@ -398,7 +398,7 @@ void QWaylandOutput::setCompositor(QWaylandCompositor *compositor)
}
/*!
- * \qmlproperty string QtWaylandCompositor::WaylandOutput::manufacturer
+ * \qmlproperty string QtWayland.Compositor::WaylandOutput::manufacturer
*
* This property holds a textual description of the manufacturer of this WaylandOutput.
*/
@@ -426,7 +426,7 @@ void QWaylandOutput::setManufacturer(const QString &manufacturer)
}
/*!
- * \qmlproperty string QtWaylandCompositor::WaylandOutput::model
+ * \qmlproperty string QtWayland.Compositor::WaylandOutput::model
*
* This property holds a textual description of the model of this WaylandOutput.
*/
@@ -454,7 +454,7 @@ void QWaylandOutput::setModel(const QString &model)
}
/*!
- * \qmlproperty point QtWaylandCompositor::WaylandOutput::position
+ * \qmlproperty point QtWayland.Compositor::WaylandOutput::position
*
* This property holds the position of this WaylandOutput in the compositor's coordinate system.
*/
@@ -559,7 +559,7 @@ void QWaylandOutput::setCurrentMode(const QWaylandOutputMode &mode)
}
/*!
- * \qmlproperty rect QtWaylandCompositor::WaylandOutput::geometry
+ * \qmlproperty rect QtWayland.Compositor::WaylandOutput::geometry
*
* This property holds the geometry of the WaylandOutput.
*/
@@ -578,7 +578,7 @@ QRect QWaylandOutput::geometry() const
}
/*!
- * \qmlproperty rect QtWaylandCompositor::WaylandOutput::availableGeometry
+ * \qmlproperty rect QtWayland.Compositor::WaylandOutput::availableGeometry
*
* This property holds the geometry of the WaylandOutput available for displaying content.
* The available geometry is in output coordinates space, starts from 0,0 and it's as big
@@ -621,7 +621,7 @@ void QWaylandOutput::setAvailableGeometry(const QRect &availableGeometry)
}
/*!
- * \qmlproperty size QtWaylandCompositor::WaylandOutput::physicalSize
+ * \qmlproperty size QtWayland.Compositor::WaylandOutput::physicalSize
*
* This property holds the physical size of the WaylandOutput in millimeters.
*
@@ -669,7 +669,7 @@ void QWaylandOutput::setPhysicalSize(const QSize &size)
*/
/*!
- * \qmlproperty enum QtWaylandCompositor::WaylandOutput::subpixel
+ * \qmlproperty enum QtWayland.Compositor::WaylandOutput::subpixel
*
* This property holds the subpixel arrangement of this WaylandOutput.
*
@@ -726,7 +726,7 @@ void QWaylandOutput::setSubpixel(const Subpixel &subpixel)
*/
/*!
- * \qmlproperty enum QtWaylandCompositor::WaylandOutput::transform
+ * \qmlproperty enum QtWayland.Compositor::WaylandOutput::transform
*
* This property holds the transformation that the QWaylandCompositor applies to a surface
* to compensate for the orientation of the QWaylandOutput.
@@ -772,7 +772,7 @@ void QWaylandOutput::setTransform(const Transform &transform)
}
/*!
- * \qmlproperty int QtWaylandCompositor::WaylandOutput::scaleFactor
+ * \qmlproperty int QtWayland.Compositor::WaylandOutput::scaleFactor
*
* This property holds the factor by which the WaylandCompositor scales surface buffers
* before they are displayed. It is used on high density output devices where unscaled content
@@ -822,7 +822,7 @@ void QWaylandOutput::setScaleFactor(int scale)
}
/*!
- * \qmlproperty bool QtWaylandCompositor::WaylandOutput::sizeFollowsWindow
+ * \qmlproperty bool QtWayland.Compositor::WaylandOutput::sizeFollowsWindow
*
* This property controls whether the size of the WaylandOutput matches the
* size of its window.
@@ -860,7 +860,7 @@ void QWaylandOutput::setSizeFollowsWindow(bool follow)
}
/*!
- * \qmlproperty Window QtWaylandCompositor::WaylandOutput::window
+ * \qmlproperty Window QtWayland.Compositor::WaylandOutput::window
*
* This property holds the Window for this WaylandOutput.
*
diff --git a/src/compositor/compositor_api/qwaylandoutput.h b/src/compositor/compositor_api/qwaylandoutput.h
index c00ec0f95..a45fa5756 100644
--- a/src/compositor/compositor_api/qwaylandoutput.h
+++ b/src/compositor/compositor_api/qwaylandoutput.h
@@ -9,10 +9,8 @@
#include <QtWaylandCompositor/qwaylandcompositorextension.h>
#include <QtWaylandCompositor/QWaylandOutputMode>
#include <QtCore/QObject>
-
-#include <QObject>
-#include <QRect>
-#include <QSize>
+#include <QtCore/QRect>
+#include <QtCore/QSize>
struct wl_resource;
diff --git a/src/compositor/compositor_api/qwaylandoutput_p.h b/src/compositor/compositor_api/qwaylandoutput_p.h
index 508b4860c..f62def16c 100644
--- a/src/compositor/compositor_api/qwaylandoutput_p.h
+++ b/src/compositor/compositor_api/qwaylandoutput_p.h
@@ -29,6 +29,7 @@
#include <QtCore/QRect>
#include <QtCore/private/qobject_p.h>
+#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
diff --git a/src/compositor/compositor_api/qwaylandpointer_p.h b/src/compositor/compositor_api/qwaylandpointer_p.h
index 647830a01..71970351b 100644
--- a/src/compositor/compositor_api/qwaylandpointer_p.h
+++ b/src/compositor/compositor_api/qwaylandpointer_p.h
@@ -30,6 +30,8 @@
#include <QtWaylandCompositor/QWaylandSurface>
#include <QtWaylandCompositor/QWaylandSeat>
+#include <QtCore/qpointer.h>
+
#include <stdint.h>
QT_BEGIN_NAMESPACE
diff --git a/src/compositor/compositor_api/qwaylandquickcompositor.cpp b/src/compositor/compositor_api/qwaylandquickcompositor.cpp
index f908532aa..43cc8c3e2 100644
--- a/src/compositor/compositor_api/qwaylandquickcompositor.cpp
+++ b/src/compositor/compositor_api/qwaylandquickcompositor.cpp
@@ -47,7 +47,7 @@ QWaylandQuickCompositor::QWaylandQuickCompositor(QObject *parent)
}
/*!
- * \qmlproperty list QtWaylandCompositor::WaylandCompositor::extensions
+ * \qmlproperty list QtWayland.Compositor::WaylandCompositor::extensions
*
* A list of extensions that the compositor advertises to its clients. For
* any Wayland extension the compositor should support, instantiate its component,
diff --git a/src/compositor/compositor_api/qwaylandquickhardwarelayer.cpp b/src/compositor/compositor_api/qwaylandquickhardwarelayer.cpp
index 07f37abee..9cf36b36f 100644
--- a/src/compositor/compositor_api/qwaylandquickhardwarelayer.cpp
+++ b/src/compositor/compositor_api/qwaylandquickhardwarelayer.cpp
@@ -79,7 +79,7 @@ QWaylandQuickHardwareLayer::~QWaylandQuickHardwareLayer()
}
/*!
- * \qmlproperty int QtWaylandCompositor::WaylandHardwareLayer::stackingLevel
+ * \qmlproperty int QtWayland.Compositor::WaylandHardwareLayer::stackingLevel
*
* This property holds the stacking level of this hardware layer relative to other hardware layers,
* and can be used to sort hardware layers. I.e. a layer with a higher level is rendered on top of
diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp
index eb2412052..c643598be 100644
--- a/src/compositor/compositor_api/qwaylandquickitem.cpp
+++ b/src/compositor/compositor_api/qwaylandquickitem.cpp
@@ -6,9 +6,7 @@
#include "qwaylandquicksurface.h"
#include "qwaylandinputmethodcontrol.h"
#include "qwaylandtextinput.h"
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
-#include "qwaylandtextinputv4.h"
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
+#include "qwaylandtextinputv3.h"
#include "qwaylandqttextinputmethod.h"
#include "qwaylandquickoutput.h"
#include <QtWaylandCompositor/qwaylandcompositor.h>
@@ -41,7 +39,7 @@
#include <QThread>
#if QT_CONFIG(opengl)
-#include <QtGui/private/qshaderdescription_p_p.h>
+#include <QtGui/private/qshaderdescription_p.h>
#endif
#ifndef GL_TEXTURE_EXTERNAL_OES
@@ -54,65 +52,64 @@ QT_BEGIN_NAMESPACE
static const struct {
const char * const vertexShaderSourceFile;
const char * const fragmentShaderSourceFile;
- GLenum textureTarget;
int planeCount;
bool canProvideTexture;
QSGMaterial::Flags materialFlags;
QSGMaterialType materialType;
} bufferTypes[] = {
// BufferFormatEgl_Null
- { "", "", 0, 0, false, {}, {} },
+ { "", "", 0, false, {}, {} },
- // BufferFormatEgl_RGB
+ // BufferFormatEgl_RGB (GL_TEXTURE_2D)
{
":/qt-project.org/wayland/compositor/shaders/surface.vert.qsb",
":/qt-project.org/wayland/compositor/shaders/surface_rgbx.frag.qsb",
- GL_TEXTURE_2D, 1, true,
+ 1, true,
QSGMaterial::Blending,
{}
},
- // BufferFormatEgl_RGBA
+ // BufferFormatEgl_RGBA (GL_TEXTURE_2D)
{
":/qt-project.org/wayland/compositor/shaders/surface.vert.qsb",
":/qt-project.org/wayland/compositor/shaders/surface_rgba.frag.qsb",
- GL_TEXTURE_2D, 1, true,
+ 1, true,
QSGMaterial::Blending,
{}
},
- // BufferFormatEgl_EXTERNAL_OES
+ // BufferFormatEgl_EXTERNAL_OES (GL_TEXTURE_EXTERNAL_OES)
{
":/qt-project.org/wayland/compositor/shaders/surface.vert.qsb",
":/qt-project.org/wayland/compositor/shaders/surface_oes_external.frag",
- GL_TEXTURE_EXTERNAL_OES, 1, false,
+ 1, false,
QSGMaterial::Blending,
{}
},
- // BufferFormatEgl_Y_U_V
+ // BufferFormatEgl_Y_U_V (GL_TEXTURE_2D)
{
":/qt-project.org/wayland/compositor/shaders/surface.vert.qsb",
":/qt-project.org/wayland/compositor/shaders/surface_y_u_v.frag.qsb",
- GL_TEXTURE_2D, 3, false,
+ 3, false,
QSGMaterial::Blending,
{}
},
- // BufferFormatEgl_Y_UV
+ // BufferFormatEgl_Y_UV (GL_TEXTURE_2D)
{
":/qt-project.org/wayland/compositor/shaders/surface.vert.qsb",
":/qt-project.org/wayland/compositor/shaders/surface_y_uv.frag.qsb",
- GL_TEXTURE_2D, 2, false,
+ 2, false,
QSGMaterial::Blending,
{}
},
- // BufferFormatEgl_Y_XUXV
+ // BufferFormatEgl_Y_XUXV (GL_TEXTURE_2D)
{
":/qt-project.org/wayland/compositor/shaders/surface.vert.qsb",
":/qt-project.org/wayland/compositor/shaders/surface_y_xuxv.frag.qsb",
- GL_TEXTURE_2D, 2, false,
+ 2, false,
QSGMaterial::Blending,
{}
}
@@ -160,9 +157,9 @@ void QWaylandBufferMaterialShader::setupExternalOESShader(const QString &shaderF
descData->inVars = { texCoordInput };
QShaderDescription::InOutVariable fragColorOutput;
- texCoordInput.name = "gl_FragColor";
- texCoordInput.type = QShaderDescription::Vec4;
- texCoordInput.location = 0;
+ fragColorOutput.name = "gl_FragColor";
+ fragColorOutput.type = QShaderDescription::Vec4;
+ fragColorOutput.location = 0;
descData->outVars = { fragColorOutput };
@@ -453,9 +450,8 @@ private:
* Constructs a QWaylandQuickItem with the given \a parent.
*/
QWaylandQuickItem::QWaylandQuickItem(QQuickItem *parent)
- : QQuickItem(*new QWaylandQuickItemPrivate(), parent)
+ : QWaylandQuickItem(*new QWaylandQuickItemPrivate(), parent)
{
- d_func()->init();
}
/*!
@@ -465,6 +461,7 @@ QWaylandQuickItem::QWaylandQuickItem(QWaylandQuickItemPrivate &dd, QQuickItem *p
: QQuickItem(dd, parent)
{
d_func()->init();
+ connect(this, &QQuickItem::activeFocusChanged, this, &QWaylandQuickItem::updateFocus);
}
/*!
@@ -474,13 +471,16 @@ QWaylandQuickItem::~QWaylandQuickItem()
{
Q_D(QWaylandQuickItem);
disconnect(this, &QQuickItem::windowChanged, this, &QWaylandQuickItem::updateWindow);
+ disconnect(this, &QQuickItem::activeFocusChanged, this, &QWaylandQuickItem::updateFocus);
QMutexLocker locker(d->mutex);
- if (d->provider)
+ if (d->provider) {
+ disconnect(d->texProviderConnection);
d->provider->deleteLater();
+ }
}
/*!
- * \qmlproperty WaylandCompositor QtWaylandCompositor::WaylandQuickItem::compositor
+ * \qmlproperty WaylandCompositor QtWayland.Compositor::WaylandQuickItem::compositor
*
* This property holds the compositor for the surface rendered by this WaylandQuickItem.
*/
@@ -506,7 +506,7 @@ QWaylandView *QWaylandQuickItem::view() const
}
/*!
- * \qmlproperty WaylandSurface QtWaylandCompositor::WaylandQuickItem::surface
+ * \qmlproperty WaylandSurface QtWayland.Compositor::WaylandQuickItem::surface
*
* This property holds the surface rendered by this WaylandQuickItem.
*/
@@ -534,11 +534,13 @@ void QWaylandQuickItem::setSurface(QWaylandSurface *surface)
emit compositorChanged();
if (oldSurf != surface)
emit surfaceChanged();
+
+ updateFocus();
update();
}
/*!
- * \qmlproperty enum QtWaylandCompositor::WaylandQuickItem::origin
+ * \qmlproperty enum QtWayland.Compositor::WaylandQuickItem::origin
*
* This property holds the origin of the QWaylandQuickItem.
*/
@@ -757,7 +759,7 @@ void QWaylandQuickItem::keyPressEvent(QKeyEvent *event)
void QWaylandQuickItem::keyReleaseEvent(QKeyEvent *event)
{
Q_D(QWaylandQuickItem);
- if (d->shouldSendInputEvents() && hasFocus()) {
+ if (d->shouldSendInputEvents()) {
QWaylandSeat *seat = compositor()->seatFor(event);
seat->sendFullKeyEvent(event);
} else {
@@ -894,8 +896,15 @@ void QWaylandQuickItem::handlePlaceBelow(QWaylandSurface *referenceSurface)
}
}
+void QWaylandQuickItem::updateFocus()
+{
+ Q_D(const QWaylandQuickItem);
+ if (hasActiveFocus() && compositor())
+ compositor()->defaultSeat()->setKeyboardFocus(d->view->surface());
+}
+
/*!
- \qmlproperty object QtWaylandCompositor::WaylandQuickItem::subsurfaceHandler
+ \qmlproperty object QtWayland.Compositor::WaylandQuickItem::subsurfaceHandler
This property provides a way to override the default subsurface behavior.
@@ -934,6 +943,11 @@ void QWaylandQuickItem::setSubsurfaceHandler(QObject *handler)
}
/*!
+ * \qmlproperty WaylandOutput QtWayland.Compositor::WaylandQuickItem::output
+ *
+ * This property holds the output on which this item is displayed.
+ */
+/*!
* \property QWaylandQuickItem::output
*
* This property holds the output on which this item is displayed.
@@ -951,7 +965,7 @@ void QWaylandQuickItem::setOutput(QWaylandOutput *output)
}
/*!
- * \qmlproperty bool QtWaylandCompositor::WaylandQuickItem::bufferLocked
+ * \qmlproperty bool QtWayland.Compositor::WaylandQuickItem::bufferLocked
*
* This property holds whether the item's buffer is currently locked. As long as
* the buffer is locked, it will not be released and returned to the client.
@@ -1107,13 +1121,11 @@ void QWaylandQuickItem::takeFocus(QWaylandSeat *device)
textInput->setFocus(surface());
}
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- if (surface()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::TextInputV4)) {
- QWaylandTextInputV4 *textInputV4 = QWaylandTextInputV4::findIn(target);
- if (textInputV4)
- textInputV4->setFocus(surface());
+ if (surface()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::TextInputV3)) {
+ QWaylandTextInputV3 *textInputV3 = QWaylandTextInputV3::findIn(target);
+ if (textInputV3)
+ textInputV3->setFocus(surface());
}
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
if (surface()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::QtTextInputMethodV1)) {
QWaylandQtTextInputMethod *textInputMethod = QWaylandQtTextInputMethod::findIn(target);
@@ -1166,7 +1178,7 @@ void QWaylandQuickItem::updateSize()
}
/*!
- * \qmlproperty bool QtWaylandCompositor::WaylandQuickItem::focusOnClick
+ * \qmlproperty bool QtWayland.Compositor::WaylandQuickItem::focusOnClick
*
* This property specifies whether the WaylandQuickItem should take focus when
* it is clicked or touched.
@@ -1281,7 +1293,7 @@ QVariant QWaylandQuickItem::inputMethodQuery(Qt::InputMethodQuery query, QVarian
#endif
/*!
- \qmlproperty bool QtWaylandCompositor::WaylandQuickItem::paintEnabled
+ \qmlproperty bool QtWayland.Compositor::WaylandQuickItem::paintEnabled
Returns true if the item is hidden, though the texture
is still updated. As opposed to hiding the item by
@@ -1316,7 +1328,7 @@ void QWaylandQuickItem::setPaintEnabled(bool enabled)
}
/*!
- \qmlproperty bool QtWaylandCompositor::WaylandQuickItem::touchEventsEnabled
+ \qmlproperty bool QtWayland.Compositor::WaylandQuickItem::touchEventsEnabled
This property holds \c true if touch events are forwarded to the client
surface, \c false otherwise.
@@ -1411,7 +1423,7 @@ void QWaylandQuickItem::updateInputMethod(Qt::InputMethodQueries queries)
#endif
/*!
- * \qmlsignal void QtWaylandCompositor::WaylandQuickItem::surfaceDestroyed()
+ * \qmlsignal void QtWayland.Compositor::WaylandQuickItem::surfaceDestroyed()
*
* This signal is emitted when the client has destroyed the \c wl_surface associated
* with the WaylandQuickItem. The handler for this signal is expected to either destroy the
@@ -1478,8 +1490,24 @@ QSGNode *QWaylandQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
d->newTexture = true;
}
- if (!d->provider)
+ if (!d->provider) {
d->provider = new QWaylandSurfaceTextureProvider();
+ if (compositor()) {
+ d->texProviderConnection =
+ QObject::connect(
+ compositor(),
+ &QObject::destroyed,
+ this,
+ [this](QObject*) {
+ auto *itemPriv = QWaylandQuickItemPrivate::get(this);
+ if (itemPriv->provider) {
+ itemPriv->provider->deleteLater();
+ itemPriv->provider = nullptr;
+ }
+ disconnect(itemPriv->texProviderConnection); }
+ );
+ }
+ }
if (d->newTexture) {
d->newTexture = false;
diff --git a/src/compositor/compositor_api/qwaylandquickitem.h b/src/compositor/compositor_api/qwaylandquickitem.h
index bdb29842b..d30528a8a 100644
--- a/src/compositor/compositor_api/qwaylandquickitem.h
+++ b/src/compositor/compositor_api/qwaylandquickitem.h
@@ -140,6 +140,7 @@ private Q_SLOTS:
#if QT_CONFIG(im)
void updateInputMethod(Qt::InputMethodQueries queries);
#endif
+ void updateFocus();
Q_SIGNALS:
void surfaceChanged();
diff --git a/src/compositor/compositor_api/qwaylandquickitem_p.h b/src/compositor/compositor_api/qwaylandquickitem_p.h
index d3af887f7..0ddabc7da 100644
--- a/src/compositor/compositor_api/qwaylandquickitem_p.h
+++ b/src/compositor/compositor_api/qwaylandquickitem_p.h
@@ -22,6 +22,8 @@
#include <QtWaylandCompositor/QWaylandQuickItem>
#include <QtWaylandCompositor/QWaylandOutput>
+#include <QtCore/qpointer.h>
+
QT_BEGIN_NAMESPACE
class QWaylandSurfaceTextureProvider;
@@ -133,6 +135,7 @@ public:
QScopedPointer<QWaylandView> view;
QPointer<QWaylandSurface> oldSurface;
mutable QWaylandSurfaceTextureProvider *provider = nullptr;
+ QMetaObject::Connection texProviderConnection;
bool paintEnabled = true;
bool touchEventsEnabled = true;
bool inputEventsEnabled = true;
diff --git a/src/compositor/compositor_api/qwaylandquickoutput.cpp b/src/compositor/compositor_api/qwaylandquickoutput.cpp
index a388b1cc8..de6c3ede4 100644
--- a/src/compositor/compositor_api/qwaylandquickoutput.cpp
+++ b/src/compositor/compositor_api/qwaylandquickoutput.cpp
@@ -60,7 +60,7 @@ void QWaylandQuickOutput::update()
}
/*!
- * \qmlproperty bool QtWaylandCompositor::WaylandOutput::automaticFrameCallback
+ * \qmlproperty bool QtWayland.Compositor::WaylandOutput::automaticFrameCallback
*
* This property holds whether the WaylandOutput automatically sends frame
* callbacks when rendering.
diff --git a/src/compositor/compositor_api/qwaylandquicksurface.cpp b/src/compositor/compositor_api/qwaylandquicksurface.cpp
index 7921907fa..920415d68 100644
--- a/src/compositor/compositor_api/qwaylandquicksurface.cpp
+++ b/src/compositor/compositor_api/qwaylandquicksurface.cpp
@@ -37,7 +37,7 @@ QWaylandQuickSurface::~QWaylandQuickSurface()
}
/*!
- * \qmlproperty bool QtWaylandCompositor::WaylandSurface::useTextureAlpha
+ * \qmlproperty bool QtWayland.Compositor::WaylandSurface::useTextureAlpha
*
* This property specifies whether the surface should use texture alpha.
*/
diff --git a/src/compositor/compositor_api/qwaylandresource.cpp b/src/compositor/compositor_api/qwaylandresource.cpp
index 1060462b5..fc744c4b6 100644
--- a/src/compositor/compositor_api/qwaylandresource.cpp
+++ b/src/compositor/compositor_api/qwaylandresource.cpp
@@ -15,7 +15,7 @@ QT_BEGIN_NAMESPACE
* The QWaylandResource is a simple wrapper around the Wayland type \c wl_resource, and makes it
* possible to use wl_resource pointers in Qt Quick APIs.
*
- * \sa {Qt Wayland Compositor Examples - Custom Shell}
+ * \sa {Custom Shell}
*/
/*!
diff --git a/src/compositor/compositor_api/qwaylandseat.cpp b/src/compositor/compositor_api/qwaylandseat.cpp
index ee447da50..0e7df0ec0 100644
--- a/src/compositor/compositor_api/qwaylandseat.cpp
+++ b/src/compositor/compositor_api/qwaylandseat.cpp
@@ -23,9 +23,7 @@
#include "extensions/qwlqtkey_p.h"
#include "extensions/qwaylandtextinput.h"
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
-#include "extensions/qwaylandtextinputv4.h"
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
+#include "extensions/qwaylandtextinputv3.h"
#include "extensions/qwaylandqttextinputmethod.h"
QT_BEGIN_NAMESPACE
@@ -279,7 +277,7 @@ uint QWaylandSeat::sendTouchPointEvent(QWaylandSurface *surface, int id, const Q
}
/*!
- * \qmlmethod uint QtWaylandCompositor::WaylandSeat::sendTouchPointPressed(WaylandSurface surface, int id, point position)
+ * \qmlmethod uint QtWayland.Compositor::WaylandSeat::sendTouchPointPressed(WaylandSurface surface, int id, point position)
*
* Sends a touch pressed event for the touch point \a id on \a surface with
* position \a position.
@@ -313,7 +311,7 @@ uint QWaylandSeat::sendTouchPointPressed(QWaylandSurface *surface, int id, const
}
/*!
- * \qmlmethod void QtWaylandCompositor::WaylandSeat::sendTouchPointReleased(WaylandSurface surface, int id, point position)
+ * \qmlmethod void QtWayland.Compositor::WaylandSeat::sendTouchPointReleased(WaylandSurface surface, int id, point position)
*
* Sends a touch released event for the touch point \a id on \a surface with
* position \a position.
@@ -347,7 +345,7 @@ uint QWaylandSeat::sendTouchPointReleased(QWaylandSurface *surface, int id, cons
}
/*!
- * \qmlmethod void QtWaylandCompositor::WaylandSeat::sendTouchPointMoved(WaylandSurface surface, int id, point position)
+ * \qmlmethod void QtWayland.Compositor::WaylandSeat::sendTouchPointMoved(WaylandSurface surface, int id, point position)
*
* Sends a touch moved event for the touch point \a id on \a surface with
* position \a position.
@@ -381,7 +379,7 @@ uint QWaylandSeat::sendTouchPointMoved(QWaylandSurface *surface, int id, const Q
}
/*!
- * \qmlmethod void QtWaylandCompositor::WaylandSeat::sendTouchFrameEvent(WaylandClient client)
+ * \qmlmethod void QtWayland.Compositor::WaylandSeat::sendTouchFrameEvent(WaylandClient client)
*
* Sends a frame event to the touch device of a \a client to indicate the end
* of a series of touch up, down, and motion events.
@@ -399,7 +397,7 @@ void QWaylandSeat::sendTouchFrameEvent(QWaylandClient *client)
}
/*!
- * \qmlmethod void QtWaylandCompositor::WaylandSeat::sendTouchCancelEvent(WaylandClient client)
+ * \qmlmethod void QtWayland.Compositor::WaylandSeat::sendTouchCancelEvent(WaylandClient client)
*
* Sends a cancel event to the touch device of a \a client.
*/
@@ -434,6 +432,11 @@ void QWaylandSeat::sendFullTouchEvent(QWaylandSurface *surface, QTouchEvent *eve
/*!
* Sends the \a event to the keyboard device.
+ *
+ * \note The \a event should correspond to an actual keyboard key in the current mapping.
+ * For example, \c Qt::Key_Exclam is normally not a separate key: with most keyboards the
+ * exclamation mark is produced with Shift + 1. In that case, to send an exclamation mark
+ * key press event, use \c{QKeyEvent(QEvent::KeyPress, Qt::Key_1, Qt::ShiftModifier)}.
*/
void QWaylandSeat::sendFullKeyEvent(QKeyEvent *event)
{
@@ -463,17 +466,15 @@ void QWaylandSeat::sendFullKeyEvent(QKeyEvent *event)
}
}
-#if QT_WAYLAND_TEXT_INPUT_V4_WIP
- if (keyboardFocus()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::TextInputV4)) {
- QWaylandTextInputV4 *textInputV4 = QWaylandTextInputV4::findIn(this);
- if (textInputV4 && !event->text().isEmpty()) {
- // it will just commit the text for text-input-unstable-v4-wip when keyPress
+ if (keyboardFocus()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::TextInputV3)) {
+ QWaylandTextInputV3 *textInputV3 = QWaylandTextInputV3::findIn(this);
+ if (textInputV3 && !event->text().isEmpty()) {
+ // it will just commit the text for text-input-unstable-v3 when keyPress
if (event->type() == QEvent::KeyPress)
- textInputV4->sendKeyEvent(event);
+ textInputV3->sendKeyEvent(event);
return;
}
}
-#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
}
#endif
@@ -502,7 +503,7 @@ void QWaylandSeat::sendFullKeyEvent(QKeyEvent *event)
}
/*!
- * \qmlmethod void QtWaylandCompositor::WaylandSeat::sendKeyEvent(int qtKey, bool pressed)
+ * \qmlmethod void QtWayland.Compositor::WaylandSeat::sendKeyEvent(int qtKey, bool pressed)
* \since 5.12
*
* Sends a key press (if \a pressed is \c true) or release (if \a pressed is \c false)
@@ -513,6 +514,9 @@ void QWaylandSeat::sendFullKeyEvent(QKeyEvent *event)
* Sends a key press (if \a pressed is \c true) or release (if \a pressed is \c false)
* event of a key \a qtKey to the keyboard device.
*
+ * \note This function does not support key events that require modifiers, such as \c Qt::Key_Exclam.
+ * Use \l{sendFullKeyEvent} instead.
+ *
* \since 5.12
*/
void QWaylandSeat::sendKeyEvent(int qtKey, bool pressed)
@@ -534,6 +538,104 @@ void QWaylandSeat::sendKeyEvent(int qtKey, bool pressed)
}
/*!
+ * \qmlmethod void QtWayland.Compositor::WaylandSeat::sendUnicodeKeyPressEvent(uint unicode)
+ * \since 6.7
+ *
+ * Sends a key press event of a UCS4 \a unicode through a text-input protocol.
+ *
+ * \note This function will not work properly if the client does not support the
+ * text-input protocol that the compositor supports.
+ */
+
+/*!
+ * Sends a key press event of a UCS4 \a unicode through a text-input protocol.
+ *
+ * \note This function will not work properly if the client does not support the
+ * text-input protocol that the compositor supports.
+ *
+ * \sa {sendFullKeyEvent} {sendKeyEvent}
+ *
+ * \since 6.7
+ */
+void QWaylandSeat::sendUnicodeKeyPressEvent(uint unicode)
+{
+ sendUnicodeKeyEvent(unicode, QEvent::KeyPress);
+}
+
+/*!
+ * \qmlmethod void QtWayland.Compositor::WaylandSeat::sendUnicodeKeyReleaseEvent(uint unicode)
+ * \since 6.7
+ *
+ * Sends a key release event of a UCS4 \a unicode through a text-input protocol.
+ *
+ * \note This function will not work properly if the client does not support the
+ * text-input protocol that the compositor supports.
+ */
+
+/*!
+ * Sends a key release event of a UCS4 \a unicode through a text-input protocol.
+ *
+ * \note This function will not work properly if the client does not support the
+ * text-input protocol that the compositor supports.
+ *
+ * \sa {sendFullKeyEvent} {sendKeyEvent}
+ *
+ * \since 6.7
+ */
+void QWaylandSeat::sendUnicodeKeyReleaseEvent(uint unicode)
+{
+ sendUnicodeKeyEvent(unicode, QEvent::KeyRelease);
+}
+
+/*!
+ * \internal
+ *
+ * Sends an \a eventType for the UCS4 \a unicode through a text-input protocol.
+ */
+void QWaylandSeat::sendUnicodeKeyEvent(uint unicode, QEvent::Type eventType)
+{
+ if (!keyboardFocus()) {
+ qWarning("Can't send a unicode key event, no keyboard focus, fix the compositor");
+ return;
+ }
+#if QT_CONFIG(im)
+ QString text;
+ text += QChar::fromUcs4(static_cast<char32_t>(unicode));
+
+ QKeyEvent event(eventType, Qt::Key_unknown, Qt::KeyboardModifiers{}, text);
+ if (keyboardFocus()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::TextInputV2)) {
+ QWaylandTextInput *textInput = QWaylandTextInput::findIn(this);
+ if (textInput) {
+ textInput->sendKeyEvent(&event);
+ return;
+ }
+ }
+
+ if (keyboardFocus()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::QtTextInputMethodV1)) {
+ QWaylandQtTextInputMethod *textInputMethod = QWaylandQtTextInputMethod::findIn(this);
+ if (textInputMethod) {
+ textInputMethod->sendKeyEvent(&event);
+ return;
+ }
+ }
+
+ if (keyboardFocus()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::TextInputV3)) {
+ QWaylandTextInputV3 *textInputV3 = QWaylandTextInputV3::findIn(this);
+ if (textInputV3 && !text.isEmpty()) {
+ // it will just commit the text for text-input-unstable-v3 when keyPress
+ if (eventType == QEvent::KeyPress)
+ textInputV3->sendKeyEvent(&event);
+ return;
+ }
+ }
+#else
+ Q_UNUSED(unicode);
+ Q_UNUSED(eventType);
+ qWarning() << "Can't send a unicode key event: Unable to find a text-input protocol.";
+#endif
+}
+
+/*!
* Returns the keyboard for this input device.
*/
QWaylandKeyboard *QWaylandSeat::keyboard() const
@@ -705,7 +807,7 @@ void QWaylandSeat::handleMouseFocusDestroyed()
}
-/*! \qmlsignal void QtWaylandCompositor::QWaylandSeat::keyboardFocusChanged(QWaylandSurface newFocus, QWaylandSurface oldFocus)
+/*! \qmlsignal void QtWayland.Compositor::WaylandSeat::keyboardFocusChanged(QWaylandSurface newFocus, QWaylandSurface oldFocus)
*
* This signal is emitted when setKeyboardFocus() is called or when a WaylandQuickItem has focus
* and the user starts pressing keys.
@@ -725,7 +827,7 @@ void QWaylandSeat::handleMouseFocusDestroyed()
* \a oldFocus has the surface that lost keyboard focus; or \c nullptr if no surface had focus.
*/
-/*! \qmlsignal void QtWaylandCompositor::QWaylandSeat::cursorSurfaceRequest(QWaylandSurface surface, int hotspotX, int hotspotY)
+/*! \qmlsignal void QtWayland.Compositor::WaylandSeat::cursorSurfaceRequest(QWaylandSurface surface, int hotspotX, int hotspotY)
*
* This signal is emitted when the client has requested for a specific \a surface to be the mouse
* cursor. For example, when the user hovers over a particular surface, and you want the cursor
diff --git a/src/compositor/compositor_api/qwaylandseat.h b/src/compositor/compositor_api/qwaylandseat.h
index d789dff30..dd67e83ae 100644
--- a/src/compositor/compositor_api/qwaylandseat.h
+++ b/src/compositor/compositor_api/qwaylandseat.h
@@ -71,6 +71,9 @@ public:
void sendFullKeyEvent(QKeyEvent *event);
Q_INVOKABLE void sendKeyEvent(int qtKey, bool pressed);
+ Q_REVISION(6, 7) Q_INVOKABLE void sendUnicodeKeyPressEvent(uint unicode);
+ Q_REVISION(6, 7) Q_INVOKABLE void sendUnicodeKeyReleaseEvent(uint unicode);
+
uint sendTouchPointEvent(QWaylandSurface *surface, int id, const QPointF &point, Qt::TouchPointState state);
Q_INVOKABLE uint sendTouchPointPressed(QWaylandSurface *surface, int id, const QPointF &position);
Q_INVOKABLE uint sendTouchPointReleased(QWaylandSurface *surface, int id, const QPointF &position);
@@ -114,6 +117,8 @@ Q_SIGNALS:
void cursorSurfaceRequested(QWaylandSurface *surface, int hotspotX, int hotspotY, QWaylandClient *client);
private:
+ void sendUnicodeKeyEvent(uint unicode, QEvent::Type type);
+
void handleMouseFocusDestroyed();
};
diff --git a/src/compositor/compositor_api/qwaylandsurface.cpp b/src/compositor/compositor_api/qwaylandsurface.cpp
index 88147944e..207158bf7 100644
--- a/src/compositor/compositor_api/qwaylandsurface.cpp
+++ b/src/compositor/compositor_api/qwaylandsurface.cpp
@@ -101,9 +101,9 @@ QWaylandSurfacePrivate::~QWaylandSurfacePrivate()
bufferRef = QWaylandBufferRef();
- for (QtWayland::FrameCallback *c : qAsConst(pendingFrameCallbacks))
+ for (QtWayland::FrameCallback *c : std::as_const(pendingFrameCallbacks))
c->destroy();
- for (QtWayland::FrameCallback *c : qAsConst(frameCallbacks))
+ for (QtWayland::FrameCallback *c : std::as_const(frameCallbacks))
c->destroy();
}
@@ -177,18 +177,12 @@ void QWaylandSurfacePrivate::surface_attach(Resource *, struct wl_resource *buff
void QWaylandSurfacePrivate::surface_damage(Resource *, int32_t x, int32_t y, int32_t width, int32_t height)
{
- if (Q_UNLIKELY(pending.damageInBufferCoordinates && !pending.damage.isNull()))
- qCWarning(qLcWaylandCompositor) << "Unsupported: Client is using both wl_surface.damage_buffer and wl_surface.damage.";
- pending.damage = pending.damage.united(QRect(x, y, width, height));
- pending.damageInBufferCoordinates = false;
+ pending.surfaceDamage = pending.surfaceDamage.united(QRect(x, y, width, height));
}
void QWaylandSurfacePrivate::surface_damage_buffer(Resource *, int32_t x, int32_t y, int32_t width, int32_t height)
{
- if (Q_UNLIKELY(!pending.damageInBufferCoordinates && !pending.damage.isNull()))
- qCWarning(qLcWaylandCompositor) << "Unsupported: Client is using both wl_surface.damage_buffer and wl_surface.damage.";
- pending.damage = pending.damage.united(QRect(x, y, width, height));
- pending.damageInBufferCoordinates = true;
+ pending.bufferDamage = pending.bufferDamage.united(QRect(x, y, width, height));
}
void QWaylandSurfacePrivate::surface_frame(Resource *resource, uint32_t callback)
@@ -232,22 +226,23 @@ void QWaylandSurfacePrivate::surface_commit(Resource *)
sourceGeometry = !pending.sourceGeometry.isValid() ? QRect(QPoint(), surfaceSize) : pending.sourceGeometry;
destinationSize = pending.destinationSize.isEmpty() ? sourceGeometry.size().toSize() : pending.destinationSize;
QRect destinationRect(QPoint(), destinationSize);
- if (!pending.damageInBufferCoordinates || pending.bufferScale == 1) {
- // pending.damage is already in surface coordinates
- damage = pending.damage.intersected(QRect(QPoint(), destinationSize));
- } else {
- // We must transform pending.damage from buffer coordinate system to surface coordinates
- // TODO(QTBUG-85461): Also support wp_viewport setting more complex transformations
- auto xform = [](const QRect &r, int scale) -> QRect {
- QRect res{
- QPoint{ r.x() / scale, r.y() / scale },
- QPoint{ (r.right() + scale - 1) / scale, (r.bottom() + scale - 1) / scale }
+ // pending.damage is already in surface coordinates
+ damage = pending.surfaceDamage.intersected(destinationRect);
+ if (!pending.bufferDamage.isNull()) {
+ if (bufferScale == 1) {
+ damage |= pending.bufferDamage.intersected(destinationRect); // Already in surface coordinates
+ } else {
+ // We must transform pending.damage from buffer coordinate system to surface coordinates
+ // TODO(QTBUG-85461): Also support wp_viewport setting more complex transformations
+ auto xform = [](const QRect &r, int scale) -> QRect {
+ QRect res{
+ QPoint{ r.x() / scale, r.y() / scale },
+ QPoint{ (r.right() + scale - 1) / scale, (r.bottom() + scale - 1) / scale }
+ };
+ return res;
};
- return res;
- };
- damage = {};
- for (const QRect &r : pending.damage) {
- damage |= xform(r, bufferScale).intersected(destinationRect);
+ for (const QRect &r : pending.bufferDamage)
+ damage |= xform(r, bufferScale).intersected(destinationRect);
}
}
hasContent = bufferRef.hasContent();
@@ -269,14 +264,14 @@ void QWaylandSurfacePrivate::surface_commit(Resource *)
pending.buffer = QWaylandBufferRef();
pending.offset = QPoint();
pending.newlyAttached = false;
- pending.damage = QRegion();
- pending.damageInBufferCoordinates = false;
+ pending.bufferDamage = QRegion();
+ pending.surfaceDamage = QRegion();
pendingFrameCallbacks.clear();
// Notify buffers and views
if (auto *buffer = bufferRef.buffer())
buffer->setCommitted(damage);
- for (auto *view : qAsConst(views))
+ for (auto *view : std::as_const(views))
view->bufferCommitted(bufferRef, damage);
// Now all double-buffered state has been applied so it's safe to emit general signals
@@ -447,7 +442,7 @@ QWaylandSurface::~QWaylandSurface()
}
/*!
- * \qmlmethod void QtWaylandCompositor::WaylandSurface::initialize(WaylandCompositor compositor, WaylandClient client, int id, int version)
+ * \qmlmethod void QtWayland.Compositor::WaylandSurface::initialize(WaylandCompositor compositor, WaylandClient client, int id, int version)
*
* Initializes the WaylandSurface with the given \a compositor and \a client, and with the given \a id
* and \a version.
@@ -482,7 +477,7 @@ bool QWaylandSurface::isInitialized() const
}
/*!
- * \qmlproperty WaylandClient QtWaylandCompositor::WaylandSurface::client
+ * \qmlproperty WaylandClient QtWayland.Compositor::WaylandSurface::client
*
* This property holds the client using this WaylandSurface.
*/
@@ -513,7 +508,7 @@ QWaylandClient *QWaylandSurface::client() const
}
/*!
- * \qmlproperty bool QtWaylandCompositor::WaylandSurface::hasContent
+ * \qmlproperty bool QtWayland.Compositor::WaylandSurface::hasContent
*
* This property holds whether the WaylandSurface has content.
*/
@@ -530,7 +525,7 @@ bool QWaylandSurface::hasContent() const
}
/*!
- * \qmlproperty rect QtWaylandCompositor::WaylandSurface::sourceGeometry
+ * \qmlproperty rect QtWayland.Compositor::WaylandSurface::sourceGeometry
* \since 5.13
*
* This property describes the portion of the attached Wayland buffer that should
@@ -561,7 +556,7 @@ QRectF QWaylandSurface::sourceGeometry() const
}
/*!
- * \qmlproperty size QtWaylandCompositor::WaylandSurface::destinationSize
+ * \qmlproperty size QtWayland.Compositor::WaylandSurface::destinationSize
* \since 5.13
*
* This property holds the size of this WaylandSurface in surface coordinates.
@@ -586,7 +581,7 @@ QSize QWaylandSurface::destinationSize() const
}
/*!
- * \qmlproperty size QtWaylandCompositor::WaylandSurface::bufferSize
+ * \qmlproperty size QtWayland.Compositor::WaylandSurface::bufferSize
*
* This property holds the size of the current buffer of this WaylandSurface in pixels,
* not in surface coordinates.
@@ -615,7 +610,7 @@ QSize QWaylandSurface::bufferSize() const
}
/*!
- * \qmlproperty size QtWaylandCompositor::WaylandSurface::bufferScale
+ * \qmlproperty size QtWayland.Compositor::WaylandSurface::bufferScale
*
* This property holds the WaylandSurface's buffer scale. The buffer scale lets
* a client supply higher resolution buffer data for use on high resolution
@@ -636,7 +631,7 @@ int QWaylandSurface::bufferScale() const
}
/*!
- * \qmlproperty enum QtWaylandCompositor::WaylandSurface::contentOrientation
+ * \qmlproperty enum QtWayland.Compositor::WaylandSurface::contentOrientation
*
* This property holds the orientation of the WaylandSurface's contents.
*
@@ -666,7 +661,7 @@ Qt::ScreenOrientation QWaylandSurface::contentOrientation() const
*/
/*!
- * \qmlproperty enum QtWaylandCompositor::WaylandSurface::origin
+ * \qmlproperty enum QtWayland.Compositor::WaylandSurface::origin
*
* This property holds the origin of the WaylandSurface's buffer, or
* WaylandSurface.OriginTopLeft if the surface has no buffer.
@@ -705,7 +700,7 @@ QWaylandCompositor *QWaylandSurface::compositor() const
void QWaylandSurface::frameStarted()
{
Q_D(QWaylandSurface);
- for (QtWayland::FrameCallback *c : qAsConst(d->frameCallbacks))
+ for (QtWayland::FrameCallback *c : std::as_const(d->frameCallbacks))
c->canSend = true;
}
@@ -757,7 +752,7 @@ bool QWaylandSurface::inputRegionContains(const QPointF &position) const
}
/*!
- * \qmlmethod void QtWaylandCompositor::WaylandSurface::destroy()
+ * \qmlmethod void QtWayland.Compositor::WaylandSurface::destroy()
*
* Destroys the WaylandSurface.
*/
@@ -772,7 +767,7 @@ void QWaylandSurface::destroy()
}
/*!
- * \qmlmethod bool QtWaylandCompositor::WaylandSurface::isDestroyed()
+ * \qmlmethod bool QtWayland.Compositor::WaylandSurface::isDestroyed()
*
* Returns \c true if the WaylandSurface has been destroyed. Otherwise returns \c false.
*/
@@ -787,7 +782,7 @@ bool QWaylandSurface::isDestroyed() const
}
/*!
- * \qmlproperty bool QtWaylandCompositor::WaylandSurface::cursorSurface
+ * \qmlproperty bool QtWayland.Compositor::WaylandSurface::cursorSurface
*
* This property holds whether the WaylandSurface is a cursor surface.
*/
@@ -814,7 +809,7 @@ bool QWaylandSurface::isCursorSurface() const
}
/*!
- * \qmlproperty bool QtWaylandCompositor::WaylandSurface::inhibitsIdle
+ * \qmlproperty bool QtWayland.Compositor::WaylandSurface::inhibitsIdle
* \since 5.14
*
* This property holds whether this surface is intended to inhibit the idle
@@ -839,7 +834,7 @@ bool QWaylandSurface::inhibitsIdle() const
}
/*!
- * \qmlproperty bool QtWaylandCompositor::WaylandSurface::isOpaque
+ * \qmlproperty bool QtWayland.Compositor::WaylandSurface::isOpaque
* \since 6.4
*
* This property holds whether the surface is fully opaque, as reported by the
@@ -1080,7 +1075,7 @@ void QWaylandSurfacePrivate::Subsurface::subsurface_set_desync(wl_subsurface::Re
}
/*!
- * \qmlsignal QtWaylandCompositor::WaylandSurface::childAdded(WaylandSurface child)
+ * \qmlsignal QtWayland.Compositor::WaylandSurface::childAdded(WaylandSurface child)
*
* This signal is emitted when a wl_subsurface, \a child, has been added to the surface.
*/
@@ -1092,7 +1087,7 @@ void QWaylandSurfacePrivate::Subsurface::subsurface_set_desync(wl_subsurface::Re
*/
/*!
- * \qmlsignal QtWaylandCompositor::WaylandSurface::surfaceDestroyed()
+ * \qmlsignal QtWayland.Compositor::WaylandSurface::surfaceDestroyed()
*
* This signal is emitted when the corresponding wl_surface is destroyed.
*/
@@ -1104,7 +1099,7 @@ void QWaylandSurfacePrivate::Subsurface::subsurface_set_desync(wl_subsurface::Re
*/
/*!
- * \qmlsignal void QtWaylandCompositor::WaylandSurface::dragStarted(WaylandDrag drag)
+ * \qmlsignal void QtWayland.Compositor::WaylandSurface::dragStarted(WaylandDrag drag)
*
* This signal is emitted when a \a drag has started from this surface.
*/
diff --git a/src/compositor/compositor_api/qwaylandsurface_p.h b/src/compositor/compositor_api/qwaylandsurface_p.h
index c0beec7d5..b4df7498e 100644
--- a/src/compositor/compositor_api/qwaylandsurface_p.h
+++ b/src/compositor/compositor_api/qwaylandsurface_p.h
@@ -40,6 +40,8 @@
#include <QtWaylandCompositor/private/qwaylandviewporter_p.h>
#include <QtWaylandCompositor/private/qwaylandidleinhibitv1_p.h>
+#include <QtCore/qpointer.h>
+
QT_BEGIN_NAMESPACE
class QWaylandCompositor;
@@ -114,8 +116,8 @@ public: //member variables
struct {
QWaylandBufferRef buffer;
- QRegion damage;
- bool damageInBufferCoordinates = false;
+ QRegion surfaceDamage;
+ QRegion bufferDamage;
QPoint offset;
bool newlyAttached = false;
QRegion inputRegion;
diff --git a/src/compositor/compositor_api/qwaylandtouch.cpp b/src/compositor/compositor_api/qwaylandtouch.cpp
index 2e6957f9b..39aeac491 100644
--- a/src/compositor/compositor_api/qwaylandtouch.cpp
+++ b/src/compositor/compositor_api/qwaylandtouch.cpp
@@ -73,7 +73,7 @@ int QWaylandTouchPrivate::toSequentialWaylandId(int touchId)
return availableId;
}
ids.append(touchId);
- return ids.length() - 1;
+ return ids.size() - 1;
}
/*!
@@ -189,7 +189,7 @@ void QWaylandTouch::sendFullTouchEvent(QWaylandSurface *surface, QTouchEvent *ev
if (points.isEmpty())
return;
- const int pointCount = points.count();
+ const int pointCount = points.size();
for (int i = 0; i < pointCount; ++i) {
const QTouchEvent::TouchPoint &tp(points.at(i));
// Convert the local pos in the compositor window to surface-relative.
diff --git a/src/compositor/compositor_api/qwaylandview.cpp b/src/compositor/compositor_api/qwaylandview.cpp
index 88d90e198..f8a0f38af 100644
--- a/src/compositor/compositor_api/qwaylandview.cpp
+++ b/src/compositor/compositor_api/qwaylandview.cpp
@@ -11,6 +11,7 @@
#include <QtWaylandCompositor/private/qwaylandoutput_p.h>
#include <QtCore/QMutex>
+#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
@@ -84,7 +85,7 @@ QObject *QWaylandView::renderObject() const
}
/*!
- * \qmlproperty WaylandSurface QtWaylandCompositor::WaylandView::surface
+ * \qmlproperty WaylandSurface QtWayland.Compositor::WaylandView::surface
*
* This property holds the surface viewed by this WaylandView.
*/
@@ -143,7 +144,7 @@ void QWaylandView::setSurface(QWaylandSurface *newSurface)
}
/*!
- * \qmlproperty WaylandOutput QtWaylandCompositor::WaylandView::output
+ * \qmlproperty WaylandOutput QtWayland.Compositor::WaylandView::output
*
* This property holds the output on which this view displays its surface.
*/
@@ -258,7 +259,7 @@ QRegion QWaylandView::currentDamage()
}
/*!
- * \qmlproperty bool QtWaylandCompositor::WaylandView::bufferLocked
+ * \qmlproperty bool QtWayland.Compositor::WaylandView::bufferLocked
*
* This property holds whether the view's buffer is currently locked. When
* the buffer is locked, advance() will not advance to the next buffer and
@@ -291,7 +292,7 @@ void QWaylandView::setBufferLocked(bool locked)
emit bufferLockedChanged();
}
/*!
- * \qmlproperty bool QtWaylandCompositor::WaylandView::allowDiscardFrontBuffer
+ * \qmlproperty bool QtWayland.Compositor::WaylandView::allowDiscardFrontBuffer
*
* By default, the view locks the current buffer until advance() is called. Set this property
* to true to allow Qt to release the buffer when the primary view is no longer using it.
diff --git a/src/compositor/configure.cmake b/src/compositor/configure.cmake
index 8cbb40f31..10f1d4a20 100644
--- a/src/compositor/configure.cmake
+++ b/src/compositor/configure.cmake
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#### Inputs
diff --git a/src/compositor/doc/qtwaylandcompositor.qdocconf b/src/compositor/doc/qtwaylandcompositor.qdocconf
index febb05241..fae83583f 100644
--- a/src/compositor/doc/qtwaylandcompositor.qdocconf
+++ b/src/compositor/doc/qtwaylandcompositor.qdocconf
@@ -28,7 +28,19 @@ qhp.QtWaylandCompositor.subprojects.examples.indexTitle = Qt Wayland Composi
qhp.QtWaylandCompositor.subprojects.examples.selectors = fake:example
qhp.QtWaylandCompositor.subprojects.examples.sortPages = true
-depends += qtcore qtqml qtquick qtdoc qtquickcontrols qmake qtgui qtqmlmodels qtwidgets qtvirtualkeyboard
+depends += qtcore \
+ qtqml \
+ qtquick \
+ qtdoc \
+ qtquickcontrols \
+ qmake \
+ qtgui \
+ qtqmlmodels \
+ qtwidgets \
+ qtvirtualkeyboard \
+ qtcmake \
+ qtopengl \
+ qtwaylandclient
exampledirs += ../../../examples/wayland
headerdirs += \
@@ -44,12 +56,13 @@ examplesinstallpath = wayland
# Add generic thumbnail for all examples
manifestmeta.thumbnail.names = *
-Cpp.ignoretokens += Q_WAYLANDCOMPOSITOR_EXPORT
-Cpp.ignoredirectives += Q_DECLARE_LOGGING_CATEGORY
+manifestmeta.highlighted.names = \
+ "QtWaylandCompositor/Minimal QML" \
+ "QtWaylandCompositor/IVI Compositor"
navigation.landingpage = "Qt Wayland Compositor"
navigation.qmltypespage = "Qt Wayland Compositor QML Types"
navigation.cppclassespage = "Qt Wayland Compositor C++ Classes"
-# Enforce zero warnings when building the documentation
+# Enforce zero documentation warnings
warninglimit = 0
diff --git a/src/compositor/doc/src/cmake/qt_generate_wayland_protocol_server_sources.qdoc b/src/compositor/doc/src/cmake/qt_generate_wayland_protocol_server_sources.qdoc
new file mode 100644
index 000000000..5a5849463
--- /dev/null
+++ b/src/compositor/doc/src/cmake/qt_generate_wayland_protocol_server_sources.qdoc
@@ -0,0 +1,47 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt-generate-wayland-protocol-server-sources.html
+\ingroup cmake-commands-qtwaylandcompositor
+
+\title qt_generate_wayland_protocol_server_sources
+\keyword qt6_generate_wayland_protocol_server_sources
+
+\summary {Generates server-side C++ bindings for a Wayland protocol .XML file}
+
+\cmakecommandsince 6.0
+
+The command is defined in the \c WaylandCompositor component of the \c Qt6 package, which
+can be loaded like so:
+
+\badcode
+find_package(Qt6 REQUIRED COMPONENTS WaylandCompositor)
+\endcode
+
+\section1 Synopsis
+
+\badcode
+qt_generate_wayland_protocol_server_sources(target
+ FILES file1.xml [file2.xml ...])
+\endcode
+
+\versionlessCMakeCommandsNote qt6_generate_wayland_protocol_server_sources()
+
+\section1 Description
+
+qt_generate_wayland_protocol_server_sources() creates the build steps to run \c{waylandscanner} and
+\c{qtwaylandscanner} on one or more Wayland protocol files. The tools will in turn generate binding
+code in C and C++ for implementing the protocols, and the resulting files will be built as part
+of the \c target.
+
+qt_generate_wayland_protocol_server_sources() will trigger generation of the files needed to
+implement the compositor side of the protocol.
+
+\l{qt_generate_wayland_protocol_client_sources}{qt_generate_wayland_protocol_client_sources()}
+is the equivalent function for the client.
+
+See the \l{Custom Shell} or \l{Custom Extension} examples for a demonstration of how to use these
+functions.
+*/
+
diff --git a/src/compositor/doc/src/qtwaylandcompositor-cpp.qdoc b/src/compositor/doc/src/qtwaylandcompositor-cpp.qdoc
index 62175cc57..a61278d73 100644
--- a/src/compositor/doc/src/qtwaylandcompositor-cpp.qdoc
+++ b/src/compositor/doc/src/qtwaylandcompositor-cpp.qdoc
@@ -5,22 +5,22 @@
\module QtWaylandCompositor
\title Qt Wayland Compositor C++ Classes
\ingroup modules
- \qtcmakepackage Waylandcompositor
+ \qtcmakepackage WaylandCompositor
\qtvariable waylandcompositor
\brief Provides C++ classes for writing custom Wayland display servers.
- To include the definitions of the module's classes, use the following directive:
+ \section1 Using the Module
- \code
- #include <QtWaylandCompositor>
- \endcode
+ \include {module-use.qdocinc} {using the c++ api} {WaylandCompositor}
- To link against the module, add this line to your \l qmake \c .pro file:
+ \section2 Building with CMake
- \code
- QT += waylandcompositor
- \endcode
+ \include {module-use.qdocinc} {building with cmake} {WaylandCompositor}
+
+ \section2 Building with qmake
+
+ \include {module-use.qdocinc} {building_with_qmake} {waylandcompositor}
For more information about using these classes in your application,
see the \l{Qt Wayland Compositor} documentation.
diff --git a/src/compositor/doc/src/qtwaylandcompositor-overview.qdoc b/src/compositor/doc/src/qtwaylandcompositor-overview.qdoc
index dde06dbd8..cf24fbc57 100644
--- a/src/compositor/doc/src/qtwaylandcompositor-overview.qdoc
+++ b/src/compositor/doc/src/qtwaylandcompositor-overview.qdoc
@@ -97,11 +97,11 @@
when starting the compositor. The \c XDG_RUNTIME_DIR can point to any accessible location which
is not already in use.
- For instance, if you want to run the \l{Qt Wayland Compositor Examples - Pure QML}{pure-qml}
+ For instance, if you want to run the \l{Fancy Compositor}{fancy-compositor}
example with the \c wayland-egl backend, you could use the following command line:
\code
- % XDG_RUNTIME_DIR=~/my_temporary_runtime QT_XCB_GL_INTEGRATION=xcb_egl QT_WAYLAND_CLIENT_BUFFER_INTEGRATION=wayland-egl ./pure-qml
+ % XDG_RUNTIME_DIR=~/my_temporary_runtime QT_XCB_GL_INTEGRATION=xcb_egl QT_WAYLAND_CLIENT_BUFFER_INTEGRATION=wayland-egl ./fancy-compositor
\endcode
The client can subsequently be run on the compositor by setting the same \c XDG_RUNTIME_DIR and
@@ -141,6 +141,9 @@
\li \l{Qt Wayland Compositor C++ Classes}
\endlist
+ In addition, the module provides the CMake function
+ \l{qt_generate_wayland_protocol_server_sources}{qt_generate_wayland_protocol_server_sources()}.
+
\section1 Module Evolution
\l{Porting to Qt 6 - Qt Wayland Compositor} lists important changes in the
module API and functionality that were done for the Qt 6 series of Qt.
@@ -153,7 +156,7 @@
In addition, Qt Wayland Compositor is available under the
\l{GNU General Public License, version 3}, while
the Qt Wayland integration plugin is available under the
- \l{GNU General Public License, version 3} or the
+ \l{GNU Lesser General Public License, version 3} or the
\l{GNU General Public License, version 2}.
See \l{Qt Licensing} for further details.
diff --git a/src/compositor/doc/src/qtwaylandcompositor-qmltypes.qdoc b/src/compositor/doc/src/qtwaylandcompositor-qmltypes.qdoc
index 7d0a52d6f..a496d3e00 100644
--- a/src/compositor/doc/src/qtwaylandcompositor-qmltypes.qdoc
+++ b/src/compositor/doc/src/qtwaylandcompositor-qmltypes.qdoc
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
- \qmlmodule QtWayland.Compositor 1.\QtMinorVersion
+ \qmlmodule QtWayland.Compositor
\title Qt Wayland Compositor QML Types
\ingroup qmlmodules
\brief Provides QML types for writing custom Wayland display servers.
@@ -13,15 +13,23 @@
The QML types can be imported into your application using the following
import statement:
- \qml
- import QtWayland.Compositor
- \endqml
+ \section1 Using the Module
+
+ \include {module-use.qdocinc} {using the c++ api} {WaylandCompositor}
+
+ \section2 Building with CMake
+
+ \include {module-use.qdocinc} {building with cmake} {WaylandCompositor}
- To link against the module, add this line to your \l qmake \c .pro file:
+ \section2 Building with qmake
- \badcode
- QT += waylandcompositor
- \endcode
+ \include {module-use.qdocinc} {building_with_qmake} {waylandcompositor}
+
+ \section2 QML import
+
+ \qml
+ import QtWayland.Compositor
+ \endqml
For more information about using these types in your application,
see the \l{Qt Wayland Compositor} documentation.
diff --git a/src/compositor/doc/src/qtwaylandcompositor-shellextensions.qdoc b/src/compositor/doc/src/qtwaylandcompositor-shellextensions.qdoc
index ceff72a71..5494eeda3 100644
--- a/src/compositor/doc/src/qtwaylandcompositor-shellextensions.qdoc
+++ b/src/compositor/doc/src/qtwaylandcompositor-shellextensions.qdoc
@@ -31,8 +31,7 @@
\li \l IviApplication is a minimalistic protocol, originally intended for In-vehicle
Infotainment systems. It is useful for embedded systems, where a pre-defined set of
applications can run, often with pre-assigned screen real estate. For some more details
- on this protocol, see the
- \l{Qt Wayland Compositor Examples - IVI Compositor}{IVI Compositor example}.
+ on this protocol, see the \l{IVI Compositor}{IVI Compositor example}.
\li \l QtShell is a specialized shell for Qt applications which supports the window management
features available in Qt. It may be suitable on a platform where both the compositor and
client applications are written with Qt, and where applications are trusted not to abuse
@@ -47,6 +46,6 @@
applications involved which are not written in Qt and which have their own requirements.
A Qt Wayland Compositor can also support multiple shell extensions at once. See the
- \l{Qt Wayland Compositor Examples - Minimal QML}{Minimal QML example} for an example where
- all three shell extensions listed above are supported.
+ \l{Minimal QML}{Minimal QML example} for an example where all three shell extensions listed
+ above are supported.
*/
diff --git a/src/compositor/extensions/qwaylandidleinhibitv1_p.h b/src/compositor/extensions/qwaylandidleinhibitv1_p.h
index a2e3323e9..1899c109e 100644
--- a/src/compositor/extensions/qwaylandidleinhibitv1_p.h
+++ b/src/compositor/extensions/qwaylandidleinhibitv1_p.h
@@ -9,6 +9,8 @@
#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h>
#include <QtWaylandCompositor/private/qwayland-server-idle-inhibit-unstable-v1.h>
+#include <QtCore/qpointer.h>
+
//
// W A R N I N G
// -------------
diff --git a/src/compositor/extensions/qwaylandiviapplication.cpp b/src/compositor/extensions/qwaylandiviapplication.cpp
index 5d86c40cf..db9130829 100644
--- a/src/compositor/extensions/qwaylandiviapplication.cpp
+++ b/src/compositor/extensions/qwaylandiviapplication.cpp
@@ -106,7 +106,7 @@ QByteArray QWaylandIviApplication::interfaceName()
}
/*!
- * \qmlsignal void QtWaylandCompositor::IviApplication::iviSurfaceRequested(WaylandSurface surface, int iviId, WaylandResource resource)
+ * \qmlsignal void IviApplication::iviSurfaceRequested(WaylandSurface surface, int iviId, WaylandResource resource)
*
* This signal is emitted when the client has requested an \c ivi_surface to be associated
* with \a surface, which is identified by \a iviId. The handler for this signal is
@@ -125,7 +125,7 @@ QByteArray QWaylandIviApplication::interfaceName()
*/
/*!
- * \qmlsignal void QtWaylandCompositor::IviApplication::iviSurfaceCreated(IviSurface *iviSurface)
+ * \qmlsignal void IviApplication::iviSurfaceCreated(IviSurface *iviSurface)
*
* This signal is emitted when an IviSurface has been created. The supplied \a iviSurface is
* most commonly used to instantiate a ShellSurfaceItem.
diff --git a/src/compositor/extensions/qwaylandivisurface.cpp b/src/compositor/extensions/qwaylandivisurface.cpp
index 8d89f3f23..493416abf 100644
--- a/src/compositor/extensions/qwaylandivisurface.cpp
+++ b/src/compositor/extensions/qwaylandivisurface.cpp
@@ -61,7 +61,7 @@ QWaylandIviSurface::QWaylandIviSurface(QWaylandIviApplication *application, QWay
}
/*!
- * \qmlmethod void QtWaylandCompositor::IviSurface::initialize(IviApplication iviApplication, WaylandSurface surface, int iviId, WaylandResource resource)
+ * \qmlmethod void IviSurface::initialize(IviApplication iviApplication, WaylandSurface surface, int iviId, WaylandResource resource)
*
* Initializes the IviSurface, associating it with the given \a iviApplication, \a surface,
* \a iviId, and \a resource.
@@ -89,7 +89,7 @@ void QWaylandIviSurface::initialize(QWaylandIviApplication *iviApplication, QWay
}
/*!
- * \qmlproperty WaylandSurface QtWaylandCompositor::IviSurface::surface
+ * \qmlproperty WaylandSurface IviSurface::surface
*
* This property holds the surface associated with this IviSurface.
*/
@@ -106,7 +106,7 @@ QWaylandSurface *QWaylandIviSurface::surface() const
}
/*!
- * \qmlproperty int QtWaylandCompositor::IviSurface::iviId
+ * \qmlproperty int IviSurface::iviId
* \readonly
*
* This property holds the ivi id id of this IviSurface.
@@ -155,7 +155,7 @@ QWaylandIviSurface *QWaylandIviSurface::fromResource(wl_resource *resource)
}
/*!
- * \qmlmethod int QtWaylandCompositor::IviSurface::sendConfigure(size size)
+ * \qmlmethod int IviSurface::sendConfigure(size size)
*
* Sends a configure event to the client, telling it to resize the surface to the given \a size.
*/
diff --git a/src/compositor/extensions/qwaylandivisurface.h b/src/compositor/extensions/qwaylandivisurface.h
index 4a707bc14..09f18c3ed 100644
--- a/src/compositor/extensions/qwaylandivisurface.h
+++ b/src/compositor/extensions/qwaylandivisurface.h
@@ -5,7 +5,9 @@
#define QWAYLANDIVISURFACE_H
#include <QtWaylandCompositor/QWaylandShellSurface>
+#if QT_CONFIG(wayland_compositor_quick)
#include <QtWaylandCompositor/qwaylandquickchildren.h>
+#endif
struct wl_resource;
@@ -21,7 +23,9 @@ class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandIviSurface : public QWaylandShellSurfac
{
Q_OBJECT
Q_DECLARE_PRIVATE(QWaylandIviSurface)
+#if QT_CONFIG(wayland_compositor_quick)
Q_WAYLAND_COMPOSITOR_DECLARE_QUICK_CHILDREN(QWaylandIviSurface)
+#endif
Q_PROPERTY(QWaylandSurface *surface READ surface NOTIFY surfaceChanged)
Q_PROPERTY(uint iviId READ iviId NOTIFY iviIdChanged)
Q_MOC_INCLUDE("qwaylandsurface.h")
diff --git a/src/compositor/extensions/qwaylandivisurface_p.h b/src/compositor/extensions/qwaylandivisurface_p.h
index f1477dbdb..d721dff69 100644
--- a/src/compositor/extensions/qwaylandivisurface_p.h
+++ b/src/compositor/extensions/qwaylandivisurface_p.h
@@ -4,7 +4,7 @@
#ifndef QWAYLANDIVISURFACE_P_H
#define QWAYLANDIVISURFACE_P_H
-#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h>
+#include <QtWaylandCompositor/private/qwaylandshellsurface_p.h>
#include <QtWaylandCompositor/private/qwayland-server-ivi-application.h>
#include <QtWaylandCompositor/QWaylandIviSurface>
@@ -25,7 +25,7 @@
QT_BEGIN_NAMESPACE
class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandIviSurfacePrivate
- : public QWaylandCompositorExtensionPrivate
+ : public QWaylandShellSurfacePrivate
, public QtWaylandServer::ivi_surface
{
Q_DECLARE_PUBLIC(QWaylandIviSurface)
diff --git a/src/compositor/extensions/qwaylandpresentationtime.cpp b/src/compositor/extensions/qwaylandpresentationtime.cpp
index d47f60167..637fc5d68 100644
--- a/src/compositor/extensions/qwaylandpresentationtime.cpp
+++ b/src/compositor/extensions/qwaylandpresentationtime.cpp
@@ -104,7 +104,7 @@ QWaylandCompositor *QWaylandPresentationTime::compositor() const
}
/*!
- * \qmlmethod void QWaylandCompositor::PresentationTime::sendFeedback(Window window, int sequence, int sec, int nsec)
+ * \qmlmethod void PresentationTime::sendFeedback(Window window, int sequence, int sec, int nsec)
*
* Interface to notify that a frame is presented on screen using \a window.
* If your platform supports DRM events, \c page_flip_handler is the proper timing to send it.
diff --git a/src/compositor/extensions/qwaylandpresentationtime_p.h b/src/compositor/extensions/qwaylandpresentationtime_p.h
index 3b6d28379..c57cd91d2 100644
--- a/src/compositor/extensions/qwaylandpresentationtime_p.h
+++ b/src/compositor/extensions/qwaylandpresentationtime_p.h
@@ -4,6 +4,17 @@
#ifndef QWAYLANDPRESENTATIONTIME_P_H
#define QWAYLANDPRESENTATIONTIME_P_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <QObject>
#include <QtWaylandCompositor/qwaylandcompositorextension.h>
#include <QtCore/private/qglobal_p.h>
@@ -29,7 +40,7 @@ public:
static const struct wl_interface *interface();
static QByteArray interfaceName();
-signals:
+Q_SIGNALS:
void presented(quint64 sequence, quint64 tv_sec, quint32 tv_nsec, quint32 refresh_nsec);
};
diff --git a/src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp b/src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp
index 28806f622..7eb1479f5 100644
--- a/src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp
+++ b/src/compositor/extensions/qwaylandquickshellsurfaceitem.cpp
@@ -18,9 +18,8 @@ QWaylandQuickShellSurfaceItem *QWaylandQuickShellSurfaceItemPrivate::maybeCreate
auto *popupItem = new QWaylandQuickShellSurfaceItem(q);
popupItem->setShellSurface(shellSurface);
popupItem->setAutoCreatePopupItems(true);
- QObject::connect(popupItem, &QWaylandQuickShellSurfaceItem::surfaceDestroyed, [popupItem](){
- popupItem->deleteLater();
- });
+ QObject::connect(popupItem, &QWaylandQuickShellSurfaceItem::surfaceDestroyed,
+ popupItem, &QObject::deleteLater);
return popupItem;
}
@@ -77,7 +76,7 @@ QWaylandQuickShellSurfaceItem::QWaylandQuickShellSurfaceItem(QWaylandQuickShellS
}
/*!
- * \qmlproperty ShellSurface QtWaylandCompositor::ShellSurfaceItem::shellSurface
+ * \qmlproperty ShellSurface QtWayland.Compositor::ShellSurfaceItem::shellSurface
*
* This property holds the ShellSurface rendered by this ShellSurfaceItem.
* It may either be an XdgSurfaceV5, WlShellSurface or IviSurface depending on which shell protocol
@@ -103,6 +102,9 @@ void QWaylandQuickShellSurfaceItem::setShellSurface(QWaylandShellSurface *shellS
if (d->m_shellSurface == shellSurface)
return;
+ if (Q_UNLIKELY(d->m_shellSurface))
+ disconnect(d->m_shellSurface, &QWaylandShellSurface::modalChanged, this, nullptr);
+
d->m_shellSurface = shellSurface;
if (d->m_shellIntegration) {
@@ -116,11 +118,14 @@ void QWaylandQuickShellSurfaceItem::setShellSurface(QWaylandShellSurface *shellS
installEventFilter(d->m_shellIntegration);
}
+ connect(shellSurface, &QWaylandShellSurface::modalChanged, this,
+ [d](){ if (d->m_shellSurface->modal()) d->raise(); });
+
emit shellSurfaceChanged();
}
/*!
- * \qmlproperty Item QtWaylandCompositor::ShellSurfaceItem::moveItem
+ * \qmlproperty Item QtWayland.Compositor::ShellSurfaceItem::moveItem
*
* This property holds the move item for this ShellSurfaceItem. This is the item that will be moved
* when the clients request the ShellSurface to be moved, maximized, resized etc. This property is
@@ -151,7 +156,7 @@ void QWaylandQuickShellSurfaceItem::setMoveItem(QQuickItem *moveItem)
}
/*!
- * \qmlproperty bool QtWaylandCompositor::ShellSurfaceItem::autoCreatePopupItems
+ * \qmlproperty bool QtWayland.Compositor::ShellSurfaceItem::autoCreatePopupItems
*
* This property holds whether ShellSurfaceItems for popups parented to the shell
* surface managed by this item should automatically be created.
@@ -300,11 +305,22 @@ static QWaylandQuickShellSurfaceItem *findSurfaceItemFromMoveItem(QQuickItem *mo
return nullptr;
}
+static inline bool onTop(QWaylandQuickShellSurfaceItem *surf)
+{
+ return surf->staysOnTop() || surf->shellSurface()->modal();
+}
+
+static inline bool onBottom(QWaylandQuickShellSurfaceItem *surf)
+{
+ return surf->staysOnBottom() && !surf->shellSurface()->modal();
+}
+
/*
To raise a surface, find the topmost suitable surface and place above that.
We start from the top and:
If we don't have staysOnTop, skip all surfaces with staysOnTop
If we have staysOnBottom, skip all surfaces that don't have staysOnBottom
+ A modal dialog is handled as if it had staysOnTop
*/
void QWaylandQuickShellSurfaceItemPrivate::raise()
{
@@ -313,17 +329,23 @@ void QWaylandQuickShellSurfaceItemPrivate::raise()
QQuickItem *parent = moveItem->parentItem();
if (!parent)
return;
+ const bool putOnTop = staysOnTop || m_shellSurface->modal();
+ const bool putOnBottom = staysOnBottom && !m_shellSurface->modal();
+
auto it = parent->childItems().crbegin();
- auto skip = [this](QQuickItem *item) {
+ auto skip = [=](QQuickItem *item) {
if (auto *surf = findSurfaceItemFromMoveItem(item))
- return (!staysOnTop && surf->staysOnTop()) || (staysOnBottom && !surf->staysOnBottom());
+ return (!putOnTop && onTop(surf)) || (putOnBottom && !onBottom(surf));
return true; // ignore any other Quick items that may be there
};
- while (skip(*it))
+ auto end = parent->childItems().crend();
+ while (it != end && skip(*it))
++it;
- QQuickItem *top = *it;
- if (moveItem != top)
- moveItem->stackAfter(top);
+ if (it != end) {
+ QQuickItem *top = *it;
+ if (moveItem != top)
+ moveItem->stackAfter(top);
+ }
}
/*
@@ -331,6 +353,7 @@ void QWaylandQuickShellSurfaceItemPrivate::raise()
We start from the bottom and:
If we don't have staysOnBottom, skip all surfaces with staysOnBottom
If we have staysOnTop, skip all surfaces that don't have staysOnTop
+ A modal dialog is handled as if it had staysOnTop
*/
void QWaylandQuickShellSurfaceItemPrivate::lower()
{
@@ -339,11 +362,13 @@ void QWaylandQuickShellSurfaceItemPrivate::lower()
QQuickItem *parent = moveItem->parentItem();
if (!parent)
return;
- auto it = parent->childItems().cbegin();
+ const bool putOnTop = staysOnTop || m_shellSurface->modal();
+ const bool putOnBottom = staysOnBottom && !m_shellSurface->modal();
- auto skip = [this](QQuickItem *item) {
+ auto it = parent->childItems().cbegin();
+ auto skip = [=](QQuickItem *item) {
if (auto *surf = findSurfaceItemFromMoveItem(item))
- return (!staysOnBottom && surf->staysOnBottom()) || (staysOnTop && !surf->staysOnTop());
+ return (!putOnBottom && onBottom(surf)) || (putOnTop && !onTop(surf));
return true; // ignore any other Quick items that may be there
};
while (skip(*it))
diff --git a/src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h b/src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h
index 12518f580..46e5f65a5 100644
--- a/src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h
+++ b/src/compositor/extensions/qwaylandquickshellsurfaceitem_p.h
@@ -7,7 +7,9 @@
#include <QtWaylandCompositor/QWaylandQuickShellSurfaceItem>
#include <QtWaylandCompositor/QWaylandQuickShellIntegration>
#include <QtWaylandCompositor/private/qwaylandquickitem_p.h>
+
#include <QtCore/QBasicTimer>
+#include <QtCore/qpointer.h>
#include <functional>
diff --git a/src/compositor/extensions/qwaylandshell.cpp b/src/compositor/extensions/qwaylandshell.cpp
index 3c22afb4c..68f9d839b 100644
--- a/src/compositor/extensions/qwaylandshell.cpp
+++ b/src/compositor/extensions/qwaylandshell.cpp
@@ -29,7 +29,7 @@ QWaylandShell::QWaylandShell(QWaylandObject *waylandObject)
*/
/*!
- * \qmlproperty enumeration QtWaylandCompositor::Shell::focusPolicy
+ * \qmlproperty enumeration Shell::focusPolicy
*
* This property holds the focus policy of the Shell.
*/
diff --git a/src/compositor/extensions/qwaylandshellsurface.cpp b/src/compositor/extensions/qwaylandshellsurface.cpp
index fe15739f2..7e2fcee60 100644
--- a/src/compositor/extensions/qwaylandshellsurface.cpp
+++ b/src/compositor/extensions/qwaylandshellsurface.cpp
@@ -1,7 +1,7 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-#include <QtWaylandCompositor/QWaylandShellSurface>
+#include "qwaylandshellsurface_p.h"
/*!
* \class QWaylandShellSurfaceTemplate
@@ -26,7 +26,7 @@
*
* The same usage pattern applies as for QWaylandCompositorExtensionTemplate.
*
- * \sa {Qt Wayland Compositor Examples - Custom Shell}
+ * \sa { Custom Shell}
*/
/*!
@@ -81,7 +81,7 @@
#endif
/*!
- * \qmlproperty enum QtWaylandCompositor::ShellSurface::windowType
+ * \qmlproperty enum QtWayland.Compositor::ShellSurface::windowType
*
* This property holds the window type of the ShellSurface.
*/
@@ -92,8 +92,52 @@
* This property holds the window type of the QWaylandShellSurface.
*/
+/*!
+ * \qmlproperty bool QtWayland.Compositor::ShellSurface::modal
+ *
+ * This property is true if the ShellSurface represents a modal dialog.
+ * \since 6.8
+ */
+
+/*!
+ * \property QWaylandShellSurface::modal
+ *
+ * This property is true if the ShellSurface represents a modal dialog.
+ * \since 6.8
+ */
+
QT_BEGIN_NAMESPACE
+QWaylandShellSurface::QWaylandShellSurface(QWaylandShellSurfacePrivate &dd)
+ : QWaylandCompositorExtension(dd)
+{
+}
+
+QWaylandShellSurface::QWaylandShellSurface(QWaylandObject *container, QWaylandShellSurfacePrivate &dd)
+ : QWaylandCompositorExtension(container, dd)
+{
+}
+
+QWaylandShellSurface::QWaylandShellSurface(QWaylandObject *waylandObject)
+ : QWaylandCompositorExtension(waylandObject, *new QWaylandShellSurfacePrivate)
+{
+}
+
+bool QWaylandShellSurface::modal() const
+{
+ Q_D(const QWaylandShellSurface);
+ return d->modal;
+}
+
+void QWaylandShellSurface::setModal(bool newModal)
+{
+ Q_D(QWaylandShellSurface);
+ if (d->modal == newModal)
+ return;
+ d->modal = newModal;
+ emit modalChanged();
+}
+
QT_END_NAMESPACE
#include "moc_qwaylandshellsurface.cpp"
diff --git a/src/compositor/extensions/qwaylandshellsurface.h b/src/compositor/extensions/qwaylandshellsurface.h
index 527d198d8..67ee5b8f8 100644
--- a/src/compositor/extensions/qwaylandshellsurface.h
+++ b/src/compositor/extensions/qwaylandshellsurface.h
@@ -11,11 +11,15 @@ QT_BEGIN_NAMESPACE
class QWaylandQuickShellIntegration;
class QWaylandQuickShellSurfaceItem;
+class QWaylandShellSurfacePrivate;
class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandShellSurface : public QWaylandCompositorExtension
{
Q_OBJECT
+ Q_DECLARE_PRIVATE(QWaylandShellSurface)
+
Q_PROPERTY(Qt::WindowType windowType READ windowType NOTIFY windowTypeChanged)
+ Q_PROPERTY(bool modal READ modal NOTIFY modalChanged FINAL REVISION(6, 8))
QML_NAMED_ELEMENT(ShellSurface)
QML_UNCREATABLE("")
QML_ADDED_IN_VERSION(1, 0)
@@ -23,15 +27,19 @@ public:
#if QT_CONFIG(wayland_compositor_quick)
virtual QWaylandQuickShellIntegration *createIntegration(QWaylandQuickShellSurfaceItem *item) = 0;
#endif
- QWaylandShellSurface(QWaylandObject *waylandObject) : QWaylandCompositorExtension(waylandObject) {}
+ QWaylandShellSurface(QWaylandObject *waylandObject);
virtual Qt::WindowType windowType() const { return Qt::WindowType::Window; }
+ bool modal() const;
+
protected:
- QWaylandShellSurface(QWaylandCompositorExtensionPrivate &dd) : QWaylandCompositorExtension(dd){}
- QWaylandShellSurface(QWaylandObject *container, QWaylandCompositorExtensionPrivate &dd) : QWaylandCompositorExtension(container, dd) {}
+ QWaylandShellSurface(QWaylandShellSurfacePrivate &dd);
+ QWaylandShellSurface(QWaylandObject *container, QWaylandShellSurfacePrivate &dd);
+ void setModal(bool newModal);
Q_SIGNALS:
void windowTypeChanged();
+ void modalChanged();
};
template <typename T>
@@ -54,11 +62,11 @@ public:
}
protected:
- QWaylandShellSurfaceTemplate(QWaylandCompositorExtensionPrivate &dd)
+ QWaylandShellSurfaceTemplate(QWaylandShellSurfacePrivate &dd)
: QWaylandShellSurface(dd)
{ }
- QWaylandShellSurfaceTemplate(QWaylandObject *container, QWaylandCompositorExtensionPrivate &dd)
+ QWaylandShellSurfaceTemplate(QWaylandObject *container, QWaylandShellSurfacePrivate &dd)
: QWaylandShellSurface(container,dd)
{ }
};
diff --git a/src/compositor/extensions/qwaylandshellsurface_p.h b/src/compositor/extensions/qwaylandshellsurface_p.h
new file mode 100644
index 000000000..438571824
--- /dev/null
+++ b/src/compositor/extensions/qwaylandshellsurface_p.h
@@ -0,0 +1,32 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWAYLANDSHELLSURFACE_P_H
+#define QWAYLANDSHELLSURFACE_P_H
+
+#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h>
+#include "qwaylandshellsurface.h"
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandShellSurfacePrivate : public QWaylandCompositorExtensionPrivate
+{
+ Q_DECLARE_PUBLIC(QWaylandShellSurface)
+public:
+ bool modal = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDSHELLSURFACE_P_H
diff --git a/src/compositor/extensions/qwaylandtextinput.cpp b/src/compositor/extensions/qwaylandtextinput.cpp
index 766faf16a..933f31208 100644
--- a/src/compositor/extensions/qwaylandtextinput.cpp
+++ b/src/compositor/extensions/qwaylandtextinput.cpp
@@ -105,10 +105,10 @@ void QWaylandTextInputPrivate::sendInputMethodEvent(QInputMethodEvent *event)
if (event->replacementLength() > 0 || event->replacementStart() != 0) {
// Remove replacement
- afterCommit.cursorPosition = qBound(0, afterCommit.cursorPosition + event->replacementStart(), afterCommit.surroundingText.length());
+ afterCommit.cursorPosition = qBound(0, afterCommit.cursorPosition + event->replacementStart(), afterCommit.surroundingText.size());
afterCommit.surroundingText.remove(afterCommit.cursorPosition,
qMin(event->replacementLength(),
- afterCommit.surroundingText.length() - afterCommit.cursorPosition));
+ afterCommit.surroundingText.size() - afterCommit.cursorPosition));
if (event->replacementStart() <= 0 && (event->replacementLength() >= -event->replacementStart())) {
const int selectionStart = qMin(currentState->cursorPosition, currentState->anchorPosition);
@@ -124,7 +124,7 @@ void QWaylandTextInputPrivate::sendInputMethodEvent(QInputMethodEvent *event)
// Insert commit string
afterCommit.surroundingText.insert(afterCommit.cursorPosition, event->commitString());
- afterCommit.cursorPosition += event->commitString().length();
+ afterCommit.cursorPosition += event->commitString().size();
afterCommit.anchorPosition = afterCommit.cursorPosition;
for (const QInputMethodEvent::Attribute &attribute : event->attributes()) {
diff --git a/src/compositor/extensions/qwaylandtextinputmanagerv4.cpp b/src/compositor/extensions/qwaylandtextinputmanagerv3.cpp
index d77cae220..5dbc78459 100644
--- a/src/compositor/extensions/qwaylandtextinputmanagerv4.cpp
+++ b/src/compositor/extensions/qwaylandtextinputmanagerv3.cpp
@@ -1,35 +1,35 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qwaylandtextinputmanagerv4.h"
-#include "qwaylandtextinputmanagerv4_p.h"
+#include "qwaylandtextinputmanagerv3.h"
+#include "qwaylandtextinputmanagerv3_p.h"
#include <QtWaylandCompositor/QWaylandCompositor>
#include <QtWaylandCompositor/QWaylandSeat>
-#include "qwaylandtextinputv4.h"
+#include "qwaylandtextinputv3.h"
QT_BEGIN_NAMESPACE
-QWaylandTextInputManagerV4Private::QWaylandTextInputManagerV4Private()
+QWaylandTextInputManagerV3Private::QWaylandTextInputManagerV3Private()
{
}
-void QWaylandTextInputManagerV4Private::zwp_text_input_manager_v4_get_text_input(Resource *resource, uint32_t id, struct ::wl_resource *seatResource)
+void QWaylandTextInputManagerV3Private::zwp_text_input_manager_v3_get_text_input(Resource *resource, uint32_t id, struct ::wl_resource *seatResource)
{
qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
- Q_Q(QWaylandTextInputManagerV4);
+ Q_Q(QWaylandTextInputManagerV3);
QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(q->extensionContainer());
QWaylandSeat *seat = QWaylandSeat::fromSeatResource(seatResource);
- QWaylandTextInputV4 *textInput = QWaylandTextInputV4::findIn(seat);
+ QWaylandTextInputV3 *textInput = QWaylandTextInputV3::findIn(seat);
if (!textInput) {
- textInput = new QWaylandTextInputV4(seat, compositor);
+ textInput = new QWaylandTextInputV3(seat, compositor);
}
textInput->add(resource->client(), id, wl_resource_get_version(resource->handle));
QWaylandClient *client = QWaylandClient::fromWlClient(compositor, resource->client());
QWaylandClient::TextInputProtocols p = client->textInputProtocols();
- client->setTextInputProtocols(p.setFlag(QWaylandClient::TextInputProtocol::TextInputV4));
+ client->setTextInputProtocols(p.setFlag(QWaylandClient::TextInputProtocol::TextInputV3));
if (!textInput->isInitialized())
textInput->initialize();
}
@@ -38,13 +38,13 @@ void QWaylandTextInputManagerV4Private::zwp_text_input_manager_v4_get_text_input
\internal
\preliminary
- \qmltype TextInputManagerV4
- \instantiates QWaylandTextInputManagerV4
+ \qmltype TextInputManagerV3
+ \instantiates QWaylandTextInputManagerV3
\inqmlmodule QtWayland.Compositor
\brief Provides access to input methods in the compositor.
- The \c TextInputManagerV4 corresponds to the \c zwp_text_input_manager_v4 interface
- in the \c text_input_unstable_v4 extension protocol.
+ The \c TextInputManagerV3 corresponds to the \c zwp_text_input_manager_v3 interface
+ in the \c text_input_unstable_v3 extension protocol.
Instantiating this as child of a \l WaylandCompositor adds it to the list of interfaces available
to the client. If a client binds to it, then it will be used to communciate text input to
@@ -56,12 +56,12 @@ void QWaylandTextInputManagerV4Private::zwp_text_input_manager_v4_get_text_input
/*!
\internal
\preliminary
- \class QWaylandTextInputManagerV4
+ \class QWaylandTextInputManagerV3
\inmodule QtWaylandCompositor
\brief Provides access to input methods in the compositor.
- The \c QWaylandTextInputManagerV4 corresponds to the \c zwp_text_input_manager_v4 interface
- in the \c text_input_unstable_v4 extension protocol.
+ The \c QWaylandTextInputManagerV3 corresponds to the \c zwp_text_input_manager_v3 interface
+ in the \c text_input_unstable_v3 extension protocol.
Instantiating this as child of a \l WaylandCompositor adds it to the list of interfaces available
to the client. If a client binds to it, then it will be used to communciate text input to
@@ -69,43 +69,43 @@ void QWaylandTextInputManagerV4Private::zwp_text_input_manager_v4_get_text_input
\note This protocol is currently a work-in-progress and only exists in Qt for validation purposes. It may change at any time.
*/
-QWaylandTextInputManagerV4::QWaylandTextInputManagerV4()
- : QWaylandCompositorExtensionTemplate<QWaylandTextInputManagerV4>(*new QWaylandTextInputManagerV4Private)
+QWaylandTextInputManagerV3::QWaylandTextInputManagerV3()
+ : QWaylandCompositorExtensionTemplate<QWaylandTextInputManagerV3>(*new QWaylandTextInputManagerV3Private)
{
}
-QWaylandTextInputManagerV4::QWaylandTextInputManagerV4(QWaylandCompositor *compositor)
- : QWaylandCompositorExtensionTemplate<QWaylandTextInputManagerV4>(compositor, *new QWaylandTextInputManagerV4Private)
+QWaylandTextInputManagerV3::QWaylandTextInputManagerV3(QWaylandCompositor *compositor)
+ : QWaylandCompositorExtensionTemplate<QWaylandTextInputManagerV3>(compositor, *new QWaylandTextInputManagerV3Private)
{
}
-QWaylandTextInputManagerV4::~QWaylandTextInputManagerV4()
+QWaylandTextInputManagerV3::~QWaylandTextInputManagerV3()
{
}
-void QWaylandTextInputManagerV4::initialize()
+void QWaylandTextInputManagerV3::initialize()
{
qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
- Q_D(QWaylandTextInputManagerV4);
+ Q_D(QWaylandTextInputManagerV3);
QWaylandCompositorExtensionTemplate::initialize();
QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
if (!compositor) {
- qWarning() << "Failed to find QWaylandCompositor when initializing QWaylandTextInputManagerV4";
+ qWarning() << "Failed to find QWaylandCompositor when initializing QWaylandTextInputManagerV3";
return;
}
d->init(compositor->display(), 1);
}
-const wl_interface *QWaylandTextInputManagerV4::interface()
+const wl_interface *QWaylandTextInputManagerV3::interface()
{
- return QWaylandTextInputManagerV4Private::interface();
+ return QWaylandTextInputManagerV3Private::interface();
}
-QByteArray QWaylandTextInputManagerV4::interfaceName()
+QByteArray QWaylandTextInputManagerV3::interfaceName()
{
- return QWaylandTextInputManagerV4Private::interfaceName();
+ return QWaylandTextInputManagerV3Private::interfaceName();
}
QT_END_NAMESPACE
diff --git a/src/compositor/extensions/qwaylandtextinputmanagerv4.h b/src/compositor/extensions/qwaylandtextinputmanagerv3.h
index 6ad0b0900..1f3051446 100644
--- a/src/compositor/extensions/qwaylandtextinputmanagerv4.h
+++ b/src/compositor/extensions/qwaylandtextinputmanagerv3.h
@@ -1,8 +1,8 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QWAYLANDTEXTINPUTMANAGERV4_H
-#define QWAYLANDTEXTINPUTMANAGERV4_H
+#ifndef QWAYLANDTEXTINPUTMANAGERV3_H
+#define QWAYLANDTEXTINPUTMANAGERV3_H
#include <QtWaylandCompositor/QWaylandCompositorExtension>
@@ -10,16 +10,16 @@
QT_BEGIN_NAMESPACE
-class QWaylandTextInputManagerV4Private;
+class QWaylandTextInputManagerV3Private;
-class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandTextInputManagerV4 : public QWaylandCompositorExtensionTemplate<QWaylandTextInputManagerV4>
+class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandTextInputManagerV3 : public QWaylandCompositorExtensionTemplate<QWaylandTextInputManagerV3>
{
Q_OBJECT
- Q_DECLARE_PRIVATE(QWaylandTextInputManagerV4)
+ Q_DECLARE_PRIVATE(QWaylandTextInputManagerV3)
public:
- QWaylandTextInputManagerV4();
- explicit QWaylandTextInputManagerV4(QWaylandCompositor *compositor);
- ~QWaylandTextInputManagerV4() override;
+ QWaylandTextInputManagerV3();
+ explicit QWaylandTextInputManagerV3(QWaylandCompositor *compositor);
+ ~QWaylandTextInputManagerV3() override;
void initialize() override;
@@ -29,4 +29,4 @@ public:
QT_END_NAMESPACE
-#endif // QWAYLANDTEXTINPUTMANAGERV4_H
+#endif // QWAYLANDTEXTINPUTMANAGERV3_H
diff --git a/src/compositor/extensions/qwaylandtextinputmanagerv4_p.h b/src/compositor/extensions/qwaylandtextinputmanagerv3_p.h
index 00aa150c7..c35b19b90 100644
--- a/src/compositor/extensions/qwaylandtextinputmanagerv4_p.h
+++ b/src/compositor/extensions/qwaylandtextinputmanagerv3_p.h
@@ -1,12 +1,12 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QWAYLANDTEXTINPUTMANAGERV4_P_H
-#define QWAYLANDTEXTINPUTMANAGERV4_P_H
+#ifndef QWAYLANDTEXTINPUTMANAGERV3_P_H
+#define QWAYLANDTEXTINPUTMANAGERV3_P_H
#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h>
-#include <QtWaylandCompositor/private/qwayland-server-text-input-unstable-v4-wip.h>
+#include <QtWaylandCompositor/private/qwayland-server-text-input-unstable-v3.h>
//
// W A R N I N G
@@ -21,16 +21,16 @@
QT_BEGIN_NAMESPACE
-class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandTextInputManagerV4Private : public QWaylandCompositorExtensionPrivate, public QtWaylandServer::zwp_text_input_manager_v4
+class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandTextInputManagerV3Private : public QWaylandCompositorExtensionPrivate, public QtWaylandServer::zwp_text_input_manager_v3
{
- Q_DECLARE_PUBLIC(QWaylandTextInputManagerV4)
+ Q_DECLARE_PUBLIC(QWaylandTextInputManagerV3)
public:
- QWaylandTextInputManagerV4Private();
+ QWaylandTextInputManagerV3Private();
protected:
- void zwp_text_input_manager_v4_get_text_input(Resource *resource, uint32_t id, struct ::wl_resource *seatResource) override;
+ void zwp_text_input_manager_v3_get_text_input(Resource *resource, uint32_t id, struct ::wl_resource *seatResource) override;
};
QT_END_NAMESPACE
-#endif // QWAYLANDTEXTINPUTMANAGERV4_P_H
+#endif // QWAYLANDTEXTINPUTMANAGERV3_P_H
diff --git a/src/compositor/extensions/qwaylandtextinputv4.cpp b/src/compositor/extensions/qwaylandtextinputv3.cpp
index d7e19360b..3da89e630 100644
--- a/src/compositor/extensions/qwaylandtextinputv4.cpp
+++ b/src/compositor/extensions/qwaylandtextinputv3.cpp
@@ -1,8 +1,8 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qwaylandtextinputv4.h"
-#include "qwaylandtextinputv4_p.h"
+#include "qwaylandtextinputv3.h"
+#include "qwaylandtextinputv3_p.h"
#include <QtWaylandCompositor/QWaylandCompositor>
#include <QtWaylandCompositor/private/qwaylandseat_p.h>
@@ -23,11 +23,11 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(qLcWaylandCompositorTextInput)
-QWaylandTextInputV4ClientState::QWaylandTextInputV4ClientState()
+QWaylandTextInputV3ClientState::QWaylandTextInputV3ClientState()
{
}
-Qt::InputMethodQueries QWaylandTextInputV4ClientState::updatedQueries(const QWaylandTextInputV4ClientState &other) const
+Qt::InputMethodQueries QWaylandTextInputV3ClientState::updatedQueries(const QWaylandTextInputV3ClientState &other) const
{
qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
@@ -47,7 +47,7 @@ Qt::InputMethodQueries QWaylandTextInputV4ClientState::updatedQueries(const QWay
return queries;
}
-Qt::InputMethodQueries QWaylandTextInputV4ClientState::mergeChanged(const QWaylandTextInputV4ClientState &other) {
+Qt::InputMethodQueries QWaylandTextInputV3ClientState::mergeChanged(const QWaylandTextInputV3ClientState &other) {
Qt::InputMethodQueries queries;
@@ -79,16 +79,15 @@ Qt::InputMethodQueries QWaylandTextInputV4ClientState::mergeChanged(const QWayla
return queries;
}
-QWaylandTextInputV4Private::QWaylandTextInputV4Private(QWaylandCompositor *compositor)
+QWaylandTextInputV3Private::QWaylandTextInputV3Private(QWaylandCompositor *compositor)
: compositor(compositor)
- , currentState(new QWaylandTextInputV4ClientState)
- , pendingState(new QWaylandTextInputV4ClientState)
+ , currentState(new QWaylandTextInputV3ClientState)
+ , pendingState(new QWaylandTextInputV3ClientState)
{
}
-void QWaylandTextInputV4Private::sendInputMethodEvent(QInputMethodEvent *event)
+void QWaylandTextInputV3Private::sendInputMethodEvent(QInputMethodEvent *event)
{
- Q_Q(QWaylandTextInputV4);
qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
if (!focusResource || !focusResource->handle)
@@ -127,25 +126,23 @@ void QWaylandTextInputV4Private::sendInputMethodEvent(QInputMethodEvent *event)
}
if (needsDone)
- send_done(focusResource->handle, serial);
+ send_done(focusResource->handle, serials[focusResource]);
}
-void QWaylandTextInputV4Private::sendKeyEvent(QKeyEvent *event)
+void QWaylandTextInputV3Private::sendKeyEvent(QKeyEvent *event)
{
qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
- Q_Q(QWaylandTextInputV4);
-
if (!focusResource || !focusResource->handle)
return;
send_commit_string(focusResource->handle, event->text());
- send_done(focusResource->handle, serial);
+ send_done(focusResource->handle, serials[focusResource]);
}
-QVariant QWaylandTextInputV4Private::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const
+QVariant QWaylandTextInputV3Private::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const
{
qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO << property;
@@ -189,10 +186,9 @@ QVariant QWaylandTextInputV4Private::inputMethodQuery(Qt::InputMethodQuery prope
}
}
-void QWaylandTextInputV4Private::setFocus(QWaylandSurface *surface)
+void QWaylandTextInputV3Private::setFocus(QWaylandSurface *surface)
{
- qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
- Q_Q(QWaylandTextInputV4);
+ qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO << surface;
if (focusResource && focus) {
// sync before leave
@@ -225,49 +221,49 @@ void QWaylandTextInputV4Private::setFocus(QWaylandSurface *surface)
focusResource = resource;
}
-void QWaylandTextInputV4Private::zwp_text_input_v4_bind_resource(Resource *resource)
+void QWaylandTextInputV3Private::zwp_text_input_v3_bind_resource(Resource *resource)
{
qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
- Q_UNUSED(resource);
+ serials.insert(resource, 0);
}
-void QWaylandTextInputV4Private::zwp_text_input_v4_destroy_resource(Resource *resource)
+void QWaylandTextInputV3Private::zwp_text_input_v3_destroy_resource(Resource *resource)
{
qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
+ serials.remove(resource);
if (focusResource == resource)
focusResource = nullptr;
}
-void QWaylandTextInputV4Private::zwp_text_input_v4_destroy(Resource *resource)
+void QWaylandTextInputV3Private::zwp_text_input_v3_destroy(Resource *resource)
{
qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
wl_resource_destroy(resource->handle);
}
-void QWaylandTextInputV4Private::zwp_text_input_v4_enable(Resource *resource)
+void QWaylandTextInputV3Private::zwp_text_input_v3_enable(Resource *resource)
{
qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
- Q_Q(QWaylandTextInputV4);
+ Q_Q(QWaylandTextInputV3);
- pendingState.reset(new QWaylandTextInputV4ClientState);
+ pendingState.reset(new QWaylandTextInputV3ClientState);
enabledSurfaces.insert(resource, focus);
emit q->surfaceEnabled(focus);
- serial = 0;
inputPanelVisible = true;
qApp->inputMethod()->show();
}
-void QWaylandTextInputV4Private::zwp_text_input_v4_disable(QtWaylandServer::zwp_text_input_v4::Resource *resource)
+void QWaylandTextInputV3Private::zwp_text_input_v3_disable(QtWaylandServer::zwp_text_input_v3::Resource *resource)
{
qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
- Q_Q(QWaylandTextInputV4);
+ Q_Q(QWaylandTextInputV3);
QWaylandSurface *s = enabledSurfaces.take(resource);
emit q->surfaceDisabled(s);
@@ -278,15 +274,13 @@ void QWaylandTextInputV4Private::zwp_text_input_v4_disable(QtWaylandServer::zwp_
qApp->inputMethod()->commit();
}
qApp->inputMethod()->reset();
- pendingState.reset(new QWaylandTextInputV4ClientState);
+ pendingState.reset(new QWaylandTextInputV3ClientState);
}
-void QWaylandTextInputV4Private::zwp_text_input_v4_set_cursor_rectangle(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
+void QWaylandTextInputV3Private::zwp_text_input_v3_set_cursor_rectangle(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
{
qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO << x << y << width << height;
- Q_Q(QWaylandTextInputV4);
-
if (resource != focusResource)
return;
@@ -295,18 +289,11 @@ void QWaylandTextInputV4Private::zwp_text_input_v4_set_cursor_rectangle(Resource
pendingState->changedState |= Qt::ImCursorRectangle;
}
-void QWaylandTextInputV4Private::zwp_text_input_v4_commit(Resource *resource)
+void QWaylandTextInputV3Private::zwp_text_input_v3_commit(Resource *resource)
{
qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
- Q_Q(QWaylandTextInputV4);
-
- if (resource != focusResource) {
- qCDebug(qLcWaylandCompositorTextInput) << "OBS: Disabled surface!!";
- return;
- }
-
- serial = serial < UINT_MAX ? serial + 1U : 0U;
+ serials[resource] = serials[resource] < UINT_MAX ? serials[resource] + 1U : 0U;
// Just increase serials and ignore empty commits
if (!pendingState->changedState) {
@@ -327,7 +314,7 @@ void QWaylandTextInputV4Private::zwp_text_input_v4_commit(Resource *resource)
qApp->inputMethod()->invokeAction(QInputMethod::Click, pendingState->cursorPosition);
Qt::InputMethodQueries queries = currentState->mergeChanged(*pendingState.data());
- pendingState.reset(new QWaylandTextInputV4ClientState);
+ pendingState.reset(new QWaylandTextInputV3ClientState);
if (queries) {
qCDebug(qLcWaylandCompositorTextInput) << "QInputMethod::update() after commit with" << queries;
@@ -336,7 +323,7 @@ void QWaylandTextInputV4Private::zwp_text_input_v4_commit(Resource *resource)
}
}
-void QWaylandTextInputV4Private::zwp_text_input_v4_set_content_type(Resource *resource, uint32_t hint, uint32_t purpose)
+void QWaylandTextInputV3Private::zwp_text_input_v3_set_content_type(Resource *resource, uint32_t hint, uint32_t purpose)
{
qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO << hint << purpose;
@@ -405,7 +392,7 @@ void QWaylandTextInputV4Private::zwp_text_input_v4_set_content_type(Resource *re
pendingState->changedState |= Qt::ImHints;
}
-void QWaylandTextInputV4Private::zwp_text_input_v4_set_surrounding_text(Resource *resource, const QString &text, int32_t cursor, int32_t anchor)
+void QWaylandTextInputV3Private::zwp_text_input_v3_set_surrounding_text(Resource *resource, const QString &text, int32_t cursor, int32_t anchor)
{
qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO << text << cursor << anchor;
@@ -419,7 +406,7 @@ void QWaylandTextInputV4Private::zwp_text_input_v4_set_surrounding_text(Resource
pendingState->changedState |= Qt::ImSurroundingText | Qt::ImCursorPosition | Qt::ImAnchorPosition;
}
-void QWaylandTextInputV4Private::zwp_text_input_v4_set_text_change_cause(Resource *resource, uint32_t cause)
+void QWaylandTextInputV3Private::zwp_text_input_v3_set_text_change_cause(Resource *resource, uint32_t cause)
{
qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
@@ -427,57 +414,57 @@ void QWaylandTextInputV4Private::zwp_text_input_v4_set_text_change_cause(Resourc
Q_UNUSED(cause);
}
-QWaylandTextInputV4::QWaylandTextInputV4(QWaylandObject *container, QWaylandCompositor *compositor)
- : QWaylandCompositorExtensionTemplate(container, *new QWaylandTextInputV4Private(compositor))
+QWaylandTextInputV3::QWaylandTextInputV3(QWaylandObject *container, QWaylandCompositor *compositor)
+ : QWaylandCompositorExtensionTemplate(container, *new QWaylandTextInputV3Private(compositor))
{
connect(&d_func()->focusDestroyListener, &QWaylandDestroyListener::fired,
- this, &QWaylandTextInputV4::focusSurfaceDestroyed);
+ this, &QWaylandTextInputV3::focusSurfaceDestroyed);
}
-QWaylandTextInputV4::~QWaylandTextInputV4()
+QWaylandTextInputV3::~QWaylandTextInputV3()
{
}
-void QWaylandTextInputV4::sendInputMethodEvent(QInputMethodEvent *event)
+void QWaylandTextInputV3::sendInputMethodEvent(QInputMethodEvent *event)
{
- Q_D(QWaylandTextInputV4);
+ Q_D(QWaylandTextInputV3);
d->sendInputMethodEvent(event);
}
-void QWaylandTextInputV4::sendKeyEvent(QKeyEvent *event)
+void QWaylandTextInputV3::sendKeyEvent(QKeyEvent *event)
{
- Q_D(QWaylandTextInputV4);
+ Q_D(QWaylandTextInputV3);
d->sendKeyEvent(event);
}
-QVariant QWaylandTextInputV4::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const
+QVariant QWaylandTextInputV3::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const
{
- const Q_D(QWaylandTextInputV4);
+ const Q_D(QWaylandTextInputV3);
return d->inputMethodQuery(property, argument);
}
-QWaylandSurface *QWaylandTextInputV4::focus() const
+QWaylandSurface *QWaylandTextInputV3::focus() const
{
- const Q_D(QWaylandTextInputV4);
+ const Q_D(QWaylandTextInputV3);
return d->focus;
}
-void QWaylandTextInputV4::setFocus(QWaylandSurface *surface)
+void QWaylandTextInputV3::setFocus(QWaylandSurface *surface)
{
- Q_D(QWaylandTextInputV4);
+ Q_D(QWaylandTextInputV3);
d->setFocus(surface);
}
-void QWaylandTextInputV4::focusSurfaceDestroyed(void *)
+void QWaylandTextInputV3::focusSurfaceDestroyed(void *)
{
qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
- Q_D(QWaylandTextInputV4);
+ Q_D(QWaylandTextInputV3);
d->focusDestroyListener.reset();
@@ -485,32 +472,32 @@ void QWaylandTextInputV4::focusSurfaceDestroyed(void *)
d->focusResource = nullptr;
}
-bool QWaylandTextInputV4::isSurfaceEnabled(QWaylandSurface *surface) const
+bool QWaylandTextInputV3::isSurfaceEnabled(QWaylandSurface *surface) const
{
qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
- const Q_D(QWaylandTextInputV4);
+ const Q_D(QWaylandTextInputV3);
return d->enabledSurfaces.values().contains(surface);
}
-void QWaylandTextInputV4::add(::wl_client *client, uint32_t id, int version)
+void QWaylandTextInputV3::add(::wl_client *client, uint32_t id, int version)
{
- qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
+ qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO << client << id << version;
- Q_D(QWaylandTextInputV4);
+ Q_D(QWaylandTextInputV3);
d->add(client, id, version);
}
-const wl_interface *QWaylandTextInputV4::interface()
+const wl_interface *QWaylandTextInputV3::interface()
{
- return QWaylandTextInputV4Private::interface();
+ return QWaylandTextInputV3Private::interface();
}
-QByteArray QWaylandTextInputV4::interfaceName()
+QByteArray QWaylandTextInputV3::interfaceName()
{
- return QWaylandTextInputV4Private::interfaceName();
+ return QWaylandTextInputV3Private::interfaceName();
}
QT_END_NAMESPACE
diff --git a/src/compositor/extensions/qwaylandtextinputv4.h b/src/compositor/extensions/qwaylandtextinputv3.h
index 4b4d8fa4d..1305bddfb 100644
--- a/src/compositor/extensions/qwaylandtextinputv4.h
+++ b/src/compositor/extensions/qwaylandtextinputv3.h
@@ -1,8 +1,8 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QWAYLANDTEXTINPUTV4_H
-#define QWAYLANDTEXTINPUTV4_H
+#ifndef QWAYLANDTEXTINPUTV3_H
+#define QWAYLANDTEXTINPUTV3_H
#include <QtWaylandCompositor/QWaylandCompositorExtension>
@@ -10,19 +10,19 @@ struct wl_client;
QT_BEGIN_NAMESPACE
-class QWaylandTextInputV4Private;
+class QWaylandTextInputV3Private;
class QInputMethodEvent;
class QKeyEvent;
class QWaylandSurface;
-class QWaylandTextInputV4 : public QWaylandCompositorExtensionTemplate<QWaylandTextInputV4>
+class QWaylandTextInputV3 : public QWaylandCompositorExtensionTemplate<QWaylandTextInputV3>
{
Q_OBJECT
- Q_DECLARE_PRIVATE(QWaylandTextInputV4)
+ Q_DECLARE_PRIVATE(QWaylandTextInputV3)
public:
- explicit QWaylandTextInputV4(QWaylandObject *container, QWaylandCompositor *compositor);
- ~QWaylandTextInputV4() override;
+ explicit QWaylandTextInputV3(QWaylandObject *container, QWaylandCompositor *compositor);
+ ~QWaylandTextInputV3() override;
void sendInputMethodEvent(QInputMethodEvent *event);
void sendKeyEvent(QKeyEvent *event);
@@ -49,4 +49,4 @@ private:
QT_END_NAMESPACE
-#endif // QWAYLANDTEXTINPUTV4_H
+#endif // QWAYLANDTEXTINPUTV3_H
diff --git a/src/compositor/extensions/qwaylandtextinputv4_p.h b/src/compositor/extensions/qwaylandtextinputv3_p.h
index 0e29e62c1..ed43b88c6 100644
--- a/src/compositor/extensions/qwaylandtextinputv4_p.h
+++ b/src/compositor/extensions/qwaylandtextinputv3_p.h
@@ -1,11 +1,11 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QWAYLANDTEXTINPUTV4_P_H
-#define QWAYLANDTEXTINPUTV4_P_H
+#ifndef QWAYLANDTEXTINPUTV3_P_H
+#define QWAYLANDTEXTINPUTV3_P_H
#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h>
-#include <QtWaylandCompositor/private/qwayland-server-text-input-unstable-v4-wip.h>
+#include <QtWaylandCompositor/private/qwayland-server-text-input-unstable-v3.h>
#include <QtWaylandCompositor/QWaylandDestroyListener>
#include <QtCore/QObject>
@@ -31,12 +31,12 @@ class QKeyEvent;
class QWaylandCompositor;
class QWaylandView;
-class QWaylandTextInputV4ClientState {
+class QWaylandTextInputV3ClientState {
public:
- QWaylandTextInputV4ClientState();
+ QWaylandTextInputV3ClientState();
- Qt::InputMethodQueries updatedQueries(const QWaylandTextInputV4ClientState &other) const;
- Qt::InputMethodQueries mergeChanged(const QWaylandTextInputV4ClientState &other);
+ Qt::InputMethodQueries updatedQueries(const QWaylandTextInputV3ClientState &other) const;
+ Qt::InputMethodQueries mergeChanged(const QWaylandTextInputV3ClientState &other);
Qt::InputMethodHints hints = Qt::ImhNone;
QRect cursorRectangle;
@@ -47,11 +47,11 @@ public:
Qt::InputMethodQueries changedState;
};
-class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandTextInputV4Private : public QWaylandCompositorExtensionPrivate, public QtWaylandServer::zwp_text_input_v4
+class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandTextInputV3Private : public QWaylandCompositorExtensionPrivate, public QtWaylandServer::zwp_text_input_v3
{
- Q_DECLARE_PUBLIC(QWaylandTextInputV4)
+ Q_DECLARE_PUBLIC(QWaylandTextInputV3)
public:
- explicit QWaylandTextInputV4Private(QWaylandCompositor *compositor);
+ explicit QWaylandTextInputV3Private(QWaylandCompositor *compositor);
void sendInputMethodEvent(QInputMethodEvent *event);
void sendKeyEvent(QKeyEvent *event);
@@ -70,27 +70,26 @@ public:
QString currentPreeditString;
- QScopedPointer<QWaylandTextInputV4ClientState> currentState;
- QScopedPointer<QWaylandTextInputV4ClientState> pendingState;
+ QScopedPointer<QWaylandTextInputV3ClientState> currentState;
+ QScopedPointer<QWaylandTextInputV3ClientState> pendingState;
- uint32_t serial = 0;
-
- QHash<Resource *, QWaylandSurface*> enabledSurfaces;
+ QHash<Resource *, uint32_t> serials;
+ QHash<Resource *, QWaylandSurface *> enabledSurfaces;
protected:
- void zwp_text_input_v4_bind_resource(Resource *resource) override;
- void zwp_text_input_v4_destroy_resource(Resource *resource) override;
-
- void zwp_text_input_v4_destroy(Resource *resource) override;
- void zwp_text_input_v4_enable(Resource *resource) override;
- void zwp_text_input_v4_disable(Resource *resource) override;
- void zwp_text_input_v4_set_surrounding_text(Resource *resource, const QString &text, int32_t cursor, int32_t anchor) override;
- void zwp_text_input_v4_set_text_change_cause(Resource *resource, uint32_t cause) override;
- void zwp_text_input_v4_set_content_type(Resource *resource, uint32_t hint, uint32_t purpose) override;
- void zwp_text_input_v4_set_cursor_rectangle(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) override;
- void zwp_text_input_v4_commit(Resource *resource) override;
+ void zwp_text_input_v3_bind_resource(Resource *resource) override;
+ void zwp_text_input_v3_destroy_resource(Resource *resource) override;
+
+ void zwp_text_input_v3_destroy(Resource *resource) override;
+ void zwp_text_input_v3_enable(Resource *resource) override;
+ void zwp_text_input_v3_disable(Resource *resource) override;
+ void zwp_text_input_v3_set_surrounding_text(Resource *resource, const QString &text, int32_t cursor, int32_t anchor) override;
+ void zwp_text_input_v3_set_text_change_cause(Resource *resource, uint32_t cause) override;
+ void zwp_text_input_v3_set_content_type(Resource *resource, uint32_t hint, uint32_t purpose) override;
+ void zwp_text_input_v3_set_cursor_rectangle(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) override;
+ void zwp_text_input_v3_commit(Resource *resource) override;
};
QT_END_NAMESPACE
-#endif // QWAYLANDTEXTINPUTV4_P_H
+#endif // QWAYLANDTEXTINPUTV3_P_H
diff --git a/src/compositor/extensions/qwaylandviewporter_p.h b/src/compositor/extensions/qwaylandviewporter_p.h
index 67f2be2ec..84e0c90fc 100644
--- a/src/compositor/extensions/qwaylandviewporter_p.h
+++ b/src/compositor/extensions/qwaylandviewporter_p.h
@@ -9,6 +9,8 @@
#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h>
#include <QtWaylandCompositor/private/qwayland-server-viewporter.h>
+#include <QtCore/qpointer.h>
+
//
// W A R N I N G
// -------------
diff --git a/src/compositor/extensions/qwaylandwlshell.cpp b/src/compositor/extensions/qwaylandwlshell.cpp
index 4fb55e942..c0e6119e1 100644
--- a/src/compositor/extensions/qwaylandwlshell.cpp
+++ b/src/compositor/extensions/qwaylandwlshell.cpp
@@ -345,7 +345,7 @@ const struct wl_interface *QWaylandWlShell::interface()
}
/*!
- * \qmlsignal void QtWaylandCompositor::WlShell::wlShellSurfaceRequested(WaylandSurface surface, WaylandResource resource)
+ * \qmlsignal void WlShell::wlShellSurfaceRequested(WaylandSurface surface, WaylandResource resource)
*
* This signal is emitted when the client has requested a \c wl_shell_surface to be associated with
* \a surface. The handler for this signal may create a shell surface for \a resource and initialize
@@ -363,7 +363,7 @@ const struct wl_interface *QWaylandWlShell::interface()
*/
/*!
- * \qmlsignal void QtWaylandCompositor::WlShell::wlShellSurfaceCreated(WlShellSurface shellSurface)
+ * \qmlsignal void WlShell::wlShellSurfaceCreated(WlShellSurface shellSurface)
*
* This signal is emitted when the client has created a \c wl_shell_surface.
* A common use case is to let the handler of this signal instantiate a ShellSurfaceItem or
@@ -438,7 +438,7 @@ QWaylandWlShellSurface::~QWaylandWlShellSurface()
}
/*!
- * \qmlmethod void QtWaylandCompositor::WlShellSurface::initialize(WlShell shell, WaylandSurface surface, WaylandResource resource)
+ * \qmlmethod void WlShellSurface::initialize(WlShell shell, WaylandSurface surface, WaylandResource resource)
*
* Initializes the WlShellSurface and associates it with the given \a shell, \a surface, and \a resource.
*/
@@ -538,7 +538,7 @@ void QWaylandWlShellSurface::sendConfigure(const QSize &size, ResizeEdge edges)
}
/*!
- * \qmlmethod void QtWaylandCompositor::WlShellSurface::sendPopupDone()
+ * \qmlmethod void WlShellSurface::sendPopupDone()
*
* Sends a popup_done event to the client to indicate that the user has clicked
* somewhere outside the client's surfaces.
@@ -562,7 +562,7 @@ QWaylandQuickShellIntegration *QWaylandWlShellSurface::createIntegration(QWaylan
#endif
/*!
- * \qmlproperty WaylandSurface QtWaylandCompositor::WlShellSurface::surface
+ * \qmlproperty WaylandSurface WlShellSurface::surface
*
* This property holds the \c wl_surface associated with this WlShellSurface.
*/
@@ -579,7 +579,7 @@ QWaylandSurface *QWaylandWlShellSurface::surface() const
}
/*!
- * \qmlproperty WlShell QtWaylandCompositor::WlShellSurface::shell
+ * \qmlproperty WlShell WlShellSurface::shell
*
* This property holds the shell associated with this WlShellSurface.
*/
@@ -596,7 +596,7 @@ QWaylandWlShell *QWaylandWlShellSurface::shell() const
}
/*!
- * \qmlproperty enum QtWaylandCompositor::WlShellSurface::windowType
+ * \qmlproperty enum WlShellSurface::windowType
*
* This property holds the window type of the WlShellSurface.
*/
@@ -608,7 +608,7 @@ Qt::WindowType QWaylandWlShellSurface::windowType() const
}
/*!
- * \qmlproperty string QtWaylandCompositor::WlShellSurface::title
+ * \qmlproperty string WlShellSurface::title
*
* This property holds the title of the WlShellSurface.
*/
@@ -625,7 +625,7 @@ QString QWaylandWlShellSurface::title() const
}
/*!
- * \qmlproperty string QtWaylandCompositor::WlShellSurface::className
+ * \qmlproperty string WlShellSurface::className
*
* This property holds the class name of the WlShellSurface.
*/
@@ -647,7 +647,7 @@ QWaylandSurfaceRole *QWaylandWlShellSurface::role()
}
/*!
- * \qmlmethod void QtWaylandCompositor::WlShellSurface::ping()
+ * \qmlmethod void WlShellSurface::ping()
*
* Sends a ping event to the client. If the client replies to the event the pong
* signal will be emitted.
diff --git a/src/compositor/extensions/qwaylandwlshell.h b/src/compositor/extensions/qwaylandwlshell.h
index 41631ebb6..250c78447 100644
--- a/src/compositor/extensions/qwaylandwlshell.h
+++ b/src/compositor/extensions/qwaylandwlshell.h
@@ -8,7 +8,9 @@
#include <QtWaylandCompositor/QWaylandResource>
#include <QtWaylandCompositor/QWaylandShell>
#include <QtWaylandCompositor/QWaylandShellSurface>
+#if QT_CONFIG(wayland_compositor_quick)
#include <QtWaylandCompositor/qwaylandquickchildren.h>
+#endif
#include <QtCore/QSize>
@@ -52,7 +54,9 @@ class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandWlShellSurface : public QWaylandShellSu
{
Q_OBJECT
Q_DECLARE_PRIVATE(QWaylandWlShellSurface)
+#if QT_CONFIG(wayland_compositor_quick)
Q_WAYLAND_COMPOSITOR_DECLARE_QUICK_CHILDREN(QWaylandWlShellSurface)
+#endif
Q_PROPERTY(QWaylandSurface *surface READ surface NOTIFY surfaceChanged)
Q_PROPERTY(QWaylandWlShell *shell READ shell NOTIFY shellChanged)
Q_PROPERTY(QString title READ title NOTIFY titleChanged)
diff --git a/src/compositor/extensions/qwaylandwlshell_p.h b/src/compositor/extensions/qwaylandwlshell_p.h
index 151eed4f6..4202a8aed 100644
--- a/src/compositor/extensions/qwaylandwlshell_p.h
+++ b/src/compositor/extensions/qwaylandwlshell_p.h
@@ -6,7 +6,7 @@
#include <QtWaylandCompositor/qtwaylandcompositorglobal.h>
#include <QtWaylandCompositor/qwaylandsurface.h>
-#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h>
+#include <QtWaylandCompositor/private/qwaylandshellsurface_p.h>
#include <QtWaylandCompositor/private/qwaylandshell_p.h>
#include <QtWaylandCompositor/QWaylandWlShellSurface>
#include <QtWaylandCompositor/QWaylandSeat>
@@ -18,6 +18,8 @@
#include <QtWaylandCompositor/private/qwayland-server-wayland.h>
+#include <QtCore/qpointer.h>
+
//
// W A R N I N G
// -------------
@@ -50,7 +52,7 @@ protected:
};
class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandWlShellSurfacePrivate
- : public QWaylandCompositorExtensionPrivate
+ : public QWaylandShellSurfacePrivate
, public QtWaylandServer::wl_shell_surface
{
Q_DECLARE_PUBLIC(QWaylandWlShellSurface)
diff --git a/src/compositor/extensions/qwaylandwlshellintegration_p.h b/src/compositor/extensions/qwaylandwlshellintegration_p.h
index 40f0fe8a9..1818e7b8f 100644
--- a/src/compositor/extensions/qwaylandwlshellintegration_p.h
+++ b/src/compositor/extensions/qwaylandwlshellintegration_p.h
@@ -8,6 +8,8 @@
#include <QtWaylandCompositor/QWaylandWlShellSurface>
+#include <QtCore/qpointer.h>
+
QT_BEGIN_NAMESPACE
//
diff --git a/src/compositor/extensions/qwaylandxdgdecorationv1.cpp b/src/compositor/extensions/qwaylandxdgdecorationv1.cpp
index 64141b5fe..c7af0bca5 100644
--- a/src/compositor/extensions/qwaylandxdgdecorationv1.cpp
+++ b/src/compositor/extensions/qwaylandxdgdecorationv1.cpp
@@ -43,8 +43,7 @@ QT_BEGIN_NAMESPACE
}
\endqml
- \sa QWaylandXdgToplevel::decorationMode,
- {Qt Wayland Compositor Examples - Server Side Decoration Compositor}
+ \sa QWaylandXdgToplevel::decorationMode, {Server Side Decoration Compositor}
*/
/*!
@@ -87,7 +86,7 @@ void QWaylandXdgDecorationManagerV1::initialize()
}
/*!
- \qmlproperty string QtWaylandCompositor::XdgDecorationManagerV1::preferredMode
+ \qmlproperty string XdgDecorationManagerV1::preferredMode
This property holds the decoration mode the compositor prefers.
diff --git a/src/compositor/extensions/qwaylandxdgdialogv1.cpp b/src/compositor/extensions/qwaylandxdgdialogv1.cpp
new file mode 100644
index 000000000..102bfb1dd
--- /dev/null
+++ b/src/compositor/extensions/qwaylandxdgdialogv1.cpp
@@ -0,0 +1,64 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwaylandcompositor.h"
+#include "qwaylandxdgdialogv1_p.h"
+
+#include <QWaylandXdgToplevel>
+#include <wayland-server.h>
+
+QT_BEGIN_NAMESPACE
+
+QWaylandXdgDialogV1Global::QWaylandXdgDialogV1Global(QWaylandCompositor *parent)
+ : QWaylandCompositorExtensionTemplate<QWaylandXdgDialogV1Global>(parent)
+{
+}
+
+void QWaylandXdgDialogV1Global::initialize()
+{
+ QWaylandCompositorExtensionTemplate::initialize();
+ QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
+ if (compositor)
+ init(compositor->display(), 1);
+}
+
+void QWaylandXdgDialogV1Global::xdg_wm_dialog_v1_get_xdg_dialog(Resource *resource, uint32_t id, wl_resource *toplevelResource)
+{
+ auto *toplevel = QWaylandXdgToplevel::fromResource(toplevelResource);
+ (void)new QWaylandXdgDialogV1(toplevel, resource->client(), id);
+}
+
+QWaylandXdgDialogV1::QWaylandXdgDialogV1(QWaylandXdgToplevel *toplevel, wl_client *client, int id)
+ : QtWaylandServer::xdg_dialog_v1(client, id, 1), m_topLevel(toplevel)
+{
+}
+
+void QWaylandXdgDialogV1::xdg_dialog_v1_set_modal(Resource *resource)
+{
+ Q_UNUSED(resource);
+ if (m_topLevel)
+ m_topLevel->setModal(true);
+
+}
+
+void QWaylandXdgDialogV1::xdg_dialog_v1_unset_modal(Resource *resource)
+{
+ Q_UNUSED(resource);
+ if (m_topLevel)
+ m_topLevel->setModal(false);
+}
+
+void QWaylandXdgDialogV1::xdg_dialog_v1_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource);
+ delete this;
+}
+
+void QWaylandXdgDialogV1::xdg_dialog_v1_destroy(Resource *resource)
+{
+ if (m_topLevel)
+ m_topLevel->setModal(false);
+ wl_resource_destroy(resource->handle);
+}
+
+QT_END_NAMESPACE
diff --git a/src/compositor/extensions/qwaylandxdgdialogv1_p.h b/src/compositor/extensions/qwaylandxdgdialogv1_p.h
new file mode 100644
index 000000000..b6353c72f
--- /dev/null
+++ b/src/compositor/extensions/qwaylandxdgdialogv1_p.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWAYLANDXDGDIALOGV1_P_H
+#define QWAYLANDXDGDIALOGV1_P_H
+#include "qwaylandxdgshell.h"
+#include <QtWaylandCompositor/QWaylandCompositorExtensionTemplate>
+#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h>
+#include <QtWaylandCompositor/private/qwayland-server-xdg-dialog-v1.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandXdgDialogV1Global
+ : public QWaylandCompositorExtensionTemplate<QWaylandXdgDialogV1Global>
+ , public QtWaylandServer::xdg_wm_dialog_v1
+{
+ Q_OBJECT
+public:
+ QWaylandXdgDialogV1Global(QWaylandCompositor *parent = nullptr);
+
+ void initialize() override;
+
+protected:
+ void xdg_wm_dialog_v1_get_xdg_dialog(Resource *resource, uint32_t id, wl_resource *toplevelResource) override;
+};
+
+class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandXdgDialogV1
+ : public QtWaylandServer::xdg_dialog_v1
+{
+public:
+ QWaylandXdgDialogV1(QWaylandXdgToplevel *toplevel, wl_client *client, int id);
+
+protected:
+ void xdg_dialog_v1_destroy_resource(Resource *resource) override;
+ void xdg_dialog_v1_destroy(Resource *resource) override;
+
+ void xdg_dialog_v1_set_modal(Resource *resource) override;
+ void xdg_dialog_v1_unset_modal(Resource *resource) override;
+
+private:
+ QPointer<QWaylandXdgToplevel> m_topLevel;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/compositor/extensions/qwaylandxdgoutputv1.cpp b/src/compositor/extensions/qwaylandxdgoutputv1.cpp
index 14e50eb82..035d8dd3d 100644
--- a/src/compositor/extensions/qwaylandxdgoutputv1.cpp
+++ b/src/compositor/extensions/qwaylandxdgoutputv1.cpp
@@ -206,7 +206,7 @@ QWaylandXdgOutputV1::~QWaylandXdgOutputV1()
}
/*!
- * \qmlproperty XdgOutputManagerV1 QtWaylandCompositor::XdgOutputV1::manager
+ * \qmlproperty XdgOutputManagerV1 XdgOutputV1::manager
* \readonly
*
* This property holds the object that manages this XdgOutputV1.
@@ -224,7 +224,7 @@ QWaylandXdgOutputManagerV1 *QWaylandXdgOutputV1::manager() const
}
/*!
- * \qmlproperty WaylandOutput QtWaylandCompositor::XdgOutputV1::output
+ * \qmlproperty WaylandOutput XdgOutputV1::output
* \readonly
*
* This property holds the WaylandOutput associated with this XdgOutputV1.
@@ -242,7 +242,7 @@ QWaylandOutput *QWaylandXdgOutputV1::output() const
}
/*!
- * \qmlproperty string QtWaylandCompositor::XdgOutputV1::name
+ * \qmlproperty string XdgOutputV1::name
*
* This property holds the name of this output.
*
@@ -293,7 +293,7 @@ void QWaylandXdgOutputV1::setName(const QString &name)
}
/*!
- * \qmlproperty string QtWaylandCompositor::XdgOutputV1::description
+ * \qmlproperty string XdgOutputV1::description
*
* This property holds the description of this output.
*
@@ -334,7 +334,7 @@ void QWaylandXdgOutputV1::setDescription(const QString &description)
}
/*!
- * \qmlproperty point QtWaylandCompositor::XdgOutputV1::logicalPosition
+ * \qmlproperty point XdgOutputV1::logicalPosition
*
* This property holds the coordinates of the output within the global compositor space.
*
@@ -370,7 +370,7 @@ void QWaylandXdgOutputV1::setLogicalPosition(const QPoint &position)
}
/*!
- * \qmlproperty size QtWaylandCompositor::XdgOutputV1::logicalSize
+ * \qmlproperty size XdgOutputV1::logicalSize
*
* This property holds the size of the output in the global compositor space.
*
@@ -422,7 +422,7 @@ void QWaylandXdgOutputV1::setLogicalSize(const QSize &size)
}
/*!
- * \qmlproperty rect QtWaylandCompositor::XdgOutputV1::logicalGeometry
+ * \qmlproperty rect XdgOutputV1::logicalGeometry
* \readonly
*
* This property holds the position and size of the output in the global compositor space.
diff --git a/src/compositor/extensions/qwaylandxdgoutputv1.h b/src/compositor/extensions/qwaylandxdgoutputv1.h
index b8edbac75..79a6235c7 100644
--- a/src/compositor/extensions/qwaylandxdgoutputv1.h
+++ b/src/compositor/extensions/qwaylandxdgoutputv1.h
@@ -4,9 +4,11 @@
#ifndef QWAYLANDXDGOUTPUTV1_H
#define QWAYLANDXDGOUTPUTV1_H
-#include <QRect>
+#include <QtCore/QRect>
#include <QtWaylandCompositor/QWaylandCompositorExtension>
+#if QT_CONFIG(wayland_compositor_quick)
#include <QtWaylandCompositor/qwaylandquickchildren.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -33,7 +35,10 @@ class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandXdgOutputV1 : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QWaylandXdgOutputV1)
+#if QT_CONFIG(wayland_compositor_quick)
Q_WAYLAND_COMPOSITOR_DECLARE_QUICK_CHILDREN(QWaylandXdgOutputV1)
+#endif
+
Q_PROPERTY(QWaylandXdgOutputManagerV1 *manager READ manager NOTIFY managerChanged)
Q_PROPERTY(QWaylandOutput *output READ output NOTIFY outputChanged)
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
diff --git a/src/compositor/extensions/qwaylandxdgshell.cpp b/src/compositor/extensions/qwaylandxdgshell.cpp
index 0809c3f83..7185d749e 100644
--- a/src/compositor/extensions/qwaylandxdgshell.cpp
+++ b/src/compositor/extensions/qwaylandxdgshell.cpp
@@ -9,6 +9,8 @@
#endif
#include <QtWaylandCompositor/private/qwaylandutils_p.h>
+#include "qwaylandxdgdialogv1_p.h"
+
#include <QtWaylandCompositor/QWaylandCompositor>
#include <QtWaylandCompositor/QWaylandSeat>
#include <QtWaylandCompositor/QWaylandSurface>
@@ -45,7 +47,7 @@ void QWaylandXdgShellPrivate::unregisterXdgSurface(QWaylandXdgSurface *xdgSurfac
QWaylandXdgSurface *QWaylandXdgShellPrivate::xdgSurfaceFromSurface(QWaylandSurface *surface)
{
- for (QWaylandXdgSurface *xdgSurface : qAsConst(m_xdgSurfaces)) {
+ for (QWaylandXdgSurface *xdgSurface : std::as_const(m_xdgSurfaces)) {
if (surface == xdgSurface->surface())
return xdgSurface;
}
@@ -181,6 +183,10 @@ void QWaylandXdgShell::initialize()
connect(compositor, &QWaylandCompositor::defaultSeatChanged,
this, &QWaylandXdgShell::handleSeatChanged);
+
+ // Support the dialog extension unconditionally.
+ QObject *dialogExtension = new QWaylandXdgDialogV1Global(compositor);
+ dialogExtension->setParent(this);
}
/*!
@@ -197,7 +203,7 @@ QByteArray QWaylandXdgShell::interfaceName()
}
/*!
- * \qmlmethod void QtWaylandCompositor::XdgShell::ping(WaylandClient client)
+ * \qmlmethod void XdgShell::ping(WaylandClient client)
*
* Sends a ping event to \a client. If the client replies to the event the
* \l pong signal will be emitted.
@@ -330,6 +336,9 @@ void QWaylandXdgSurfacePrivate::xdg_surface_get_toplevel(QtWaylandServer::xdg_su
m_toplevel = new QWaylandXdgToplevel(q, topLevelResource);
emit q->toplevelCreated();
emit m_xdgShell->toplevelCreated(m_toplevel, q);
+ q->connect(m_toplevel, &QWaylandXdgToplevel::modalChanged, q, [q, this](){
+ q->setModal(m_toplevel->modal());
+ });
}
void QWaylandXdgSurfacePrivate::xdg_surface_get_popup(QtWaylandServer::xdg_surface::Resource *resource, uint32_t id, wl_resource *parentResource, wl_resource *positionerResource)
@@ -475,7 +484,7 @@ QWaylandXdgSurface::QWaylandXdgSurface(QWaylandXdgShell *xdgShell, QWaylandSurfa
}
/*!
- * \qmlmethod void QtWaylandCompositor::XdgSurface::initialize(object xdgShell, object surface, object client, int id)
+ * \qmlmethod void XdgSurface::initialize(object xdgShell, object surface, object client, int id)
*
* Initializes the XdgSurface, associating it with the given \a xdgShell, \a surface,
* \a client, and \a id.
@@ -501,7 +510,7 @@ void QWaylandXdgSurface::initialize(QWaylandXdgShell *xdgShell, QWaylandSurface
}
/*!
- * \qmlproperty enum QtWaylandCompositor::XdgSurface::windowType
+ * \qmlproperty enum XdgSurface::windowType
*
* This property holds the window type of the XdgSurface.
*/
@@ -512,7 +521,7 @@ Qt::WindowType QWaylandXdgSurface::windowType() const
}
/*!
- * \qmlproperty rect QtWaylandCompositor::XdgSurface::windowGeometry
+ * \qmlproperty rect XdgSurface::windowGeometry
*
* This property holds the window geometry of the QWaylandXdgSurface. The window
* geometry describes the window's visible bounds from the user's perspective.
@@ -557,7 +566,7 @@ void QWaylandXdgSurface::handleBufferScaleChanged()
}
/*!
- * \qmlproperty XdgShell QtWaylandCompositor::XdgSurface::shell
+ * \qmlproperty XdgShell XdgSurface::shell
*
* This property holds the shell associated with this XdgSurface.
*/
@@ -574,7 +583,7 @@ QWaylandXdgShell *QWaylandXdgSurface::shell() const
}
/*!
- * \qmlproperty WaylandSurface QtWaylandCompositor::XdgSurface::surface
+ * \qmlproperty WaylandSurface XdgSurface::surface
*
* This property holds the surface associated with this XdgSurface.
*/
@@ -591,7 +600,7 @@ QWaylandSurface *QWaylandXdgSurface::surface() const
}
/*!
- * \qmlproperty XdgToplevel QtWaylandCompositor::XdgSurface::toplevel
+ * \qmlproperty XdgToplevel XdgSurface::toplevel
*
* This property holds the properties and methods that are specific to the
* toplevel XdgSurface.
@@ -614,7 +623,7 @@ QWaylandXdgToplevel *QWaylandXdgSurface::toplevel() const
}
/*!
- * \qmlproperty XdgPopup QtWaylandCompositor::XdgSurface::popup
+ * \qmlproperty XdgPopup XdgSurface::popup
*
* This property holds the properties and methods that are specific to the
* popup XdgSurface.
@@ -725,7 +734,7 @@ QWaylandXdgToplevel::~QWaylandXdgToplevel()
}
/*!
- * \qmlproperty XdgSurface QtWaylandCompositor::XdgToplevel::xdgSurface
+ * \qmlproperty XdgSurface XdgToplevel::xdgSurface
*
* This property holds the XdgSurface for this XdgToplevel.
*/
@@ -742,7 +751,7 @@ QWaylandXdgSurface *QWaylandXdgToplevel::xdgSurface() const
}
/*!
- * \qmlproperty XdgToplevel QtWaylandCompositor::XdgToplevel::parentToplevel
+ * \qmlproperty XdgToplevel XdgToplevel::parentToplevel
*
* This property holds the XdgToplevel parent of this XdgToplevel.
*/
@@ -760,7 +769,7 @@ QWaylandXdgToplevel *QWaylandXdgToplevel::parentToplevel() const
}
/*!
- * \qmlproperty string QtWaylandCompositor::XdgToplevel::title
+ * \qmlproperty string XdgToplevel::title
*
* This property holds the title of the XdgToplevel.
*/
@@ -777,7 +786,7 @@ QString QWaylandXdgToplevel::title() const
}
/*!
- * \qmlproperty string QtWaylandCompositor::XdgToplevel::appId
+ * \qmlproperty string XdgToplevel::appId
*
* This property holds the app id of the XdgToplevel.
*/
@@ -794,7 +803,7 @@ QString QWaylandXdgToplevel::appId() const
}
/*!
- * \qmlproperty size QtWaylandCompositor::XdgToplevel::maxSize
+ * \qmlproperty size XdgToplevel::maxSize
*
* This property holds the maximum size of the XdgToplevel as requested by the client.
*
@@ -815,7 +824,7 @@ QSize QWaylandXdgToplevel::maxSize() const
}
/*!
- * \qmlproperty size QtWaylandCompositor::XdgToplevel::minSize
+ * \qmlproperty size XdgToplevel::minSize
*
* This property holds the minimum size of the XdgToplevel as requested by the client.
*
@@ -847,7 +856,7 @@ QList<QWaylandXdgToplevel::State> QWaylandXdgToplevel::states() const
}
/*!
- * \qmlproperty bool QtWaylandCompositor::XdgToplevel::maximized
+ * \qmlproperty bool XdgToplevel::maximized
*
* This property holds whether the client has acknowledged that it should be maximized.
*/
@@ -864,7 +873,7 @@ bool QWaylandXdgToplevel::maximized() const
}
/*!
- * \qmlproperty bool QtWaylandCompositor::XdgToplevel::fullscreen
+ * \qmlproperty bool XdgToplevel::fullscreen
*
* This property holds whether the client has acknowledged that it should be fullscreen.
*/
@@ -881,7 +890,7 @@ bool QWaylandXdgToplevel::fullscreen() const
}
/*!
- * \qmlproperty bool QtWaylandCompositor::XdgToplevel::resizing
+ * \qmlproperty bool XdgToplevel::resizing
*
* This property holds whether the client has acknowledged that it is being resized.
*/
@@ -898,7 +907,7 @@ bool QWaylandXdgToplevel::resizing() const
}
/*!
- * \qmlproperty bool QtWaylandCompositor::XdgToplevel::activated
+ * \qmlproperty bool XdgToplevel::activated
*
* This property holds whether toplevel is drawing itself as having input focus.
*/
@@ -915,6 +924,34 @@ bool QWaylandXdgToplevel::activated() const
}
/*!
+ * \qmlproperty bool XdgToplevel::modal
+ *
+ * This property holds whether toplevel blocks other windows from receiving input.
+ * \since 6.8
+ */
+
+/*!
+ * \property QWaylandXdgToplevel::modal
+ *
+ * This property holds whether toplevel blocks other windows from receiving input.
+ * \since 6.8
+ */
+bool QWaylandXdgToplevel::modal() const
+{
+ Q_D(const QWaylandXdgToplevel);
+ return d->m_modal;
+}
+
+void QWaylandXdgToplevel::setModal(bool newModal)
+{
+ Q_D(QWaylandXdgToplevel);
+ if (d->m_modal == newModal)
+ return;
+ d->m_modal = newModal;
+ emit modalChanged();
+}
+
+/*!
* \enum QWaylandXdgToplevel::DecorationMode
*
* This enum type is used to specify the window decoration mode for toplevel windows.
@@ -924,7 +961,7 @@ bool QWaylandXdgToplevel::activated() const
*/
/*!
- * \qmlproperty enumeration QtWaylandCompositor::XdgToplevel::decorationMode
+ * \qmlproperty enumeration XdgToplevel::decorationMode
*
* This property holds the current window decoration mode for this toplevel.
*
@@ -949,7 +986,7 @@ QWaylandXdgToplevel::DecorationMode QWaylandXdgToplevel::decorationMode() const
}
/*!
- * \qmlmethod size QtWaylandCompositor::XdgToplevel::sizeForResize(size size, point delta, uint edges)
+ * \qmlmethod size XdgToplevel::sizeForResize(size size, point delta, uint edges)
*
* Convenience for computing the new size given the current \a size, a \a delta, and
* the \a edges active in the drag.
@@ -1005,7 +1042,7 @@ uint QWaylandXdgToplevel::sendConfigure(const QSize &size, const QList<QWaylandX
}
/*!
- * \qmlmethod int QtWaylandCompositor::XdgToplevel::sendConfigure(size size, list<int> states)
+ * \qmlmethod int XdgToplevel::sendConfigure(size size, list<int> states)
*
* Sends a configure event to the client. \a size contains the pixel size of the surface.
* A size of zero means the client is free to decide the size.
@@ -1020,7 +1057,7 @@ uint QWaylandXdgToplevel::sendConfigure(const QSize &size, const QList<int> &sta
}
/*!
- * \qmlmethod void QtWaylandCompositor::XdgToplevel::sendClose()
+ * \qmlmethod void XdgToplevel::sendClose()
*
* Sends a close event to the client. The client may choose to ignore the event.
*/
@@ -1035,7 +1072,7 @@ void QWaylandXdgToplevel::sendClose()
}
/*!
- * \qmlmethod void QtWaylandCompositor::XdgToplevel::sendMaximized(size size)
+ * \qmlmethod void XdgToplevel::sendMaximized(size size)
*
* Convenience for sending a configure event with the maximized state set, and
* fullscreen and resizing removed. The activated state is left in its current state.
@@ -1063,7 +1100,7 @@ uint QWaylandXdgToplevel::sendMaximized(const QSize &size)
}
/*!
- * \qmlmethod void QtWaylandCompositor::XdgToplevel::sendUnmaximized(size size)
+ * \qmlmethod void XdgToplevel::sendUnmaximized(size size)
*
* Convenience for sending a configure event with the maximized, fullscreen and
* resizing states removed, and fullscreen and resizing removed. The activated
@@ -1093,7 +1130,7 @@ uint QWaylandXdgToplevel::sendUnmaximized(const QSize &size)
}
/*!
- * \qmlmethod void QtWaylandCompositor::XdgToplevel::sendFullscreen(size size)
+ * \qmlmethod void XdgToplevel::sendFullscreen(size size)
*
* Convenience for sending a configure event with the fullscreen state set, and
* maximized and resizing removed. The activated state is left in its current state.
@@ -1125,7 +1162,7 @@ uint QWaylandXdgToplevel::sendFullscreen(const QSize &size)
}
/*!
- * \qmlmethod void QtWaylandCompositor::XdgToplevel::sendResizing(size maxSize)
+ * \qmlmethod void XdgToplevel::sendResizing(size maxSize)
*
* Convenience for sending a configure event with the resizing state set, and
* maximized and fullscreen removed. The activated state is left in its current state.
@@ -1171,7 +1208,7 @@ QWaylandXdgToplevel *QWaylandXdgToplevel::fromResource(wl_resource *resource)
}
/*!
- * \qmlsignal QtWaylandCompositor::XdgShell::xdgSurfaceCreated(XdgSurface xdgSurface)
+ * \qmlsignal XdgShell::xdgSurfaceCreated(XdgSurface xdgSurface)
*
* This signal is emitted when the client has created a \c xdg_surface.
* Note that \a xdgSurface is not mapped, i.e. according to the \c xdg-shell
@@ -1191,7 +1228,7 @@ QWaylandXdgToplevel *QWaylandXdgToplevel::fromResource(wl_resource *resource)
*/
/*!
- * \qmlsignal QtWaylandCompositor::XdgShell::toplevelCreated(XdgToplevel toplevel, XdgSurface xdgSurface)
+ * \qmlsignal XdgShell::toplevelCreated(XdgToplevel toplevel, XdgSurface xdgSurface)
*
* This signal is emitted when the client has created a \c xdg_toplevel.
* A common use case is to let the handler of this signal instantiate a ShellSurfaceItem or
@@ -1211,7 +1248,7 @@ QWaylandXdgToplevel *QWaylandXdgToplevel::fromResource(wl_resource *resource)
*/
/*!
- * \qmlsignal QtWaylandCompositor::XdgShell::popupCreated(XdgPopup popup, XdgSurface xdgSurface)
+ * \qmlsignal XdgShell::popupCreated(XdgPopup popup, XdgSurface xdgSurface)
*
* This signal is emitted when the client has created a \c xdg_popup.
* A common use case is to let the handler of this signal instantiate a ShellSurfaceItem or
@@ -1231,7 +1268,7 @@ QWaylandXdgToplevel *QWaylandXdgToplevel::fromResource(wl_resource *resource)
*/
/*!
- * \qmlsignal QtWaylandCompositor::XdgShell::pong(int serial)
+ * \qmlsignal XdgShell::pong(int serial)
*
* This signal is emitted when the client has responded to a ping event with serial, \a serial.
*
@@ -1552,7 +1589,7 @@ QWaylandXdgPopup::QWaylandXdgPopup(QWaylandXdgSurface *xdgSurface, QWaylandXdgSu
}
/*!
- * \qmlproperty XdgSurface QtWaylandCompositor::XdgPopup::xdgSurface
+ * \qmlproperty XdgSurface XdgPopup::xdgSurface
*
* This property holds the XdgSurface associated with this XdgPopup.
*/
@@ -1569,7 +1606,7 @@ QWaylandXdgSurface *QWaylandXdgPopup::xdgSurface() const
}
/*!
- * \qmlproperty XdgSurface QtWaylandCompositor::XdgPopup::parentXdgSurface
+ * \qmlproperty XdgSurface XdgPopup::parentXdgSurface
*
* This property holds the XdgSurface associated with the parent of this XdgPopup.
*/
@@ -1587,7 +1624,7 @@ QWaylandXdgSurface *QWaylandXdgPopup::parentXdgSurface() const
}
/*!
- * \qmlproperty rect QtWaylandCompositor::XdgPopup::configuredGeometry
+ * \qmlproperty rect XdgPopup::configuredGeometry
*
* The window geometry the popup received in the configure event. Relative to the
* upper left corner of the parent surface.
@@ -1606,7 +1643,7 @@ QRect QWaylandXdgPopup::configuredGeometry() const
}
/*!
- * \qmlproperty rect QtWaylandCompositor::XdgPopup::anchorRect
+ * \qmlproperty rect XdgPopup::anchorRect
*
* The anchor rectangle relative to the parent window geometry that the child
* surface should be placed relative to.
@@ -1625,7 +1662,7 @@ QRect QWaylandXdgPopup::anchorRect() const
}
/*!
- * \qmlproperty enumeration QtWaylandCompositor::XdgPopup::anchorEdges
+ * \qmlproperty enumeration XdgPopup::anchorEdges
*
* This property holds the set of edges on the anchor rect that the child surface should be placed
* relative to. If no edges are specified in a direction, the anchor point should be
@@ -1652,7 +1689,7 @@ Qt::Edges QWaylandXdgPopup::anchorEdges() const
}
/*!
- * \qmlproperty rect QtWaylandCompositor::XdgPopup::gravityEdges
+ * \qmlproperty rect XdgPopup::gravityEdges
*
* Specifies in what direction the surface should be positioned, relative to the anchor
* point.
@@ -1677,7 +1714,7 @@ Qt::Edges QWaylandXdgPopup::gravityEdges() const
}
/*!
- * \qmlproperty enumeration QtWaylandCompositor::XdgPopup::slideConstraints
+ * \qmlproperty enumeration XdgPopup::slideConstraints
*
* This property holds the orientations in which the child should slide to fit within the screen.
*
@@ -1707,7 +1744,7 @@ Qt::Orientations QWaylandXdgPopup::slideConstraints() const
}
/*!
- * \qmlproperty enumeration QtWaylandCompositor::XdgPopup::flipConstraints
+ * \qmlproperty enumeration XdgPopup::flipConstraints
*
* This property holds the orientations in which the child should flip to fit within the screen.
*
@@ -1737,7 +1774,7 @@ Qt::Orientations QWaylandXdgPopup::flipConstraints() const
}
/*!
- * \qmlproperty enumeration QtWaylandCompositor::XdgPopup::resizeConstraints
+ * \qmlproperty enumeration XdgPopup::resizeConstraints
*
* This property holds the orientations in which the child should resize to fit within the screen.
*
@@ -1767,7 +1804,7 @@ Qt::Orientations QWaylandXdgPopup::resizeConstraints() const
}
/*!
- * \qmlproperty point QtWaylandCompositor::XdgPopup::offset
+ * \qmlproperty point XdgPopup::offset
*
* The position relative to the position of the anchor on the anchor rectangle and
* the anchor on the surface.
@@ -1786,7 +1823,7 @@ QPoint QWaylandXdgPopup::offset() const
}
/*!
- * \qmlproperty size QtWaylandCompositor::XdgPopup::positionerSize
+ * \qmlproperty size XdgPopup::positionerSize
*
* The size requested for the window geometry by the positioner object.
*/
@@ -1803,7 +1840,7 @@ QSize QWaylandXdgPopup::positionerSize() const
}
/*!
- * \qmlproperty point QtWaylandCompositor::XdgPopup::unconstrainedPosition
+ * \qmlproperty point XdgPopup::unconstrainedPosition
*
* The position of the surface relative to the parent window geometry if the surface
* is not constrained. I.e. when not moved to fit inside the screen or similar.
@@ -1822,7 +1859,7 @@ QPoint QWaylandXdgPopup::unconstrainedPosition() const
}
/*!
- * \qmlmethod int QtWaylandCompositor::XdgPopup::sendConfigure(rect geometry)
+ * \qmlmethod int XdgPopup::sendConfigure(rect geometry)
*
* Sends a configure event to the client. \a geometry contains the window geometry
* relative to the upper left corner of the window geometry of the parent surface.
@@ -1844,7 +1881,7 @@ uint QWaylandXdgPopup::sendConfigure(const QRect &geometry)
}
/*!
- * \qmlmethod void QtWaylandCompositor::XdgPopup::sendPopupDone()
+ * \qmlmethod void XdgPopup::sendPopupDone()
* \since 5.14
*
* Dismiss the popup. According to the \c xdg-shell protocol this should make the
diff --git a/src/compositor/extensions/qwaylandxdgshell.h b/src/compositor/extensions/qwaylandxdgshell.h
index 02ae7acd4..82442e841 100644
--- a/src/compositor/extensions/qwaylandxdgshell.h
+++ b/src/compositor/extensions/qwaylandxdgshell.h
@@ -8,7 +8,9 @@
#include <QtWaylandCompositor/QWaylandResource>
#include <QtWaylandCompositor/QWaylandShell>
#include <QtWaylandCompositor/QWaylandShellSurface>
+#if QT_CONFIG(wayland_compositor_quick)
#include <QtWaylandCompositor/qwaylandquickchildren.h>
+#endif
#include <QtCore/QRect>
@@ -61,7 +63,9 @@ class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandXdgSurface : public QWaylandShellSurfac
{
Q_OBJECT
Q_DECLARE_PRIVATE(QWaylandXdgSurface)
+#if QT_CONFIG(wayland_compositor_quick)
Q_WAYLAND_COMPOSITOR_DECLARE_QUICK_CHILDREN(QWaylandXdgSurface)
+#endif
Q_PROPERTY(QWaylandXdgShell *shell READ shell NOTIFY shellChanged)
Q_PROPERTY(QWaylandSurface *surface READ surface NOTIFY surfaceChanged)
Q_PROPERTY(QWaylandXdgToplevel *toplevel READ toplevel NOTIFY toplevelCreated)
@@ -121,12 +125,9 @@ class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandXdgToplevel : public QObject
Q_PROPERTY(bool fullscreen READ fullscreen NOTIFY fullscreenChanged)
Q_PROPERTY(bool resizing READ resizing NOTIFY resizingChanged)
Q_PROPERTY(bool activated READ activated NOTIFY activatedChanged)
-// QDoc fails to parse the property type that includes the keyword 'enum'
-#ifndef Q_CLANG_QDOC
+ Q_PROPERTY(bool modal READ modal NOTIFY modalChanged FINAL REVISION(6,8))
Q_PROPERTY(enum DecorationMode decorationMode READ decorationMode NOTIFY decorationModeChanged)
-#else
- Q_PROPERTY(DecorationMode decorationMode READ decorationMode NOTIFY decorationModeChanged)
-#endif
+
public:
enum State : uint {
MaximizedState = 1,
@@ -171,6 +172,8 @@ public:
static QWaylandSurfaceRole *role();
static QWaylandXdgToplevel *fromResource(::wl_resource *resource);
+ bool modal() const;
+
Q_SIGNALS:
void parentToplevelChanged();
void titleChanged();
@@ -194,8 +197,12 @@ Q_SIGNALS:
void decorationModeChanged();
+ void modalChanged();
+
private:
QList<int> statesAsInts() const;
+ void setModal(bool newModal);
+ friend class QWaylandXdgDialogV1;
};
class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandXdgPopup : public QObject
diff --git a/src/compositor/extensions/qwaylandxdgshell_p.h b/src/compositor/extensions/qwaylandxdgshell_p.h
index 8a93579ac..9ab188a44 100644
--- a/src/compositor/extensions/qwaylandxdgshell_p.h
+++ b/src/compositor/extensions/qwaylandxdgshell_p.h
@@ -4,7 +4,7 @@
#ifndef QWAYLANDXDGSHELL_P_H
#define QWAYLANDXDGSHELL_P_H
-#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h>
+#include <QtWaylandCompositor/private/qwaylandshellsurface_p.h>
#include <QtWaylandCompositor/private/qwaylandshell_p.h>
#include <QtWaylandCompositor/private/qwayland-server-xdg-shell.h>
@@ -66,7 +66,7 @@ protected:
};
class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandXdgSurfacePrivate
- : public QWaylandCompositorExtensionPrivate
+ : public QWaylandShellSurfacePrivate
, public QtWaylandServer::xdg_surface
{
Q_DECLARE_PUBLIC(QWaylandXdgSurface)
@@ -153,6 +153,7 @@ public:
QSize m_maxSize;
QSize m_minSize = {0, 0};
QWaylandXdgToplevelDecorationV1 *m_decoration = nullptr;
+ bool m_modal = false;
static QWaylandSurfaceRole s_role;
};
diff --git a/src/compositor/extensions/qwaylandxdgshellintegration.cpp b/src/compositor/extensions/qwaylandxdgshellintegration.cpp
index ac13fffe0..643ad65ba 100644
--- a/src/compositor/extensions/qwaylandxdgshellintegration.cpp
+++ b/src/compositor/extensions/qwaylandxdgshellintegration.cpp
@@ -49,45 +49,63 @@ bool XdgToplevelIntegration::eventFilter(QObject *object, QEvent *event)
if (event->type() == QEvent::MouseMove) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
return filterMouseMoveEvent(mouseEvent);
- } else if (event->type() == QEvent::MouseButtonRelease) {
- QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
- return filterMouseReleaseEvent(mouseEvent);
+ } else if (event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::TouchEnd || event->type() == QEvent::TouchCancel) {
+ return filterPointerReleaseEvent();
+ } else if (event->type() == QEvent::TouchUpdate) {
+ QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
+ return filterTouchUpdateEvent(touchEvent);
}
return QWaylandQuickShellIntegration::eventFilter(object, event);
}
-bool XdgToplevelIntegration::filterMouseMoveEvent(QMouseEvent *event)
+bool XdgToplevelIntegration::filterPointerMoveEvent(const QPointF &scenePosition)
{
if (grabberState == GrabberState::Resize) {
- Q_ASSERT(resizeState.seat == m_item->compositor()->seatFor(event));
if (!resizeState.initialized) {
- resizeState.initialMousePos = event->scenePosition();
+ resizeState.initialMousePos = scenePosition;
resizeState.initialized = true;
return true;
}
- QPointF delta = m_item->mapToSurface(event->scenePosition() - resizeState.initialMousePos);
+ QPointF delta = m_item->mapToSurface(scenePosition - resizeState.initialMousePos);
QSize newSize = m_toplevel->sizeForResize(resizeState.initialWindowSize, delta, resizeState.resizeEdges);
m_toplevel->sendResizing(newSize);
} else if (grabberState == GrabberState::Move) {
- Q_ASSERT(moveState.seat == m_item->compositor()->seatFor(event));
QQuickItem *moveItem = m_item->moveItem();
if (!moveState.initialized) {
- moveState.initialOffset = moveItem->mapFromItem(nullptr, event->scenePosition());
+ moveState.initialOffset = moveItem->mapFromItem(nullptr, scenePosition);
moveState.initialized = true;
return true;
}
if (!moveItem->parentItem())
return true;
- QPointF parentPos = moveItem->parentItem()->mapFromItem(nullptr, event->scenePosition());
+ QPointF parentPos = moveItem->parentItem()->mapFromItem(nullptr, scenePosition);
moveItem->setPosition(parentPos - moveState.initialOffset);
}
return false;
}
-bool XdgToplevelIntegration::filterMouseReleaseEvent(QMouseEvent *event)
+bool XdgToplevelIntegration::filterTouchUpdateEvent(QTouchEvent *event)
+{
+ if (event->pointCount() == 0)
+ return false;
+
+ Q_ASSERT(grabberState != GrabberState::Move || moveState.seat == m_item->compositor()->seatFor(event));
+ Q_ASSERT(grabberState != GrabberState::Resize || resizeState.seat == m_item->compositor()->seatFor(event));
+
+ QEventPoint point = event->points().first();
+ return filterPointerMoveEvent(point.scenePosition());
+ }
+
+bool XdgToplevelIntegration::filterMouseMoveEvent(QMouseEvent *event)
{
- Q_UNUSED(event);
+ Q_ASSERT(grabberState != GrabberState::Move || moveState.seat == m_item->compositor()->seatFor(event));
+ Q_ASSERT(grabberState != GrabberState::Resize || resizeState.seat == m_item->compositor()->seatFor(event));
+ return filterPointerMoveEvent(event->scenePosition());
+}
+
+bool XdgToplevelIntegration::filterPointerReleaseEvent()
+{
if (grabberState != GrabberState::Default) {
grabberState = GrabberState::Default;
return true;
diff --git a/src/compositor/extensions/qwaylandxdgshellintegration_p.h b/src/compositor/extensions/qwaylandxdgshellintegration_p.h
index 3fe095874..eba397678 100644
--- a/src/compositor/extensions/qwaylandxdgshellintegration_p.h
+++ b/src/compositor/extensions/qwaylandxdgshellintegration_p.h
@@ -89,8 +89,10 @@ private:
// geometry-changed.
} nonwindowedState;
+ bool filterPointerMoveEvent(const QPointF &scenePosition);
bool filterMouseMoveEvent(QMouseEvent *event);
- bool filterMouseReleaseEvent(QMouseEvent *event);
+ bool filterPointerReleaseEvent();
+ bool filterTouchUpdateEvent(QTouchEvent *event);
};
class XdgPopupIntegration : public QWaylandQuickShellIntegration
diff --git a/src/compositor/extensions/qwlqttouch.cpp b/src/compositor/extensions/qwlqttouch.cpp
index 89753cc1f..1435dde1e 100644
--- a/src/compositor/extensions/qwlqttouch.cpp
+++ b/src/compositor/extensions/qwlqttouch.cpp
@@ -33,13 +33,13 @@ static inline int toFixed(qreal f)
bool TouchExtensionGlobal::postTouchEvent(QTouchEvent *event, QWaylandSurface *surface)
{
const QList<QTouchEvent::TouchPoint> points = event->points();
- const int pointCount = points.count();
+ const int pointCount = points.size();
if (!pointCount)
return false;
wl_client *surfaceClient = surface->client()->client();
uint32_t time = m_compositor->currentTimeMsecs();
- const int rescount = m_resources.count();
+ const int rescount = m_resources.size();
for (int res = 0; res < rescount; ++res) {
Resource *target = m_resources.at(res);
diff --git a/src/compositor/extensions/qwltexturesharingextension.cpp b/src/compositor/extensions/qwltexturesharingextension.cpp
index 9d7810a15..c474176d2 100644
--- a/src/compositor/extensions/qwltexturesharingextension.cpp
+++ b/src/compositor/extensions/qwltexturesharingextension.cpp
@@ -99,7 +99,7 @@ public:
return m_errorString;
}
-public slots:
+public Q_SLOTS:
void doResponse(const QString &key, QtWayland::ServerBuffer *buffer)
{
if (key != m_id)
@@ -144,7 +144,7 @@ QQuickImageResponse *QWaylandSharedTextureProvider::requestImageResponse(const Q
void QWaylandSharedTextureProvider::setExtensionReady(QWaylandTextureSharingExtension *extension)
{
- for (auto *response : qAsConst(m_pendingResponses))
+ for (auto *response : std::as_const(m_pendingResponses))
response->doRequest(extension);
m_pendingResponses.clear();
m_pendingResponses.squeeze();
@@ -199,7 +199,7 @@ void QWaylandTextureSharingExtension::initialize()
auto suffixes = QTextureFileReader::supportedFileFormats();
suffixes.append(QImageReader::supportedImageFormats());
- for (auto ext : qAsConst(suffixes))
+ for (auto ext : std::as_const(suffixes))
m_image_suffixes << QLatin1Char('.') + QString::fromLatin1(ext);
//qDebug() << "m_image_suffixes" << m_image_suffixes << "m_image_dirs" << m_image_dirs;
@@ -224,13 +224,13 @@ QString QWaylandTextureSharingExtension::getExistingFilePath(const QString &key)
if (key.contains(QLatin1String("../")))
return QString();
- for (auto dir : qAsConst(m_image_dirs)) {
+ for (auto dir : std::as_const(m_image_dirs)) {
QString path = dir + key;
if (QFileInfo::exists(path))
return path;
}
- for (auto dir : qAsConst(m_image_dirs)) {
+ for (auto dir : std::as_const(m_image_dirs)) {
for (auto ext : m_image_suffixes) {
QString fp = dir + key + ext;
//qDebug() << "trying" << fp;
@@ -399,7 +399,7 @@ void QWaylandTextureSharingExtension::cleanupBuffers()
void QWaylandTextureSharingExtension::dumpBufferInfo()
{
- qDebug() << "shared buffers:" << m_server_buffers.count();
+ qDebug() << "shared buffers:" << m_server_buffers.size();
for (auto it = m_server_buffers.cbegin(); it != m_server_buffers.cend(); ++it)
qDebug() << " " << it.key() << ":" << it.value().buffer << "in use" << it.value().buffer->bufferInUse() << "usedLocally" << it.value().usedLocally ;
}
diff --git a/src/compositor/extensions/qwltexturesharingextension_p.h b/src/compositor/extensions/qwltexturesharingextension_p.h
index 784f94a2a..92f9ee187 100644
--- a/src/compositor/extensions/qwltexturesharingextension_p.h
+++ b/src/compositor/extensions/qwltexturesharingextension_p.h
@@ -71,13 +71,13 @@ public:
static QWaylandTextureSharingExtension *self() { return s_self; }
-public slots:
+public Q_SLOTS:
void requestBuffer(const QString &key);
-signals:
+Q_SIGNALS:
void bufferResult(const QString &key, QtWayland::ServerBuffer *buffer);
-protected slots:
+protected Q_SLOTS:
void cleanupBuffers();
protected:
diff --git a/src/compositor/global/qwaylandcompositorextension.cpp b/src/compositor/global/qwaylandcompositorextension.cpp
index 18179177b..3a10d177a 100644
--- a/src/compositor/global/qwaylandcompositorextension.cpp
+++ b/src/compositor/global/qwaylandcompositorextension.cpp
@@ -44,7 +44,7 @@ QT_BEGIN_NAMESPACE
*
* In this example, \c MyExtension is an implementation of the generated interface \c my_extension.
*
- * \sa {Qt Wayland Compositor Examples - Custom Shell}
+ * \sa {Custom Shell}
*/
/*!
@@ -68,7 +68,7 @@ QT_BEGIN_NAMESPACE
* For example, for registering global extensions, you can inherit from QWaylandCompositorExtension
* and pass the QWaylandCompositor object as extension container.
*
- * \sa QWaylandCompositorExtensionTemplate, {Qt Wayland Compositor Examples - Custom Shell}
+ * \sa QWaylandCompositorExtensionTemplate, {Custom Shell}
*/
/*!
@@ -222,7 +222,7 @@ QWaylandObject::QWaylandObject(QObjectPrivate &d, QObject *parent)
QWaylandObject::~QWaylandObject()
{
- for (QWaylandCompositorExtension *extension : qAsConst(extension_vector))
+ for (QWaylandCompositorExtension *extension : std::as_const(extension_vector))
QWaylandCompositorExtensionPrivate::get(extension)->extension_container = nullptr;
}
@@ -277,6 +277,8 @@ void QWaylandObject::addExtension(QWaylandCompositorExtension *extension)
*/
void QWaylandObject::removeExtension(QWaylandCompositorExtension *extension)
{
+ if (!extension->isInitialized())
+ return;
Q_ASSERT(extension_vector.contains(extension));
extension_vector.removeOne(extension);
}
diff --git a/src/compositor/global/qwaylandquickextension.h b/src/compositor/global/qwaylandquickextension.h
index ef51fb2eb..2338b0d6e 100644
--- a/src/compositor/global/qwaylandquickextension.h
+++ b/src/compositor/global/qwaylandquickextension.h
@@ -4,6 +4,10 @@
#ifndef QWAYLANDQUICKEXTENSION_H
#define QWAYLANDQUICKEXTENSION_H
+#if 0
+#pragma qt_class(QWaylandQuickExtension)
+#endif
+
#include <QtWaylandCompositor/QWaylandCompositorExtension>
#include <QtQml/QQmlParserStatus>
#include <QtQml/QQmlListProperty>
diff --git a/src/compositor/global/qwaylandquickextension.qdoc b/src/compositor/global/qwaylandquickextension.qdoc
index 09f05cfa0..5977e56c9 100644
--- a/src/compositor/global/qwaylandquickextension.qdoc
+++ b/src/compositor/global/qwaylandquickextension.qdoc
@@ -7,13 +7,13 @@
* \inmodule QtWaylandCompositor
* \ingroup funclists
*
- * \brief The <QWaylandQuickExtension> header file includes \l{macros} for creating Qt Quick types
+ * \brief The <QWaylandQuickExtension> header file includes macros for creating Qt Quick types
* that correspond to subclasses of QWaylandCompositorExtension and QWaylandObject.
*
* If you are creating extensions to Qt Wayland Compositor, the macros in the QWaylandQuickExtension
* header may be a useful alternative to manually implementing the required parts for each class.
*
- * \sa {Qt Wayland Compositor Examples - Custom Shell}
+ * \sa {Custom Shell}
*/
/*!
diff --git a/src/compositor/hardware_integration/qwlclientbufferintegrationfactory.cpp b/src/compositor/hardware_integration/qwlclientbufferintegrationfactory.cpp
index f96d6c4eb..c85cba80f 100644
--- a/src/compositor/hardware_integration/qwlclientbufferintegrationfactory.cpp
+++ b/src/compositor/hardware_integration/qwlclientbufferintegrationfactory.cpp
@@ -12,17 +12,17 @@ QT_BEGIN_NAMESPACE
namespace QtWayland {
-Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, qwbifiLoader,
(QtWaylandClientBufferIntegrationFactoryInterface_iid, QLatin1String("/wayland-graphics-integration-server"), Qt::CaseInsensitive))
QStringList ClientBufferIntegrationFactory::keys()
{
- return loader->keyMap().values();
+ return qwbifiLoader->keyMap().values();
}
ClientBufferIntegration *ClientBufferIntegrationFactory::create(const QString &name, const QStringList &args)
{
- return qLoadPlugin<ClientBufferIntegration, ClientBufferIntegrationPlugin>(loader(), name, args);
+ return qLoadPlugin<ClientBufferIntegration, ClientBufferIntegrationPlugin>(qwbifiLoader(), name, args);
}
}
diff --git a/src/compositor/hardware_integration/qwlhardwarelayerintegrationfactory.cpp b/src/compositor/hardware_integration/qwlhardwarelayerintegrationfactory.cpp
index c521d8cac..01c0c95a0 100644
--- a/src/compositor/hardware_integration/qwlhardwarelayerintegrationfactory.cpp
+++ b/src/compositor/hardware_integration/qwlhardwarelayerintegrationfactory.cpp
@@ -13,17 +13,17 @@ QT_BEGIN_NAMESPACE
namespace QtWayland {
-Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, qwhlifLoader,
(QtWaylandHardwareLayerIntegrationFactoryInterface_iid, QLatin1String("/wayland-hardware-layer-integration"), Qt::CaseInsensitive))
QStringList HardwareLayerIntegrationFactory::keys()
{
- return loader->keyMap().values();
+ return qwhlifLoader->keyMap().values();
}
HardwareLayerIntegration *HardwareLayerIntegrationFactory::create(const QString &name, const QStringList &args)
{
- return qLoadPlugin<HardwareLayerIntegration, HardwareLayerIntegrationPlugin>(loader(), name, args);
+ return qLoadPlugin<HardwareLayerIntegration, HardwareLayerIntegrationPlugin>(qwhlifLoader(), name, args);
}
}
diff --git a/src/compositor/hardware_integration/qwlserverbufferintegrationfactory.cpp b/src/compositor/hardware_integration/qwlserverbufferintegrationfactory.cpp
index 2551cedb3..a92c3f35e 100644
--- a/src/compositor/hardware_integration/qwlserverbufferintegrationfactory.cpp
+++ b/src/compositor/hardware_integration/qwlserverbufferintegrationfactory.cpp
@@ -12,17 +12,17 @@ QT_BEGIN_NAMESPACE
namespace QtWayland {
-Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, qwsbifLoader,
(QtWaylandServerBufferIntegrationFactoryInterface_iid, QLatin1String("/wayland-graphics-integration-server"), Qt::CaseInsensitive))
QStringList ServerBufferIntegrationFactory::keys()
{
- return loader->keyMap().values();
+ return qwsbifLoader->keyMap().values();
}
ServerBufferIntegration *ServerBufferIntegrationFactory::create(const QString &name, const QStringList &args)
{
- return qLoadPlugin<ServerBufferIntegration, ServerBufferIntegrationPlugin>(loader(), name, args);
+ return qLoadPlugin<ServerBufferIntegration, ServerBufferIntegrationPlugin>(qwsbifLoader(), name, args);
}
}
diff --git a/src/compositor/hardware_integration/qwltextureorphanage.cpp b/src/compositor/hardware_integration/qwltextureorphanage.cpp
new file mode 100644
index 000000000..c1ff86977
--- /dev/null
+++ b/src/compositor/hardware_integration/qwltextureorphanage.cpp
@@ -0,0 +1,108 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwltextureorphanage_p.h"
+
+#include <QOpenGLContext>
+#include <QOpenGLTexture>
+#include <QDebug>
+#include <QtTypeTraits>
+#include <QMutexLocker>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qLcWTO, "qt.waylandcompositor.orphanage")
+
+Q_GLOBAL_STATIC(QtWayland::QWaylandTextureOrphanage, inst)
+
+namespace QtWayland {
+
+QWaylandTextureOrphanage::~QWaylandTextureOrphanage()
+{
+ QMutexLocker locker(&m_containerLock);
+ if (!m_orphanedTextures.isEmpty()) {
+ qCWarning(qLcWTO) << Q_FUNC_INFO << "m_orphanedTextures container isn't empty! content:"
+ << m_orphanedTextures;
+ }
+}
+
+QWaylandTextureOrphanage *QWaylandTextureOrphanage::instance()
+{
+ return inst;
+}
+
+void QWaylandTextureOrphanage::admitTexture(QOpenGLTexture *tex, QOpenGLContext *ctx)
+{
+ qCDebug(qLcWTO) << Q_FUNC_INFO << "got a texture (" << (void *)tex
+ << ") ready to be deleted! It's ctx:" << ctx;
+
+ {
+ QMutexLocker locker(&m_containerLock);
+ m_orphanedTextures.insert(ctx, tex);
+ }
+
+ connect(ctx, &QOpenGLContext::aboutToBeDestroyed, this,
+ [this, ctx]() { this->onContextAboutToBeDestroyed(ctx); },
+ Qt::ConnectionType(Qt::DirectConnection));
+}
+
+void QWaylandTextureOrphanage::deleteTextures()
+{
+ QOpenGLContext *cCtx = QOpenGLContext::currentContext();
+
+ if (cCtx == nullptr) {
+ qCWarning(qLcWTO) << Q_FUNC_INFO << "cannot delete textures without current OpenGL context";
+ return;
+ }
+
+ {
+ QMutexLocker locker(&m_containerLock);
+
+ for (QOpenGLContext *aCtx : m_orphanedTextures.keys()) {
+ if (QOpenGLContext::areSharing(cCtx, aCtx)) {
+
+ qCDebug(qLcWTO) << Q_FUNC_INFO << "currentContext (" << cCtx
+ << ") and ctx of orphane(s) (" << aCtx
+ << ") are shared! => deleteTexturesByContext";
+
+ deleteTexturesByContext(aCtx);
+ }
+ }
+ }
+}
+
+void QWaylandTextureOrphanage::onContextAboutToBeDestroyed(QOpenGLContext *ctx)
+{
+ Q_ASSERT(ctx != nullptr);
+
+ qCDebug(qLcWTO) << Q_FUNC_INFO << " ctx (" << ctx
+ << ") fired aboutToBeDestroyed => deleteTexturesByContext(ctx)";
+
+ {
+ QMutexLocker locker(&m_containerLock);
+ deleteTexturesByContext(ctx);
+ }
+}
+
+void QWaylandTextureOrphanage::deleteTexturesByContext(QOpenGLContext *ctx)
+{
+ // NOTE: We are (by class-internal design) locked (m_containerLock)
+ // when we enter this function!
+ // If not (e.g.: someone changes something in/around this class),
+ // then in a debug-build we will fail below:
+ Q_ASSERT(!m_containerLock.tryLock());
+
+ QList<QOpenGLTexture *> texturesToDelete = m_orphanedTextures.values(ctx);
+ m_orphanedTextures.remove(ctx);
+
+ for (QOpenGLTexture *tex : texturesToDelete) {
+ delete tex;
+ qCDebug(qLcWTO) << Q_FUNC_INFO << " texture (" << (void *)tex << ") got deleted";
+ }
+}
+
+} // namespace QtWayland
+
+QT_END_NAMESPACE
+
+#include "moc_qwltextureorphanage_p.cpp"
diff --git a/src/compositor/hardware_integration/qwltextureorphanage_p.h b/src/compositor/hardware_integration/qwltextureorphanage_p.h
new file mode 100644
index 000000000..f040ec750
--- /dev/null
+++ b/src/compositor/hardware_integration/qwltextureorphanage_p.h
@@ -0,0 +1,64 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWLTEXTUREORPHANAGE_P_H
+#define QWLTEXTUREORPHANAGE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QObject>
+#include <QMutex>
+#include <QLoggingCategory>
+#include <QtWaylandCompositor/qtwaylandcompositorglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLContext;
+class QOpenGLTexture;
+
+Q_DECLARE_LOGGING_CATEGORY(qLcWTO)
+
+namespace QtWayland {
+
+class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandTextureOrphanage : public QObject
+{
+ Q_OBJECT
+
+public:
+ QWaylandTextureOrphanage(){};
+ ~QWaylandTextureOrphanage();
+
+ static QWaylandTextureOrphanage *instance();
+
+ // texture that isn't needed anymore will be "take care of" (killed) appropriately
+ void admitTexture(QOpenGLTexture *tex, QOpenGLContext *ctx);
+
+ // uses QOpenGLContext::currentContext to call deleteTexturesByContext on all shared ctx
+ void deleteTextures();
+
+public Q_SLOTS:
+ // uses sender() to call deleteTexturesByContext
+ void onContextAboutToBeDestroyed(QOpenGLContext *ctx);
+
+private:
+ void deleteTexturesByContext(QOpenGLContext *ctx);
+
+ // tracks all the orphanes that need to be deleted
+ QMultiHash<QOpenGLContext *, QOpenGLTexture *> m_orphanedTextures;
+
+ QMutex m_containerLock;
+};
+
+} // namespace QtWayland
+
+QT_END_NAMESPACE
+#endif
diff --git a/src/compositor/qmlfiles/WaylandCursorItem.qml b/src/compositor/qmlfiles/WaylandCursorItem.qml
index 1153038b9..dfa704176 100644
--- a/src/compositor/qmlfiles/WaylandCursorItem.qml
+++ b/src/compositor/qmlfiles/WaylandCursorItem.qml
@@ -22,7 +22,7 @@ WaylandQuickItem {
Connections {
target: seat
- onCursorSurfaceRequest: {
+ function onCursorSurfaceRequest(surface, hotspotX, hotspotY) {
cursorItem.surface = surface;
cursorItem.hotspotX = hotspotX;
cursorItem.hotspotY = hotspotY;
@@ -41,7 +41,9 @@ WaylandQuickItem {
Connections {
target: dragIcon.surface
- onOffsetForNextFrame: dragIcon.offset = offset;
+ function onOffsetForNextFrame(offset) {
+ dragIcon.offset = offset;
+ }
}
}
}
diff --git a/src/compositor/shaders/surface.vert b/src/compositor/shaders/surface.vert
index 7b891c77d..bd28d9bf8 100644
--- a/src/compositor/shaders/surface.vert
+++ b/src/compositor/shaders/surface.vert
@@ -1,3 +1,6 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
#version 440
layout(location = 0) in vec2 qt_VertexPosition;
diff --git a/src/compositor/shaders/surface_oes_external.frag b/src/compositor/shaders/surface_oes_external.frag
index 1cec856b2..3064bf7b1 100644
--- a/src/compositor/shaders/surface_oes_external.frag
+++ b/src/compositor/shaders/surface_oes_external.frag
@@ -1,3 +1,6 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
// This shader stump cannot be precompiled and is compiled at run-time.
// Appropriate target preamble added when it is loaded.
diff --git a/src/compositor/shaders/surface_rgba.frag b/src/compositor/shaders/surface_rgba.frag
index f6a7732a4..8bb48dc15 100644
--- a/src/compositor/shaders/surface_rgba.frag
+++ b/src/compositor/shaders/surface_rgba.frag
@@ -1,3 +1,6 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
#version 440
layout(location = 0) in vec2 v_texcoord;
diff --git a/src/compositor/shaders/surface_rgbx.frag b/src/compositor/shaders/surface_rgbx.frag
index 37ad3fd21..600c1beae 100644
--- a/src/compositor/shaders/surface_rgbx.frag
+++ b/src/compositor/shaders/surface_rgbx.frag
@@ -1,3 +1,6 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
#version 440
layout(location = 0) in vec2 v_texcoord;
diff --git a/src/compositor/shaders/surface_y_u_v.frag b/src/compositor/shaders/surface_y_u_v.frag
index f8fa1010d..3c14036ef 100644
--- a/src/compositor/shaders/surface_y_u_v.frag
+++ b/src/compositor/shaders/surface_y_u_v.frag
@@ -1,3 +1,6 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
#version 440
layout(location = 0) in vec2 v_texcoord;
diff --git a/src/compositor/shaders/surface_y_uv.frag b/src/compositor/shaders/surface_y_uv.frag
index 107c30009..42b614882 100644
--- a/src/compositor/shaders/surface_y_uv.frag
+++ b/src/compositor/shaders/surface_y_uv.frag
@@ -1,3 +1,6 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
#version 440
layout(location = 0) in vec2 v_texcoord;
diff --git a/src/compositor/shaders/surface_y_xuxv.frag b/src/compositor/shaders/surface_y_xuxv.frag
index cf554db7c..57609f4fd 100644
--- a/src/compositor/shaders/surface_y_xuxv.frag
+++ b/src/compositor/shaders/surface_y_xuxv.frag
@@ -1,3 +1,6 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
#version 440
layout(location = 0) in vec2 v_texcoord;
diff --git a/src/compositor/wayland_wrapper/qwldatadevicemanager.cpp b/src/compositor/wayland_wrapper/qwldatadevicemanager.cpp
index b7d94ae94..04add014f 100644
--- a/src/compositor/wayland_wrapper/qwldatadevicemanager.cpp
+++ b/src/compositor/wayland_wrapper/qwldatadevicemanager.cpp
@@ -67,7 +67,7 @@ void DataDeviceManager::retain()
{
QList<QString> offers = m_current_selection_source->mimeTypes();
finishReadFromClient();
- if (m_retainedReadIndex >= offers.count()) {
+ if (m_retainedReadIndex >= offers.size()) {
QWaylandCompositorPrivate::get(m_compositor)->feedRetainedSelectionData(&m_retainedData);
return;
}
@@ -104,7 +104,7 @@ void DataDeviceManager::finishReadFromClient(bool exhausted)
void DataDeviceManager::readFromClient(int fd)
{
static char buf[4096];
- int obsCount = m_obsoleteRetainedReadNotifiers.count();
+ int obsCount = m_obsoleteRetainedReadNotifiers.size();
for (int i = 0; i < obsCount; ++i) {
QSocketNotifier *sn = m_obsoleteRetainedReadNotifiers.at(i);
if (sn->socket() == fd) {
diff --git a/src/configure.cmake b/src/configure.cmake
index 3fd7f93e0..00b337786 100644
--- a/src/configure.cmake
+++ b/src/configure.cmake
@@ -1,29 +1,43 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# configure.cmake for the QtWaylandGlobalPrivate module
#### Inputs
-set(INPUT_wayland_text_input_v4_wip OFF CACHE BOOL "")
-
-
#### Libraries
if(LINUX OR QT_FIND_ALL_PACKAGES_ALWAYS)
# waylandclient libraries
+ if(TARGET Wayland::Client)
+ qt_internal_disable_find_package_global_promotion(Wayland::Client)
+ endif()
qt_find_package(Wayland
PROVIDED_TARGETS Wayland::Client
MODULE_NAME waylandclient
QMAKE_LIB wayland-client)
+
+ if(TARGET Wayland::Cursor)
+ qt_internal_disable_find_package_global_promotion(Wayland::Cursor)
+ endif()
qt_find_package(Wayland
PROVIDED_TARGETS Wayland::Cursor
MODULE_NAME waylandclient
QMAKE_LIB wayland-cursor)
qt_add_qmake_lib_dependency(wayland-cursor wayland-client)
+
+ if(TARGET Wayland::Egl)
+ qt_internal_disable_find_package_global_promotion(Wayland::Egl)
+ endif()
qt_find_package(Wayland
PROVIDED_TARGETS Wayland::Egl
MODULE_NAME waylandclient
QMAKE_LIB wayland-egl)
# waylandcompositor libraries
+ if(TARGET Wayland::Server)
+ qt_internal_disable_find_package_global_promotion(Wayland::Server)
+ endif()
qt_find_package(Wayland
PROVIDED_TARGETS Wayland::Server
MODULE_NAME waylandcompositor
@@ -231,12 +245,12 @@ qt_feature("wayland-vulkan-server-buffer" PRIVATE
qt_feature("wayland-datadevice" PRIVATE
CONDITION QT_FEATURE_draganddrop OR QT_FEATURE_clipboard
)
-qt_feature("wayland-text-input-v4-wip" PRIVATE
- LABEL "Qt Wayland TextInput Protocol V4(WIP)"
- PURPOSE "Enables wayland_text_input_unstable_v4(wip)"
+qt_feature("wayland-decoration-adwaita" PRIVATE
+ LABEL "GNOME-like client-side decorations"
+ CONDITION NOT WIN32 AND QT_FEATURE_wayland_client AND TARGET Qt::DBus AND TARGET Qt::Svg
)
-qt_configure_add_summary_entry(ARGS "wayland-text-input-v4-wip")
+
qt_configure_add_summary_entry(ARGS "wayland-client")
qt_configure_add_summary_entry(ARGS "wayland-server")
qt_configure_add_summary_section(NAME "Qt Wayland Drivers")
@@ -248,3 +262,12 @@ qt_configure_add_summary_entry(ARGS "wayland-dmabuf-server-buffer")
qt_configure_add_summary_entry(ARGS "wayland-shm-emulation-server-buffer")
qt_configure_add_summary_entry(ARGS "wayland-vulkan-server-buffer")
qt_configure_end_summary_section() # end of "Qt Wayland Drivers" section
+qt_configure_add_summary_section(NAME "Qt Wayland Decoration Plugins")
+qt_configure_add_summary_entry(ARGS "wayland-decoration-adwaita")
+qt_configure_end_summary_section() # end of "Qt Wayland Decoration Plugins" section
+
+qt_configure_add_report_entry(
+ TYPE ERROR
+ MESSAGE "Qt Gui has been built without 'wayland' feature. This feature is required for building Qt Wayland Client."
+ CONDITION NOT QT_FEATURE_wayland AND QT_FEATURE_wayland_client
+)
diff --git a/src/hardwareintegration/CMakeLists.txt b/src/hardwareintegration/CMakeLists.txt
index f2bab1e1c..bc75a2088 100644
--- a/src/hardwareintegration/CMakeLists.txt
+++ b/src/hardwareintegration/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
if(TARGET Qt::WaylandClient)
add_subdirectory(client)
endif()
diff --git a/src/hardwareintegration/client/CMakeLists.txt b/src/hardwareintegration/client/CMakeLists.txt
index 5f411192d..f63592c84 100644
--- a/src/hardwareintegration/client/CMakeLists.txt
+++ b/src/hardwareintegration/client/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
if(QT_FEATURE_wayland_egl)
add_subdirectory(wayland-egl)
endif()
diff --git a/src/hardwareintegration/client/shm-emulation-server/shmserverbufferintegration.cpp b/src/hardwareintegration/client/shm-emulation-server/shmserverbufferintegration.cpp
index 0b25b9c84..38065dbde 100644
--- a/src/hardwareintegration/client/shm-emulation-server/shmserverbufferintegration.cpp
+++ b/src/hardwareintegration/client/shm-emulation-server/shmserverbufferintegration.cpp
@@ -13,7 +13,7 @@ QT_BEGIN_NAMESPACE
static QOpenGLTexture *createTextureFromShm(const QString &key, int w, int h, int bpl, int format)
{
- QSharedMemory shm(key);
+ QT_IGNORE_DEPRECATIONS(QSharedMemory shm(key);)
bool ok;
ok = shm.attach(QSharedMemory::ReadOnly);
if (!ok) {
diff --git a/src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.cpp b/src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.cpp
index e3bcef1f8..8f1ff9a46 100644
--- a/src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.cpp
+++ b/src/hardwareintegration/client/vulkan-server/vulkanserverbufferintegration.cpp
@@ -14,7 +14,7 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
-static constexpr bool extraDebug =
+static constexpr bool sbiExtraDebug =
#ifdef VULKAN_SERVER_BUFFER_EXTRA_DEBUG
true;
#else
@@ -88,7 +88,7 @@ VulkanServerBuffer::~VulkanServerBuffer()
if (m_texture) { //only do gl cleanup if import has been called
m_integration->deleteGLTextureWhenPossible(m_texture);
- if (extraDebug) qDebug() << "glDeleteMemoryObjectsEXT" << m_memoryObject;
+ if (sbiExtraDebug) qDebug() << "glDeleteMemoryObjectsEXT" << m_memoryObject;
funcs->glDeleteMemoryObjectsEXT(1, &m_memoryObject);
}
qt_server_buffer_release(m_server_buffer);
@@ -100,7 +100,7 @@ void VulkanServerBuffer::import()
if (m_texture)
return;
- if (extraDebug) qDebug() << "importing" << m_fd << Qt::hex << glGetError();
+ if (sbiExtraDebug) qDebug() << "importing" << m_fd << Qt::hex << glGetError();
auto *glContext = QOpenGLContext::currentContext();
if (!glContext)
@@ -110,21 +110,21 @@ void VulkanServerBuffer::import()
return;
funcs->glCreateMemoryObjectsEXT(1, &m_memoryObject);
- if (extraDebug) qDebug() << "glCreateMemoryObjectsEXT" << Qt::hex << glGetError();
+ if (sbiExtraDebug) qDebug() << "glCreateMemoryObjectsEXT" << Qt::hex << glGetError();
funcs->glImportMemoryFdEXT(m_memoryObject, m_memorySize, GL_HANDLE_TYPE_OPAQUE_FD_EXT, m_fd);
- if (extraDebug) qDebug() << "glImportMemoryFdEXT" << Qt::hex << glGetError();
+ if (sbiExtraDebug) qDebug() << "glImportMemoryFdEXT" << Qt::hex << glGetError();
m_texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_texture->create();
- if (extraDebug) qDebug() << "created texture" << m_texture->textureId() << Qt::hex << glGetError();
+ if (sbiExtraDebug) qDebug() << "created texture" << m_texture->textureId() << Qt::hex << glGetError();
m_texture->bind();
- if (extraDebug) qDebug() << "bound texture" << Qt::hex << glGetError();
+ if (sbiExtraDebug) qDebug() << "bound texture" << Qt::hex << glGetError();
funcs->glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, m_internalFormat, m_size.width(), m_size.height(), m_memoryObject, 0 );
- if (extraDebug) qDebug() << "glTexStorageMem2DEXT" << Qt::hex << glGetError();
- if (extraDebug) qDebug() << "format" << Qt::hex << m_internalFormat << GL_RGBA8;
+ if (sbiExtraDebug) qDebug() << "glTexStorageMem2DEXT" << Qt::hex << glGetError();
+ if (sbiExtraDebug) qDebug() << "format" << Qt::hex << m_internalFormat << GL_RGBA8;
}
QOpenGLTexture *VulkanServerBuffer::toOpenGlTexture()
@@ -157,7 +157,7 @@ void VulkanServerBufferIntegration::wlDisplayHandleGlobal(void *data, ::wl_regis
void VulkanServerBufferIntegration::zqt_vulkan_server_buffer_v1_server_buffer_created(qt_server_buffer *id, int32_t fd, uint32_t width, uint32_t height, uint32_t memory_size, uint32_t format)
{
- if (extraDebug) qDebug() << "vulkan_server_buffer_server_buffer_created" << fd;
+ if (sbiExtraDebug) qDebug() << "vulkan_server_buffer_server_buffer_created" << fd;
auto *server_buffer = new VulkanServerBuffer(this, id, fd, width, height, memory_size, format);
qt_server_buffer_set_user_data(id, server_buffer);
}
diff --git a/src/hardwareintegration/client/wayland-egl/CMakeLists.txt b/src/hardwareintegration/client/wayland-egl/CMakeLists.txt
index 8ab1ef6fe..967dd3cab 100644
--- a/src/hardwareintegration/client/wayland-egl/CMakeLists.txt
+++ b/src/hardwareintegration/client/wayland-egl/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from wayland-egl.pro.
#####################################################################
@@ -24,6 +27,7 @@ qt_internal_add_module(WaylandEglClientHwIntegrationPrivate
Qt::WaylandClientPrivate
Wayland::Client
Wayland::Egl
+ NO_GENERATE_CPP_EXPORTS
)
#### Keys ignored in scope 1:.:.:wayland-egl.pro:<TRUE>:
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandeglclientbufferintegration.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandeglclientbufferintegration.cpp
index cc7ee90ae..3b97aef20 100644
--- a/src/hardwareintegration/client/wayland-egl/qwaylandeglclientbufferintegration.cpp
+++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglclientbufferintegration.cpp
@@ -92,6 +92,13 @@ void QWaylandEglClientBufferIntegration::initialize(QWaylandDisplay *display)
break;
}
}
+
+ // On desktop NVIDIA resizing QtQuick freezes them when using threaded rendering QTBUG-95817
+ // In order to support threaded rendering on embedded platforms where resizing is not needed
+ // we check if XDG_CURRENT_DESKTOP is set which desktop environments should set
+ if (qstrcmp(vendor, "NVIDIA") == 0 && qEnvironmentVariableIsSet("XDG_CURRENT_DESKTOP")) {
+ m_supportsThreading = false;
+ }
}
bool QWaylandEglClientBufferIntegration::isValid() const
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
index bf37572da..0b014cd5c 100644
--- a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
+++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
@@ -4,6 +4,7 @@
#include "qwaylandeglwindow_p.h"
#include <QtWaylandClient/private/qwaylandscreen_p.h>
+#include <QtWaylandClient/private/qwaylandsurface_p.h>
#include "qwaylandglcontext_p.h"
#include <QtGui/private/qeglconvenience_p.h>
@@ -23,6 +24,10 @@ QWaylandEglWindow::QWaylandEglWindow(QWindow *window, QWaylandDisplay *display)
, m_clientBufferIntegration(static_cast<QWaylandEglClientBufferIntegration *>(mDisplay->clientBufferIntegration()))
, m_format(window->requestedFormat())
{
+ connect(display, &QWaylandDisplay::connected, this, [this] {
+ m_clientBufferIntegration = static_cast<QWaylandEglClientBufferIntegration *>(
+ mDisplay->clientBufferIntegration());
+ });
}
QWaylandEglWindow::~QWaylandEglWindow()
@@ -60,7 +65,7 @@ void QWaylandEglWindow::setGeometry(const QRect &rect)
void QWaylandEglWindow::updateSurface(bool create)
{
- QMargins margins = mWindowDecoration ? frameMargins() : QMargins{};
+ QMargins margins = clientSideMargins();
QRect rect = geometry();
QSize sizeWithMargins = (rect.size() + QSize(margins.left() + margins.right(), margins.top() + margins.bottom())) * scale();
@@ -79,6 +84,7 @@ void QWaylandEglWindow::updateSurface(bool create)
}
mOffset = QPoint();
} else {
+ QReadLocker locker(&mSurfaceLock);
if (m_waylandEglWindow) {
int current_width, current_height;
static bool disableResizeCheck = qgetenv("QT_WAYLAND_DISABLE_RESIZECHECK").toInt();
@@ -93,8 +99,8 @@ void QWaylandEglWindow::updateSurface(bool create)
m_resize = true;
}
- } else if (create && wlSurface()) {
- m_waylandEglWindow = wl_egl_window_create(wlSurface(), sizeWithMargins.width(), sizeWithMargins.height());
+ } else if (create && mSurface) {
+ m_waylandEglWindow = wl_egl_window_create(mSurface->object(), sizeWithMargins.width(), sizeWithMargins.height());
m_requestedSize = sizeWithMargins;
}
@@ -104,7 +110,7 @@ void QWaylandEglWindow::updateSurface(bool create)
if (mDisplay->supportsWindowDecoration())
fmt.setAlphaBufferSize(8);
EGLConfig eglConfig = q_configFromGLFormat(m_clientBufferIntegration->eglDisplay(), fmt);
- m_format = q_glFormatFromConfig(m_clientBufferIntegration->eglDisplay(), eglConfig);
+ m_format = q_glFormatFromConfig(m_clientBufferIntegration->eglDisplay(), eglConfig, fmt);
m_eglSurface = eglCreateWindowSurface(m_clientBufferIntegration->eglDisplay(), eglConfig, eglw, 0);
if (Q_UNLIKELY(m_eglSurface == EGL_NO_SURFACE))
qCWarning(lcQpaWayland, "Could not create EGL surface (EGL error 0x%x)\n", eglGetError());
@@ -115,7 +121,7 @@ void QWaylandEglWindow::updateSurface(bool create)
QRect QWaylandEglWindow::contentsRect() const
{
QRect r = geometry();
- QMargins m = frameMargins();
+ QMargins m = clientSideMargins();
return QRect(m.left(), m.bottom(), r.width(), r.height());
}
@@ -134,6 +140,8 @@ void QWaylandEglWindow::invalidateSurface()
wl_egl_window_destroy(m_waylandEglWindow);
m_waylandEglWindow = nullptr;
}
+ delete m_contentFBO;
+ m_contentFBO = nullptr;
}
EGLSurface QWaylandEglWindow::eglSurface() const
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
index 376ba5a79..02789b305 100644
--- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
+++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
@@ -195,6 +195,9 @@ QWaylandGLContext::QWaylandGLContext(EGLDisplay eglDisplay, QWaylandDisplay *dis
const QSurfaceFormat &fmt, QPlatformOpenGLContext *share)
: QEGLPlatformContext(fmt, share, eglDisplay), m_display(display)
{
+ m_reconnectionWatcher = QObject::connect(m_display, &QWaylandDisplay::connected,
+ m_display, [this] { invalidateContext(); });
+
switch (format().renderableType()) {
case QSurfaceFormat::OpenVG:
m_api = EGL_OPENVG_API;
@@ -260,6 +263,7 @@ void QWaylandGLContext::destroyTemporaryOffscreenSurface(EGLSurface eglSurface)
QWaylandGLContext::~QWaylandGLContext()
{
+ QObject::disconnect(m_reconnectionWatcher);
delete m_blitter;
m_blitter = nullptr;
if (m_decorationsContext != EGL_NO_CONTEXT)
@@ -269,17 +273,23 @@ QWaylandGLContext::~QWaylandGLContext()
void QWaylandGLContext::beginFrame()
{
Q_ASSERT(m_currentWindow != nullptr);
- m_currentWindow->beginFrame();
+ if (m_supportNonBlockingSwap)
+ m_currentWindow->beginFrame();
}
void QWaylandGLContext::endFrame()
{
Q_ASSERT(m_currentWindow != nullptr);
- m_currentWindow->endFrame();
+ if (m_supportNonBlockingSwap)
+ m_currentWindow->endFrame();
}
bool QWaylandGLContext::makeCurrent(QPlatformSurface *surface)
{
+ if (!isValid()) {
+ return false;
+ }
+
// in QWaylandGLContext() we called eglBindAPI with the correct value. However,
// eglBindAPI's documentation says:
// "eglBindAPI defines the current rendering API for EGL in the thread it is called from"
@@ -294,7 +304,7 @@ bool QWaylandGLContext::makeCurrent(QPlatformSurface *surface)
if (!m_currentWindow->needToUpdateContentFBO() && (eglSurface != EGL_NO_SURFACE)) {
if (!eglMakeCurrent(eglDisplay(), eglSurface, eglSurface, eglContext())) {
- qWarning("QWaylandGLContext::makeCurrent: eglError: %x, this: %p \n", eglGetError(), this);
+ qWarning("QWaylandGLContext::makeCurrent: eglError: %#x, this: %p \n", eglGetError(), this);
return false;
}
return true;
@@ -302,8 +312,6 @@ bool QWaylandGLContext::makeCurrent(QPlatformSurface *surface)
if (m_currentWindow->isExposed())
m_currentWindow->setCanResize(false);
- if (m_decorationsContext != EGL_NO_CONTEXT && !m_currentWindow->decoration())
- m_currentWindow->createDecoration();
if (eglSurface == EGL_NO_SURFACE) {
m_currentWindow->updateSurface(true);
@@ -311,7 +319,7 @@ bool QWaylandGLContext::makeCurrent(QPlatformSurface *surface)
}
if (!eglMakeCurrent(eglDisplay(), eglSurface, eglSurface, eglContext())) {
- qWarning("QWaylandGLContext::makeCurrent: eglError: %x, this: %p \n", eglGetError(), this);
+ qWarning("QWaylandGLContext::makeCurrent: eglError: %#x, this: %p \n", eglGetError(), this);
m_currentWindow->setCanResize(true);
return false;
}
@@ -363,7 +371,8 @@ void QWaylandGLContext::swapBuffers(QPlatformSurface *surface)
window->waitForFrameSync(100);
}
window->handleUpdate();
- eglSwapBuffers(eglDisplay(), eglSurface);
+ if (!eglSwapBuffers(eglDisplay(), eglSurface))
+ qCWarning(lcQpaWayland, "eglSwapBuffers failed with %#x, surface: %p", eglGetError(), eglSurface);
window->setCanResize(true);
}
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext_p.h b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext_p.h
index 00ef99b1a..b985c6675 100644
--- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext_p.h
+++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext_p.h
@@ -62,6 +62,7 @@ private:
wl_surface *m_wlSurface = nullptr;
wl_egl_window *m_eglWindow = nullptr;
QWaylandEglWindow *m_currentWindow = nullptr;
+ QMetaObject::Connection m_reconnectionWatcher;
};
}
diff --git a/src/hardwareintegration/compositor/CMakeLists.txt b/src/hardwareintegration/compositor/CMakeLists.txt
index 82e0be9d4..8da6b3ce1 100644
--- a/src/hardwareintegration/compositor/CMakeLists.txt
+++ b/src/hardwareintegration/compositor/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from compositor.pro.
if(QT_FEATURE_wayland_egl)
diff --git a/src/hardwareintegration/compositor/dmabuf-server/dmabufserverbufferintegration.cpp b/src/hardwareintegration/compositor/dmabuf-server/dmabufserverbufferintegration.cpp
index 2dc0dfb1f..a217c1c89 100644
--- a/src/hardwareintegration/compositor/dmabuf-server/dmabufserverbufferintegration.cpp
+++ b/src/hardwareintegration/compositor/dmabuf-server/dmabufserverbufferintegration.cpp
@@ -100,7 +100,7 @@ QOpenGLTexture *DmaBufServerBuffer::toOpenGlTexture()
bool DmaBufServerBuffer::bufferInUse()
{
- return resourceMap().count() > 0;
+ return resourceMap().size() > 0;
}
DmaBufServerBufferIntegration::DmaBufServerBufferIntegration()
diff --git a/src/hardwareintegration/compositor/drm-egl-server/drmeglserverbufferintegration.cpp b/src/hardwareintegration/compositor/drm-egl-server/drmeglserverbufferintegration.cpp
index 13b566e0f..3c49f30a4 100644
--- a/src/hardwareintegration/compositor/drm-egl-server/drmeglserverbufferintegration.cpp
+++ b/src/hardwareintegration/compositor/drm-egl-server/drmeglserverbufferintegration.cpp
@@ -87,7 +87,7 @@ QOpenGLTexture *DrmEglServerBuffer::toOpenGlTexture()
bool DrmEglServerBuffer::bufferInUse()
{
- return resourceMap().count() > 0;
+ return resourceMap().size() > 0;
}
DrmEglServerBufferIntegration::DrmEglServerBufferIntegration()
diff --git a/src/hardwareintegration/compositor/hardwarelayer/vsp2/vsp2hardwarelayerintegration.cpp b/src/hardwareintegration/compositor/hardwarelayer/vsp2/vsp2hardwarelayerintegration.cpp
index 4cb6bb28b..c30bf5ae3 100644
--- a/src/hardwareintegration/compositor/hardwarelayer/vsp2/vsp2hardwarelayerintegration.cpp
+++ b/src/hardwareintegration/compositor/hardwarelayer/vsp2/vsp2hardwarelayerintegration.cpp
@@ -162,7 +162,7 @@ wl_kms_buffer *Vsp2Layer::nextKmsBuffer()
void Vsp2HardwareLayerIntegration::enableVspLayers()
{
- for (auto &layer : qAsConst(m_layers)) {
+ for (auto &layer : std::as_const(m_layers)) {
Q_ASSERT(!layer->isEnabled());
layer->enableVspLayer();
}
@@ -225,7 +225,7 @@ void Vsp2HardwareLayerIntegration::remove(QWaylandQuickHardwareLayer *hwLayer)
void Vsp2HardwareLayerIntegration::sendFrameCallbacks()
{
- for (auto &layer : qAsConst(m_layers)) {
+ for (auto &layer : std::as_const(m_layers)) {
if (auto *surface = layer->hwLayer()->waylandItem()->surface())
surface->sendFrameCallbacks();
}
diff --git a/src/hardwareintegration/compositor/hardwarelayer/vsp2/vsp2hardwarelayerintegration.h b/src/hardwareintegration/compositor/hardwarelayer/vsp2/vsp2hardwarelayerintegration.h
index 2153a5bdf..3ec77957f 100644
--- a/src/hardwareintegration/compositor/hardwarelayer/vsp2/vsp2hardwarelayerintegration.h
+++ b/src/hardwareintegration/compositor/hardwarelayer/vsp2/vsp2hardwarelayerintegration.h
@@ -64,7 +64,7 @@ public:
bool isEnabled() { return m_layerIndex != -1; }
QWaylandQuickHardwareLayer *hwLayer() const { return m_hwLayer; }
-public slots:
+public Q_SLOTS:
void handleBufferCommitted();
void handleSurfaceChanged();
void updatePosition();
diff --git a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.cpp b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.cpp
index d0f83a696..a608b9c4d 100644
--- a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.cpp
+++ b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.cpp
@@ -5,6 +5,7 @@
#include "linuxdmabufclientbufferintegration.h"
#include <QtWaylandCompositor/QWaylandCompositor>
+#include <QtWaylandCompositor/private/qwltextureorphanage_p.h>
#include <drm_fourcc.h>
#include <drm_mode.h>
@@ -32,7 +33,7 @@ void LinuxDmabuf::zwp_linux_dmabuf_v1_bind_resource(Resource *resource)
// send DRM_FORMAT_MOD_INVALID when no modifiers are supported for a format
if (modifiers.isEmpty())
modifiers << DRM_FORMAT_MOD_INVALID;
- for (const auto &modifier : qAsConst(modifiers)) {
+ for (const auto &modifier : std::as_const(modifiers)) {
if (resource->version() >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) {
const uint32_t modifier_lo = modifier & 0xFFFFFFFF;
const uint32_t modifier_hi = modifier >> 32;
@@ -92,7 +93,7 @@ bool LinuxDmabufParams::handleCreateParams(Resource *resource, int width, int he
// check for holes in plane sequence
auto planeIds = m_planes.keys();
std::sort(planeIds.begin(), planeIds.end());
- for (int i = 0; i < planeIds.count(); ++i) {
+ for (int i = 0; i < planeIds.size(); ++i) {
if (uint(i) != planeIds[i]) {
wl_resource_post_error(resource->handle,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
@@ -257,10 +258,17 @@ LinuxDmabufWlBuffer::~LinuxDmabufWlBuffer()
void LinuxDmabufWlBuffer::buffer_destroy(Resource *resource)
{
Q_UNUSED(resource);
+
+ QMutexLocker locker(&m_texturesLock);
+
for (uint32_t i = 0; i < m_planesNumber; ++i) {
if (m_textures[i] != nullptr) {
- m_clientBufferIntegration->deleteGLTextureWhenPossible(m_textures[i]);
+ QtWayland::QWaylandTextureOrphanage::instance()->admitTexture(m_textures[i],
+ m_texturesContext[i]);
m_textures[i] = nullptr;
+ m_texturesContext[i] = nullptr;
+ QObject::disconnect(m_texturesAboutToBeDestroyedConnection[i]);
+ m_texturesAboutToBeDestroyedConnection[i] = QMetaObject::Connection();
}
if (m_eglImages[i] != EGL_NO_IMAGE_KHR) {
m_clientBufferIntegration->deleteImage(m_eglImages[i]);
@@ -282,9 +290,40 @@ void LinuxDmabufWlBuffer::initImage(uint32_t plane, EGLImageKHR image)
void LinuxDmabufWlBuffer::initTexture(uint32_t plane, QOpenGLTexture *texture)
{
+ QMutexLocker locker(&m_texturesLock);
+
Q_ASSERT(plane < m_planesNumber);
Q_ASSERT(m_textures.at(plane) == nullptr);
+ Q_ASSERT(QOpenGLContext::currentContext());
m_textures[plane] = texture;
+ m_texturesContext[plane] = QOpenGLContext::currentContext();
+
+ m_texturesAboutToBeDestroyedConnection[plane] =
+ QObject::connect(m_texturesContext[plane], &QOpenGLContext::aboutToBeDestroyed,
+ m_texturesContext[plane], [this, plane]() {
+
+ QMutexLocker locker(&this->m_texturesLock);
+
+ // See above lock - there is a chance that this has already been removed from m_textures[plane]!
+ // Furthermore, we can trust that all the rest (e.g. disconnect) has also been properly executed!
+ if (this->m_textures[plane] == nullptr)
+ return;
+
+ delete this->m_textures[plane];
+
+ qCDebug(qLcWaylandCompositorHardwareIntegration)
+ << Q_FUNC_INFO
+ << "texture deleted due to QOpenGLContext::aboutToBeDestroyed!"
+ << "Pointer (now dead) was:" << (void*)(this->m_textures[plane])
+ << " Associated context (about to die too) is: " << (void*)(this->m_texturesContext[plane]);
+
+ this->m_textures[plane] = nullptr;
+ this->m_texturesContext[plane] = nullptr;
+
+ QObject::disconnect(this->m_texturesAboutToBeDestroyedConnection[plane]);
+ this->m_texturesAboutToBeDestroyedConnection[plane] = QMetaObject::Connection();
+
+ }, Qt::DirectConnection);
}
void LinuxDmabufWlBuffer::buffer_destroy_resource(Resource *resource)
diff --git a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.h b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.h
index 208e44004..dba4e3980 100644
--- a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.h
+++ b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabuf.h
@@ -16,6 +16,8 @@
#include <QtCore/QTextStream>
#include <array>
+#include <QtGui/QOpenGLContext>
+#include <QtCore/QMutex>
#include <EGL/egl.h>
#include <EGL/eglext.h>
@@ -123,6 +125,10 @@ private:
LinuxDmabufClientBufferIntegration *m_clientBufferIntegration = nullptr;
std::array<EGLImageKHR, MaxDmabufPlanes> m_eglImages = { {EGL_NO_IMAGE_KHR, EGL_NO_IMAGE_KHR, EGL_NO_IMAGE_KHR, EGL_NO_IMAGE_KHR} };
std::array<QOpenGLTexture *, MaxDmabufPlanes> m_textures = { {nullptr, nullptr, nullptr, nullptr} };
+ std::array<QOpenGLContext *, MaxDmabufPlanes> m_texturesContext = { {nullptr, nullptr, nullptr, nullptr} };
+ std::array<QMetaObject::Connection, MaxDmabufPlanes> m_texturesAboutToBeDestroyedConnection = { {QMetaObject::Connection(), QMetaObject::Connection(), QMetaObject::Connection(), QMetaObject::Connection()} };
+ QMutex m_texturesLock;
+
void freeResources();
void buffer_destroy(Resource *resource) override;
diff --git a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp
index af613f2e3..205f25d1f 100644
--- a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp
+++ b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp
@@ -6,6 +6,7 @@
#include <QtWaylandCompositor/QWaylandCompositor>
#include <QtWaylandCompositor/private/qwayland-server-wayland.h>
+#include <QtWaylandCompositor/private/qwltextureorphanage_p.h>
#include <qpa/qplatformnativeinterface.h>
#include <QtOpenGL/QOpenGLTexture>
#include <QtCore/QVarLengthArray>
@@ -350,13 +351,6 @@ QList<uint64_t> LinuxDmabufClientBufferIntegration::supportedDrmModifiers(uint32
return QList<uint64_t>();
}
-void LinuxDmabufClientBufferIntegration::deleteOrphanedTextures()
-{
- Q_ASSERT(QOpenGLContext::currentContext());
- qDeleteAll(m_orphanedTextures);
- m_orphanedTextures.clear();
-}
-
void LinuxDmabufClientBufferIntegration::deleteImage(EGLImageKHR image)
{
egl_destroy_image(m_eglDisplay, image);
@@ -403,7 +397,7 @@ LinuxDmabufClientBuffer::LinuxDmabufClientBuffer(LinuxDmabufClientBufferIntegrat
QOpenGLTexture *LinuxDmabufClientBuffer::toOpenGlTexture(int plane)
{
// At this point we should have a valid OpenGL context, so it's safe to destroy textures
- m_integration->deleteOrphanedTextures();
+ QtWayland::QWaylandTextureOrphanage::instance()->deleteTextures();
if (!m_buffer)
return nullptr;
diff --git a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.h b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.h
index 24c4eeea8..b72a24d5d 100644
--- a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.h
+++ b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.h
@@ -9,6 +9,7 @@
#include <QtWaylandCompositor/private/qwlclientbufferintegration_p.h>
#include <QtWaylandCompositor/private/qwlclientbuffer_p.h>
#include <QtWaylandCompositor/private/qwayland-server-wayland.h>
+#include <QtCore/QMutex>
#include <drm_fourcc.h>
@@ -45,9 +46,7 @@ public:
QtWayland::ClientBuffer *createBufferFor(wl_resource *resource) override;
bool importBuffer(wl_resource *resource, LinuxDmabufWlBuffer *linuxDmabufBuffer);
void removeBuffer(wl_resource *resource);
- void deleteOrphanedTextures();
void deleteImage(EGLImageKHR image);
- void deleteGLTextureWhenPossible(QOpenGLTexture *texture) { m_orphanedTextures << texture; }
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC gl_egl_image_target_texture_2d = nullptr;
private:
@@ -68,7 +67,7 @@ private:
EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
::wl_display *m_wlDisplay = nullptr;
bool m_displayBound = false;
- QList<QOpenGLTexture *> m_orphanedTextures;
+
QHash<EGLint, YuvFormatConversion> m_yuvFormats;
bool m_supportsDmabufModifiers = false;
QHash<struct ::wl_resource *, LinuxDmabufWlBuffer *> m_importedBuffers;
diff --git a/src/hardwareintegration/compositor/shm-emulation-server/shmserverbufferintegration.cpp b/src/hardwareintegration/compositor/shm-emulation-server/shmserverbufferintegration.cpp
index 9eca71619..6dc99e193 100644
--- a/src/hardwareintegration/compositor/shm-emulation-server/shmserverbufferintegration.cpp
+++ b/src/hardwareintegration/compositor/shm-emulation-server/shmserverbufferintegration.cpp
@@ -33,7 +33,8 @@ ShmServerBuffer::ShmServerBuffer(ShmServerBufferIntegration *integration, const
}
QString key = "qt_shm_emulation_" + QString::number(qimage.cacheKey());
- m_shm = new QSharedMemory(key);
+ // ### Use proper native keys the next time we can break protocol compatibility
+ QT_IGNORE_DEPRECATIONS(m_shm = new QSharedMemory(key);)
qsizetype shm_size = qimage.sizeInBytes();
bool ok = m_shm->create(shm_size) && m_shm->lock();
if (ok) {
@@ -60,7 +61,8 @@ struct ::wl_resource *ShmServerBuffer::resourceForClient(struct ::wl_client *cli
}
struct ::wl_resource *shm_integration_resource = integrationResource->handle;
Resource *resource = add(client, 1);
- m_integration->send_server_buffer_created(shm_integration_resource, resource->handle, m_shm->key(), m_width, m_height, m_bpl, m_shm_format);
+ QT_IGNORE_DEPRECATIONS(const QString shmKey = m_shm->key();)
+ m_integration->send_server_buffer_created(shm_integration_resource, resource->handle, shmKey, m_width, m_height, m_bpl, m_shm_format);
return resource->handle;
}
return bufferResource->handle;
@@ -68,7 +70,7 @@ struct ::wl_resource *ShmServerBuffer::resourceForClient(struct ::wl_client *cli
bool ShmServerBuffer::bufferInUse()
{
- return resourceMap().count() > 0;
+ return resourceMap().size() > 0;
}
QOpenGLTexture *ShmServerBuffer::toOpenGlTexture()
diff --git a/src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.cpp b/src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.cpp
index 8c9d82b6a..1b5aea29a 100644
--- a/src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.cpp
+++ b/src/hardwareintegration/compositor/vulkan-server/vulkanserverbufferintegration.cpp
@@ -16,7 +16,7 @@
#include <QtCore/QDebug>
QT_BEGIN_NAMESPACE
-static constexpr bool extraDebug = false;
+static constexpr bool vsbiExtraDebug = false;
#define DECL_GL_FUNCTION(name, type) \
type name
@@ -179,7 +179,7 @@ QOpenGLTexture *VulkanServerBuffer::toOpenGlTexture()
return nullptr;
funcs->glCreateMemoryObjectsEXT(1, &m_memoryObject);
- if (extraDebug) qDebug() << "glCreateMemoryObjectsEXT" << Qt::hex << glGetError();
+ if (vsbiExtraDebug) qDebug() << "glCreateMemoryObjectsEXT" << Qt::hex << glGetError();
int dupfd = fcntl(m_fd, F_DUPFD_CLOEXEC, 0);
@@ -189,7 +189,7 @@ QOpenGLTexture *VulkanServerBuffer::toOpenGlTexture()
}
funcs->glImportMemoryFdEXT(m_memoryObject, m_memorySize, GL_HANDLE_TYPE_OPAQUE_FD_EXT, dupfd);
- if (extraDebug) qDebug() << "glImportMemoryFdEXT" << Qt::hex << glGetError();
+ if (vsbiExtraDebug) qDebug() << "glImportMemoryFdEXT" << Qt::hex << glGetError();
if (!m_texture)
@@ -197,13 +197,13 @@ QOpenGLTexture *VulkanServerBuffer::toOpenGlTexture()
m_texture->create();
GLuint texId = m_texture->textureId();
- if (extraDebug) qDebug() << "created texture" << texId << Qt::hex << glGetError();
+ if (vsbiExtraDebug) qDebug() << "created texture" << texId << Qt::hex << glGetError();
m_texture->bind();
- if (extraDebug) qDebug() << "bound texture" << texId << Qt::hex << glGetError();
+ if (vsbiExtraDebug) qDebug() << "bound texture" << texId << Qt::hex << glGetError();
funcs->glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, m_glInternalFormat, m_size.width(), m_size.height(), m_memoryObject, 0 );
- if (extraDebug) qDebug() << "glTexStorageMem2DEXT" << Qt::hex << glGetError();
- if (extraDebug) qDebug() << "format" << Qt::hex << m_glInternalFormat << GL_RGBA8;
+ if (vsbiExtraDebug) qDebug() << "glTexStorageMem2DEXT" << Qt::hex << glGetError();
+ if (vsbiExtraDebug) qDebug() << "format" << Qt::hex << m_glInternalFormat << GL_RGBA8;
return m_texture;
@@ -222,7 +222,7 @@ void VulkanServerBuffer::releaseOpenGlTexture()
bool VulkanServerBuffer::bufferInUse()
{
- return (m_texture && m_texture->isCreated()) || resourceMap().count() > 0;
+ return (m_texture && m_texture->isCreated()) || resourceMap().size() > 0;
}
void VulkanServerBuffer::server_buffer_release(Resource *resource)
diff --git a/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp b/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp
index 7c8718cbc..bf3700aec 100644
--- a/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp
+++ b/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp
@@ -21,7 +21,7 @@
QT_BEGIN_NAMESPACE
-static constexpr bool extraDebug = false;
+static constexpr bool vwExtraDebug = false;
#define DECL_VK_FUNCTION(name) \
PFN_ ## name name = nullptr;
@@ -228,7 +228,7 @@ VulkanImageWrapper *VulkanWrapperPrivate::createImage(VkFormat format, VkImageTi
int res = vkBindImageMemory(m_device, image, imageWrapper->textureImageMemory, 0);
Q_UNUSED(res);
- if (extraDebug) qDebug() << "vkBindImageMemory res" << res;
+ if (vwExtraDebug) qDebug() << "vkBindImageMemory res" << res;
VkMemoryGetFdInfoKHR memoryFdInfo = {};
memoryFdInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR;
@@ -236,7 +236,7 @@ VulkanImageWrapper *VulkanWrapperPrivate::createImage(VkFormat format, VkImageTi
memoryFdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
res = vkGetMemoryFdKHR(m_device, &memoryFdInfo, &imageWrapper->imgFd);
- if (extraDebug) qDebug() << "vkGetMemoryFdKHR res" << res << "fd" << imageWrapper->imgFd;
+ if (vwExtraDebug) qDebug() << "vkGetMemoryFdKHR res" << res << "fd" << imageWrapper->imgFd;
return imageWrapper.release();
}
@@ -331,19 +331,19 @@ VkCommandBuffer VulkanWrapperPrivate::beginSingleTimeCommands()
allocInfo.commandPool = m_commandPool;
allocInfo.commandBufferCount = 1;
- if (extraDebug) qDebug() << "allocating...";
+ if (vwExtraDebug) qDebug() << "allocating...";
VkCommandBuffer commandBuffer;
int res = vkAllocateCommandBuffers(m_device, &allocInfo, &commandBuffer);
Q_UNUSED(res);
- if (extraDebug) qDebug() << "vkAllocateCommandBuffers res" << res;
+ if (vwExtraDebug) qDebug() << "vkAllocateCommandBuffers res" << res;
VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
res = vkBeginCommandBuffer(commandBuffer, &beginInfo);
- if (extraDebug) qDebug() << "BEGIN res" << res;
+ if (vwExtraDebug) qDebug() << "BEGIN res" << res;
return commandBuffer;
}
@@ -352,7 +352,7 @@ void VulkanWrapperPrivate::endSingleTimeCommands(VkCommandBuffer commandBuffer)
{
int res = vkEndCommandBuffer(commandBuffer);
Q_UNUSED(res);
- if (extraDebug) qDebug() << "END res" << res;
+ if (vwExtraDebug) qDebug() << "END res" << res;
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
@@ -409,7 +409,7 @@ QueueFamilyIndices VulkanWrapperPrivate::findQueueFamilies(VkPhysicalDevice devi
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
- if (extraDebug) qDebug() << "queueFamilyCount" << queueFamilyCount;
+ if (vwExtraDebug) qDebug() << "queueFamilyCount" << queueFamilyCount;
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
@@ -482,7 +482,7 @@ VulkanImageWrapper *VulkanWrapperPrivate::createTextureImageFromData(const uchar
int texWidth = size.width();
int texHeight = size.height();
bool ok;
- if (extraDebug) qDebug("image load %p %dx%d", pixels, texWidth, texHeight);
+ if (vwExtraDebug) qDebug("image load %p %dx%d", pixels, texWidth, texHeight);
if (!pixels) {
qCritical("VulkanWrapper: failed to load texture image!");
return nullptr;
@@ -497,17 +497,17 @@ VulkanImageWrapper *VulkanWrapperPrivate::createTextureImageFromData(const uchar
void* data;
vkMapMemory(m_device, stagingBufferMemory, 0, bufferSize, 0, &data);
- if (extraDebug) qDebug() << "mapped" << data << bufferSize;
+ if (vwExtraDebug) qDebug() << "mapped" << data << bufferSize;
memcpy(data, pixels, static_cast<size_t>(bufferSize));
vkUnmapMemory(m_device, stagingBufferMemory);
- if (extraDebug) qDebug() << "creating image...";
+ if (vwExtraDebug) qDebug() << "creating image...";
std::unique_ptr<VulkanImageWrapper> imageWrapper(createImage(vkFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, size, bufferSize));
if (!imageWrapper)
return nullptr;
- if (extraDebug) qDebug() << "transition...";
+ if (vwExtraDebug) qDebug() << "transition...";
const VkImage textureImage = imageWrapper->textureImage;
@@ -516,7 +516,7 @@ VulkanImageWrapper *VulkanWrapperPrivate::createTextureImageFromData(const uchar
if (!ok)
return nullptr;
- if (extraDebug) qDebug() << "copyBufferToImage...";
+ if (vwExtraDebug) qDebug() << "copyBufferToImage...";
copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight));
transitionImageLayout(textureImage, vkFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
@@ -541,7 +541,7 @@ void VulkanWrapperPrivate::freeTextureImage(VulkanImageWrapper *imageWrapper)
VulkanWrapperPrivate::VulkanWrapperPrivate(QOpenGLContext *glContext)
{
- if (extraDebug) qDebug("Creating Vulkan instance");
+ if (vwExtraDebug) qDebug("Creating Vulkan instance");
VkApplicationInfo applicationInfo = {};
applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
applicationInfo.pNext = nullptr;
@@ -573,7 +573,7 @@ VulkanWrapperPrivate::VulkanWrapperPrivate(QOpenGLContext *glContext)
VkResult instanceCreationResult = vkCreateInstance(&instanceCreateInfo, nullptr, &m_instance);
- if (extraDebug) qDebug() << "result" << instanceCreationResult;
+ if (vwExtraDebug) qDebug() << "result" << instanceCreationResult;
if (instanceCreationResult != VK_SUCCESS) {
qCritical() << "VulkanWrapper: Failed to create Vulkan instance: Error "
@@ -585,12 +585,12 @@ VulkanWrapperPrivate::VulkanWrapperPrivate(QOpenGLContext *glContext)
uint32_t devCount;
auto res = vkEnumeratePhysicalDevices(m_instance, &devCount, nullptr);
- if (extraDebug) qDebug() << "vkEnumeratePhysicalDevices res =" << res << "count =" << devCount;
+ if (vwExtraDebug) qDebug() << "vkEnumeratePhysicalDevices res =" << res << "count =" << devCount;
QVarLengthArray<VkPhysicalDevice, 5> dev(devCount);
res = vkEnumeratePhysicalDevices(m_instance, &devCount, dev.data());
- if (extraDebug) qDebug() << "...devs res =" << res << "count =" << devCount;
+ if (vwExtraDebug) qDebug() << "...devs res =" << res << "count =" << devCount;
#ifdef VULKAN_SERVER_BUFFER_EXTRA_DEBUG
VkPhysicalDeviceProperties props;
diff --git a/src/hardwareintegration/compositor/wayland-egl/CMakeLists.txt b/src/hardwareintegration/compositor/wayland-egl/CMakeLists.txt
index c88c438d8..f31928550 100644
--- a/src/hardwareintegration/compositor/wayland-egl/CMakeLists.txt
+++ b/src/hardwareintegration/compositor/wayland-egl/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#####################################################################
## WaylandEglCompositorHwIntegrationPrivate Module:
#####################################################################
@@ -18,6 +21,7 @@ qt_internal_add_module(WaylandEglCompositorHwIntegrationPrivate
Qt::Core
Qt::Gui
Qt::WaylandCompositorPrivate
+ NO_GENERATE_CPP_EXPORTS
)
qt_internal_extend_target(WaylandEglCompositorHwIntegrationPrivate CONDITION NOT QT_FEATURE_egl_x11
diff --git a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp
index 0c52c23fe..c8819ba1f 100644
--- a/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp
+++ b/src/hardwareintegration/compositor/wayland-egl/waylandeglclientbufferintegration.cpp
@@ -4,6 +4,7 @@
#include "waylandeglclientbufferintegration_p.h"
#include <QtWaylandCompositor/QWaylandCompositor>
+#include <QtWaylandCompositor/private/qwltextureorphanage_p.h>
#include <qpa/qplatformnativeinterface.h>
#include <QtOpenGL/QOpenGLTexture>
#include <QtGui/QGuiApplication>
@@ -126,7 +127,11 @@ struct BufferState
EGLint egl_format = EGL_TEXTURE_RGBA;
QVarLengthArray<EGLImageKHR, 3> egl_images;
- QOpenGLTexture *textures[3] = {};
+ QOpenGLTexture *textures[3] = {nullptr, nullptr, nullptr};
+ QOpenGLContext *texturesContext[3] = {nullptr, nullptr, nullptr};
+ QMetaObject::Connection texturesAboutToBeDestroyedConnection[3] = {QMetaObject::Connection(), QMetaObject::Connection(), QMetaObject::Connection()};
+ QMutex texturesLock;
+
EGLStreamKHR egl_stream = EGL_NO_STREAM_KHR;
bool isYInverted = true;
@@ -143,17 +148,15 @@ public:
void initEglTexture(WaylandEglClientBuffer *buffer, EGLint format);
bool ensureContext();
bool initEglStream(WaylandEglClientBuffer *buffer, struct ::wl_resource *bufferHandle);
+ void setupBufferAndCleanup(BufferState *bs, QOpenGLTexture *texture, int plane);
void handleEglstreamTexture(WaylandEglClientBuffer *buffer, wl_resource *bufferHandle);
void registerBuffer(struct ::wl_resource *buffer, BufferState state);
- void deleteGLTextureWhenPossible(QOpenGLTexture *texture) { orphanedTextures << texture; }
- void deleteOrphanedTextures();
EGLDisplay egl_display = EGL_NO_DISPLAY;
bool display_bound = false;
::wl_display *wlDisplay = nullptr;
QOffscreenSurface *offscreenSurface = nullptr;
QOpenGLContext *localContext = nullptr;
- QList<QOpenGLTexture *> orphanedTextures;
PFNEGLBINDWAYLANDDISPLAYWL egl_bind_wayland_display = nullptr;
PFNEGLUNBINDWAYLANDDISPLAYWL egl_unbind_wayland_display = nullptr;
@@ -254,6 +257,8 @@ void WaylandEglClientBufferIntegrationPrivate::initEglTexture(WaylandEglClientBu
}
state.egl_images << image;
+
+ QMutexLocker locker(&state.texturesLock);
state.textures[i] = nullptr;
}
}
@@ -280,6 +285,50 @@ bool WaylandEglClientBufferIntegrationPrivate::ensureContext()
return localContextNeeded;
}
+
+void WaylandEglClientBufferIntegrationPrivate::setupBufferAndCleanup(BufferState *bs, QOpenGLTexture *texture, int plane)
+{
+ QMutexLocker locker(&bs->texturesLock);
+
+ bs->textures[plane] = texture;
+ bs->texturesContext[plane] = QOpenGLContext::currentContext();
+
+ Q_ASSERT(bs->texturesContext[plane] != nullptr);
+
+ qCDebug(qLcWaylandCompositorHardwareIntegration)
+ << Q_FUNC_INFO
+ << "(egl) creating a cleanup-lambda for QOpenGLContext::aboutToBeDestroyed!"
+ << ", texture: " << bs->textures[plane]
+ << ", ctx: " << (void*)bs->texturesContext[plane];
+
+ bs->texturesAboutToBeDestroyedConnection[plane] =
+ QObject::connect(bs->texturesContext[plane], &QOpenGLContext::aboutToBeDestroyed,
+ bs->texturesContext[plane], [bs, plane]() {
+
+ QMutexLocker locker(&bs->texturesLock);
+
+ // See above lock - there is a chance that this has already been removed from textures[plane]!
+ // Furthermore, we can trust that all the rest (e.g. disconnect) has also been properly executed!
+ if (bs->textures[plane] == nullptr)
+ return;
+
+ delete bs->textures[plane];
+
+ qCDebug(qLcWaylandCompositorHardwareIntegration)
+ << Q_FUNC_INFO
+ << "texture deleted due to QOpenGLContext::aboutToBeDestroyed!"
+ << "Pointer (now dead) was:" << (void*)(bs->textures[plane])
+ << " Associated context (about to die too) is: " << (void*)(bs->texturesContext[plane]);
+
+ bs->textures[plane] = nullptr;
+ bs->texturesContext[plane] = nullptr;
+
+ QObject::disconnect(bs->texturesAboutToBeDestroyedConnection[plane]);
+ bs->texturesAboutToBeDestroyedConnection[plane] = QMetaObject::Connection();
+
+ }, Qt::DirectConnection);
+}
+
bool WaylandEglClientBufferIntegrationPrivate::initEglStream(WaylandEglClientBuffer *buffer, wl_resource *bufferHandle)
{
BufferState &state = *buffer->d;
@@ -313,7 +362,11 @@ bool WaylandEglClientBufferIntegrationPrivate::initEglStream(WaylandEglClientBuf
auto texture = new QOpenGLTexture(static_cast<QOpenGLTexture::Target>(GL_TEXTURE_EXTERNAL_OES));
texture->create();
- state.textures[0] = texture; // TODO: support multiple planes for the streaming case
+ setupBufferAndCleanup(buffer->d, texture, 0);
+
+ qCDebug(qLcWaylandCompositorHardwareIntegration)
+ << " NEW texture! It's pointer and ctx pointer: "
+ << (void*)state.textures[0] << "; " << (void*)state.texturesContext[0];
texture->bind();
@@ -357,13 +410,6 @@ void WaylandEglClientBufferIntegrationPrivate::handleEglstreamTexture(WaylandEgl
localContext->doneCurrent();
}
-void WaylandEglClientBufferIntegrationPrivate::deleteOrphanedTextures()
-{
- Q_ASSERT(QOpenGLContext::currentContext());
- qDeleteAll(orphanedTextures);
- orphanedTextures.clear();
-}
-
WaylandEglClientBufferIntegration::WaylandEglClientBufferIntegration()
: d_ptr(new WaylandEglClientBufferIntegrationPrivate)
{
@@ -479,9 +525,29 @@ WaylandEglClientBuffer::~WaylandEglClientBuffer()
if (d->egl_stream)
p->funcs->destroy_stream(p->egl_display, d->egl_stream);
- for (auto *texture : d->textures)
- p->deleteGLTextureWhenPossible(texture);
}
+
+ {
+ QMutexLocker locker(&d->texturesLock);
+
+ for (int i=0; i<3; i++) {
+ if (d->textures[i] != nullptr) {
+
+ qCDebug(qLcWaylandCompositorHardwareIntegration)
+ << Q_FUNC_INFO << " handing over texture!"
+ << (void*)d->textures[i] << "; " << (void*)d->texturesContext[i]
+ << " ... current context might be the same: " << QOpenGLContext::currentContext();
+
+ QtWayland::QWaylandTextureOrphanage::instance()->admitTexture(
+ d->textures[i], d->texturesContext[i]);
+ d->textures[i] = nullptr; // in case the aboutToBeDestroyed lambda is called while we where here
+ d->texturesContext[i] = nullptr;
+ QObject::disconnect(d->texturesAboutToBeDestroyedConnection[i]);
+ d->texturesAboutToBeDestroyedConnection[i] = QMetaObject::Connection();
+ }
+ }
+ }
+
delete d;
}
@@ -524,7 +590,7 @@ QOpenGLTexture *WaylandEglClientBuffer::toOpenGlTexture(int plane)
{
auto *p = WaylandEglClientBufferIntegrationPrivate::get(m_integration);
// At this point we should have a valid OpenGL context, so it's safe to destroy textures
- p->deleteOrphanedTextures();
+ QtWayland::QWaylandTextureOrphanage::instance()->deleteTextures();
if (!m_buffer)
return nullptr;
@@ -540,7 +606,7 @@ QOpenGLTexture *WaylandEglClientBuffer::toOpenGlTexture(int plane)
texture->setFormat(openGLFormatFromEglFormat(d->egl_format));
texture->setSize(d->size.width(), d->size.height());
texture->create();
- d->textures[plane] = texture;
+ p->setupBufferAndCleanup(this->d, texture, plane);
}
if (m_textureDirty) {
diff --git a/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.cpp b/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.cpp
index f43bfb092..0924f0fd7 100644
--- a/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.cpp
+++ b/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.cpp
@@ -9,12 +9,14 @@
#include <QtGui/QGuiApplication>
#include <QtGui/QOpenGLContext>
#include <QtGui/QOffscreenSurface>
+#include <QtCore/QMutexLocker>
#include <QtGui/private/qeglstreamconvenience_p.h>
#include <qpa/qplatformnativeinterface.h>
#include <QtWaylandCompositor/private/qwaylandcompositor_p.h>
#include <QtWaylandCompositor/private/qwlbuffermanager_p.h>
+#include <QtWaylandCompositor/private/qwltextureorphanage_p.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
@@ -109,7 +111,11 @@ struct BufferState
BufferState() = default;
EGLint egl_format = EGL_TEXTURE_EXTERNAL_WL;
- QOpenGLTexture *textures[3] = {};
+ QOpenGLTexture *textures[3] = {nullptr, nullptr, nullptr};
+ QOpenGLContext *texturesContext[3] = {nullptr, nullptr, nullptr};
+ QMetaObject::Connection texturesAboutToBeDestroyedConnection[3] = {QMetaObject::Connection(), QMetaObject::Connection(), QMetaObject::Connection()};
+ QMutex texturesLock;
+
EGLStreamKHR egl_stream = EGL_NO_STREAM_KHR;
bool isYInverted = false;
@@ -123,16 +129,14 @@ public:
bool ensureContext();
bool initEglStream(WaylandEglStreamClientBuffer *buffer, struct ::wl_resource *bufferHandle);
+ void setupBufferAndCleanup(BufferState *bs, QOpenGLTexture *texture, int plane);
void handleEglstreamTexture(WaylandEglStreamClientBuffer *buffer);
- void deleteGLTextureWhenPossible(QOpenGLTexture *texture) { orphanedTextures << texture; }
- void deleteOrphanedTextures();
EGLDisplay egl_display = EGL_NO_DISPLAY;
bool display_bound = false;
::wl_display *wlDisplay = nullptr;
QOffscreenSurface *offscreenSurface = nullptr;
QOpenGLContext *localContext = nullptr;
- QList<QOpenGLTexture *> orphanedTextures;
WaylandEglStreamController *eglStreamController = nullptr;
@@ -150,13 +154,6 @@ public:
bool WaylandEglStreamClientBufferIntegrationPrivate::shuttingDown = false;
-void WaylandEglStreamClientBufferIntegrationPrivate::deleteOrphanedTextures()
-{
- Q_ASSERT(QOpenGLContext::currentContext());
- qDeleteAll(orphanedTextures);
- orphanedTextures.clear();
-}
-
bool WaylandEglStreamClientBufferIntegrationPrivate::ensureContext()
{
bool localContextNeeded = false;
@@ -180,6 +177,49 @@ bool WaylandEglStreamClientBufferIntegrationPrivate::ensureContext()
}
+void WaylandEglStreamClientBufferIntegrationPrivate::setupBufferAndCleanup(BufferState *bs, QOpenGLTexture *texture, int plane)
+{
+ QMutexLocker locker(&bs->texturesLock);
+
+ bs->textures[plane] = texture;
+ bs->texturesContext[plane] = QOpenGLContext::currentContext();
+
+ Q_ASSERT(bs->texturesContext[plane] != nullptr);
+
+ qCDebug(qLcWaylandCompositorHardwareIntegration)
+ << Q_FUNC_INFO
+ << "(eglstream) creating a cleanup-lambda for QOpenGLContext::aboutToBeDestroyed!"
+ << ", texture: " << bs->textures[plane]
+ << ", ctx: " << (void*)bs->texturesContext[plane];
+
+ bs->texturesAboutToBeDestroyedConnection[plane] =
+ QObject::connect(bs->texturesContext[plane], &QOpenGLContext::aboutToBeDestroyed,
+ bs->texturesContext[plane], [bs, plane]() {
+
+ QMutexLocker locker(&bs->texturesLock);
+
+ // See above lock - there is a chance that this has already been removed from textures[plane]!
+ // Furthermore, we can trust that all the rest (e.g. disconnect) has also been properly executed!
+ if (bs->textures[plane] == nullptr)
+ return;
+
+ delete bs->textures[plane];
+
+ qCDebug(qLcWaylandCompositorHardwareIntegration)
+ << Q_FUNC_INFO
+ << "texture deleted due to QOpenGLContext::aboutToBeDestroyed!"
+ << "Pointer (now dead) was:" << (void*)(bs->textures[plane])
+ << " Associated context (about to die too) is: " << (void*)(bs->texturesContext[plane]);
+
+ bs->textures[plane] = nullptr;
+ bs->texturesContext[plane] = nullptr;
+
+ QObject::disconnect(bs->texturesAboutToBeDestroyedConnection[plane]);
+ bs->texturesAboutToBeDestroyedConnection[plane] = QMetaObject::Connection();
+
+ }, Qt::DirectConnection);
+}
+
bool WaylandEglStreamClientBufferIntegrationPrivate::initEglStream(WaylandEglStreamClientBuffer *buffer, wl_resource *bufferHandle)
{
BufferState &state = *buffer->d;
@@ -210,7 +250,7 @@ bool WaylandEglStreamClientBufferIntegrationPrivate::initEglStream(WaylandEglStr
auto texture = new QOpenGLTexture(static_cast<QOpenGLTexture::Target>(GL_TEXTURE_EXTERNAL_OES));
texture->create();
- state.textures[0] = texture; // TODO: support multiple planes
+ setupBufferAndCleanup(buffer->d, texture, 0);
texture->bind();
@@ -359,10 +399,29 @@ WaylandEglStreamClientBuffer::~WaylandEglStreamClientBuffer()
if (p) {
if (d->egl_stream)
p->funcs->destroy_stream(p->egl_display, d->egl_stream);
+ }
+
+ {
+ QMutexLocker locker(&d->texturesLock);
- for (auto *texture : d->textures)
- p->deleteGLTextureWhenPossible(texture);
+ for (int i=0; i<3; i++) {
+ if (d->textures[i] != nullptr) {
+
+ qCDebug(qLcWaylandCompositorHardwareIntegration)
+ << Q_FUNC_INFO << " handing over texture!"
+ << (void*)d->textures[i] << "; " << (void*)d->texturesContext[i]
+ << " ... current context might be the same: " << QOpenGLContext::currentContext();
+
+ QtWayland::QWaylandTextureOrphanage::instance()->admitTexture(
+ d->textures[i], d->texturesContext[i]);
+ d->textures[i] = nullptr; // in case the aboutToBeDestroyed lambda is called while we where here
+ d->texturesContext[i] = nullptr;
+ QObject::disconnect(d->texturesAboutToBeDestroyedConnection[i]);
+ d->texturesAboutToBeDestroyedConnection[i] = QMetaObject::Connection();
+ }
+ }
}
+
delete d;
}
@@ -385,9 +444,8 @@ QWaylandSurface::Origin WaylandEglStreamClientBuffer::origin() const
QOpenGLTexture *WaylandEglStreamClientBuffer::toOpenGlTexture(int plane)
{
- auto *p = WaylandEglStreamClientBufferIntegrationPrivate::get(m_integration);
// At this point we should have a valid OpenGL context, so it's safe to destroy textures
- p->deleteOrphanedTextures();
+ QtWayland::QWaylandTextureOrphanage::instance()->deleteTextures();
if (!m_buffer)
return nullptr;
diff --git a/src/imports/CMakeLists.txt b/src/imports/CMakeLists.txt
index 9ff345ae6..417b6bce8 100644
--- a/src/imports/CMakeLists.txt
+++ b/src/imports/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from imports.pro.
if(TARGET Qt::Quick AND TARGET Qt::WaylandCompositor)
diff --git a/src/imports/compositor-extensions/CMakeLists.txt b/src/imports/compositor-extensions/CMakeLists.txt
index 356a4c09f..28d187ab4 100644
--- a/src/imports/compositor-extensions/CMakeLists.txt
+++ b/src/imports/compositor-extensions/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from compositor-extensions.pro.
add_subdirectory(xdgshell)
diff --git a/src/imports/compositor-extensions/iviapplication/CMakeLists.txt b/src/imports/compositor-extensions/iviapplication/CMakeLists.txt
index 4549a3e2e..eaf0f8770 100644
--- a/src/imports/compositor-extensions/iviapplication/CMakeLists.txt
+++ b/src/imports/compositor-extensions/iviapplication/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from iviapplication.pro.
#####################################################################
@@ -19,8 +22,11 @@ qt_internal_add_qml_module(WaylandCompositorIviapplication
Qt::Core
Qt::Gui
Qt::WaylandCompositor
+ NO_GENERATE_CPP_EXPORTS
)
+qt_internal_add_autogen_sync_header_dependencies(WaylandCompositorIviapplication WaylandCompositor)
+
#### Keys ignored in scope 1:.:.:iviapplication.pro:<TRUE>:
# CXX_MODULE = "qml"
# QML_IMPORT_VERSION = "$$QT_VERSION"
diff --git a/src/imports/compositor-extensions/presentationtime/CMakeLists.txt b/src/imports/compositor-extensions/presentationtime/CMakeLists.txt
index d94a438bf..f1413dfc1 100644
--- a/src/imports/compositor-extensions/presentationtime/CMakeLists.txt
+++ b/src/imports/compositor-extensions/presentationtime/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#####################################################################
## qwaylandcompositorpresentationtimeplugin Plugin:
#####################################################################
@@ -16,4 +19,8 @@ qt_internal_add_qml_module(WaylandCompositorPresentationTime
Qt::Core
Qt::Gui
Qt::WaylandCompositorPrivate
+ NO_GENERATE_CPP_EXPORTS
)
+
+qt_internal_add_autogen_sync_header_dependencies(WaylandCompositorPresentationTime
+ WaylandCompositor)
diff --git a/src/imports/compositor-extensions/qtshell/CMakeLists.txt b/src/imports/compositor-extensions/qtshell/CMakeLists.txt
index d9b3d5ef8..7bb165bf3 100644
--- a/src/imports/compositor-extensions/qtshell/CMakeLists.txt
+++ b/src/imports/compositor-extensions/qtshell/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#####################################################################
## qwaylandqtshellplugin Plugin:
#####################################################################
@@ -24,9 +27,12 @@ qt_internal_add_qml_module(WaylandCompositorQtShell
Qt::QuickPrivate
Qt::WaylandCompositor
Qt::WaylandCompositorPrivate
+ NO_GENERATE_CPP_EXPORTS
)
qt6_generate_wayland_protocol_server_sources(WaylandCompositorQtShell
FILES
${CMAKE_CURRENT_SOURCE_DIR}/../../../extensions/qt-shell-unstable-v1.xml
)
+
+qt_internal_add_autogen_sync_header_dependencies(WaylandCompositorQtShell WaylandCompositor)
diff --git a/src/imports/compositor-extensions/qtshell/qwaylandqtshell.cpp b/src/imports/compositor-extensions/qtshell/qwaylandqtshell.cpp
index 7788e3ea8..d0715e8c2 100644
--- a/src/imports/compositor-extensions/qtshell/qwaylandqtshell.cpp
+++ b/src/imports/compositor-extensions/qtshell/qwaylandqtshell.cpp
@@ -157,7 +157,7 @@ QByteArray QWaylandQtShell::interfaceName()
}
/*!
- * \qmlsignal void QtWaylandCompositor::QtShell::qtShellSurfaceRequested(WaylandSurface surface, WaylandResource resource)
+ * \qmlsignal void QtShell::qtShellSurfaceRequested(WaylandSurface surface, WaylandResource resource)
*
* This signal is emitted when the client has requested a QtShellSurface to be associated
* with \a surface. The handler for this signal is expected to create the QtShellSurface for
@@ -166,7 +166,7 @@ QByteArray QWaylandQtShell::interfaceName()
*/
/*!
- * \qmlsignal void QtWaylandCompositor::QtShell::qtShellSurfaceCreated(QtShellSurface *qtShellSurface)
+ * \qmlsignal void QtShell::qtShellSurfaceCreated(QtShellSurface *qtShellSurface)
*
* This signal is emitted when an QtShellSurface has been created. The supplied \a qtShellSurface is
* most commonly used to instantiate a ShellSurfaceItem.
@@ -221,7 +221,7 @@ QWaylandSurfaceRole QWaylandQtShellSurfacePrivate::s_role("qt_shell_surface");
*/
/*!
- \qmlsignal void QtWaylandCompositor::QtShellSurface::startMove()
+ \qmlsignal void QtShellSurface::startMove()
The client has requested an interactive move operation in the compositor by calling
\l{QWindow::startSystemMove()}.
@@ -230,7 +230,7 @@ QWaylandSurfaceRole QWaylandQtShellSurfacePrivate::s_role("qt_shell_surface");
*/
/*!
- \qmlsignal void QtWaylandCompositor::QtShellSurface::startResize(enum edges)
+ \qmlsignal void QtShellSurface::startResize(enum edges)
The client has requested an interactive resize operation in the compositor by calling
\l{QWindow::startSystemResize()}.
@@ -259,7 +259,7 @@ QWaylandQtShellSurface::QWaylandQtShellSurface(QWaylandQtShell *application, QWa
}
/*!
- * \qmlmethod void QtWaylandCompositor::QtShellSurface::initialize(QtShell qtShell, WaylandSurface surface, WaylandResource resource)
+ * \qmlmethod void QtShellSurface::initialize(QtShell qtShell, WaylandSurface surface, WaylandResource resource)
*
* Initializes the QtShellSurface, associating it with the given \a qtShell, \a surface, and
* \a resource.
@@ -282,7 +282,7 @@ void QWaylandQtShellSurface::initialize(QWaylandQtShell *qtShell, QWaylandSurfac
}
/*!
- * \qmlproperty WaylandSurface QtWaylandCompositor::QtShellSurface::surface
+ * \qmlproperty WaylandSurface QtShellSurface::surface
*
* This property holds the surface associated with this QtShellSurface.
*/
@@ -299,7 +299,7 @@ QWaylandQtShell *QWaylandQtShellSurface::shell() const
}
/*!
- * \qmlproperty point QtWaylandCompositor::QtShellSurface::windowPosition
+ * \qmlproperty point QtShellSurface::windowPosition
*
* This property holds the position of the shell surface relative to its output.
*/
@@ -324,7 +324,7 @@ void QWaylandQtShellSurface::setWindowPosition(const QPoint &position)
}
/*!
- * \qmlproperty rect QtWaylandCompositor::QtShellSurface::windowGeometry
+ * \qmlproperty rect QtShellSurface::windowGeometry
*
* This property holds the window geometry of the shell surface.
*/
@@ -335,7 +335,7 @@ QRect QWaylandQtShellSurface::windowGeometry() const
}
/*!
- * \qmlproperty size QtWaylandCompositor::QtShellSurface::minimumSize
+ * \qmlproperty size QtShellSurface::minimumSize
*
* The minimum size of the window if the client has specified one. Otherwise an invalid size.
*/
@@ -346,7 +346,7 @@ QSize QWaylandQtShellSurface::minimumSize() const
}
/*!
- * \qmlproperty size QtWaylandCompositor::QtShellSurface::maximumSize
+ * \qmlproperty size QtShellSurface::maximumSize
*
* The maximum size of the window if the client has specified one. Otherwise an invalid size.
*/
@@ -357,7 +357,7 @@ QSize QWaylandQtShellSurface::maximumSize() const
}
/*!
- * \qmlmethod void QtWaylandCompositor::QtShellSurface::requestWindowGeometry(int windowState, rect windowGeometry)
+ * \qmlmethod void QtShellSurface::requestWindowGeometry(int windowState, rect windowGeometry)
*
* Requests a new \a windowState and \a windowGeometry for the QtShellSurface. The state and
* geometry is updated when the client has acknowledged the request (at which point it is safe to
@@ -402,7 +402,7 @@ void QWaylandQtShellSurface::setFrameMargins(const QMargins &margins)
}
/*!
- * \qmlproperty int QtWaylandCompositor::QtShellSurface::frameMarginLeft
+ * \qmlproperty int QtShellSurface::frameMarginLeft
*
* This holds the window frame margin to the left of the surface.
*/
@@ -425,7 +425,7 @@ int QWaylandQtShellSurface::frameMarginLeft() const
}
/*!
- * \qmlproperty int QtWaylandCompositor::QtShellSurface::frameMarginRight
+ * \qmlproperty int QtShellSurface::frameMarginRight
*
* This holds the window frame margin to the right of the surface.
*/
@@ -448,7 +448,7 @@ int QWaylandQtShellSurface::frameMarginRight() const
}
/*!
- * \qmlproperty int QtWaylandCompositor::QtShellSurface::frameMarginTop
+ * \qmlproperty int QtShellSurface::frameMarginTop
*
* This holds the window frame margin above the surface.
*/
@@ -471,7 +471,7 @@ int QWaylandQtShellSurface::frameMarginTop() const
}
/*!
- * \qmlproperty int QtWaylandCompositor::QtShellSurface::frameMarginBottom
+ * \qmlproperty int QtShellSurface::frameMarginBottom
*
* This holds the window frame margin below the surface.
*/
@@ -499,7 +499,7 @@ int QWaylandQtShellSurface::frameMarginBottom() const
}
/*!
- * \qmlproperty int QtWaylandCompositor::QtShellSurface::windowFlags
+ * \qmlproperty int QtShellSurface::windowFlags
*
* This property holds the window flags of the QtShellSurface.
*/
@@ -510,7 +510,7 @@ uint QWaylandQtShellSurface::windowFlags() const
}
/*!
- * \qmlmethod void QtWaylandCompositor::QtShellSurface::sendClose()
+ * \qmlmethod void QtShellSurface::sendClose()
*
* Requests that the client application closes itself.
*/
@@ -521,7 +521,7 @@ void QWaylandQtShellSurface::sendClose()
}
/*!
- * \qmlproperty string QtWaylandCompositor::QtShellSurface::windowTitle
+ * \qmlproperty string QtShellSurface::windowTitle
*
* This property holds the window title of the QtShellSurface.
*/
@@ -532,7 +532,7 @@ QString QWaylandQtShellSurface::windowTitle() const
}
/*!
- * \qmlproperty bool QtWaylandCompositor::QtShellSurface::active
+ * \qmlproperty bool QtShellSurface::active
*
* This property holds whether the surface is currently considered active.
*
@@ -561,7 +561,7 @@ bool QWaylandQtShellSurface::active() const
}
/*!
- * \qmlproperty enum QtWaylandCompositor::QtShellSurface::capabilities
+ * \qmlproperty enum QtShellSurface::capabilities
*
* This property holds the capabilities of the compositor. By default, no special capabilities are
* enabled.
@@ -594,7 +594,7 @@ QWaylandQtShellSurface::CapabilityFlags QWaylandQtShellSurface::capabilities() c
}
/*!
- * \qmlproperty int QtWaylandCompositor::QtShellSurface::windowState
+ * \qmlproperty int QtShellSurface::windowState
*
* This property holds the window state of the QtShellSurface.
*
diff --git a/src/imports/compositor-extensions/qtshell/qwaylandqtshell_p.h b/src/imports/compositor-extensions/qtshell/qwaylandqtshell_p.h
index e98aae612..ad93dee1a 100644
--- a/src/imports/compositor-extensions/qtshell/qwaylandqtshell_p.h
+++ b/src/imports/compositor-extensions/qtshell/qwaylandqtshell_p.h
@@ -4,7 +4,7 @@
#ifndef QWAYLANDQTSHELL_P_H
#define QWAYLANDQTSHELL_P_H
-#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h>
+#include <QtWaylandCompositor/private/qwaylandshellsurface_p.h>
#include <QtWaylandCompositor/QWaylandSurfaceRole>
#include <QHash>
@@ -43,7 +43,7 @@ protected:
};
class Q_WAYLANDCOMPOSITOR_EXPORT QWaylandQtShellSurfacePrivate
- : public QWaylandCompositorExtensionPrivate
+ : public QWaylandShellSurfacePrivate
, public QtWaylandServer::zqt_shell_surface_v1
{
Q_DECLARE_PUBLIC(QWaylandQtShellSurface)
diff --git a/src/imports/compositor-extensions/qtshell/qwaylandqtshellchrome.cpp b/src/imports/compositor-extensions/qtshell/qwaylandqtshellchrome.cpp
index f15842007..ffccf5d21 100644
--- a/src/imports/compositor-extensions/qtshell/qwaylandqtshellchrome.cpp
+++ b/src/imports/compositor-extensions/qtshell/qwaylandqtshellchrome.cpp
@@ -112,7 +112,7 @@ void QWaylandQtShellChromePrivate::updateDecorationInteraction(quint8 flags,
*
* The QtShellChrome is intended to be used together with QtShell and QtShellSurface.
*
- * \sa {Qt Wayland Compositor Examples - QtShell Compositor}
+ * \sa {QtShell Compositor}
*/
QWaylandQtShellChrome::QWaylandQtShellChrome(QQuickItem *parent)
: QQuickItem(*new QWaylandQtShellChromePrivate{}, parent)
@@ -171,7 +171,7 @@ void QWaylandQtShellChrome::init()
}
/*!
- * \qmlmethod void QtWaylandCompositor::QtShellChrome::toggleFullScreen()
+ * \qmlmethod void QtShellChrome::toggleFullScreen()
*
* Toggles between fullscreen and normal window states. This method also clears the minimized
* or maximized window states if either is set.
@@ -195,7 +195,7 @@ void QWaylandQtShellChrome::toggleFullScreen()
}
/*!
- * \qmlmethod void QtWaylandCompositor::QtShellChrome::toggleMaximized()
+ * \qmlmethod void QtShellChrome::toggleMaximized()
*
* Toggles between maximized and normal states. This method also clears the minimized
* window state if it is set.
@@ -219,7 +219,7 @@ void QWaylandQtShellChrome::toggleMaximized()
}
/*!
- * \qmlmethod void QtWaylandCompositor::QtShellChrome::toggleMinimized()
+ * \qmlmethod void QtShellChrome::toggleMinimized()
*
* Toggles between minimized and normal states. This method also clears the maximized
* window state if it is set.
@@ -243,7 +243,7 @@ void QWaylandQtShellChrome::toggleMinimized()
}
/*!
- * \qmlproperty ShellSurfaceItem QtWaylandCompositor::QtShellChrome::shellSurfaceItem
+ * \qmlproperty ShellSurfaceItem QtShellChrome::shellSurfaceItem
*
* This property holds the shell surface item associated with this QtShellChrome. It will
* in turn manage the \c shellSurface of this item. The \c shellSurface of the item is expected to
@@ -402,7 +402,7 @@ void QWaylandQtShellChrome::titleBarMove()
}
/*!
- * \qmlproperty Item QtWaylandCompositor::QtShellChrome::titleBar
+ * \qmlproperty Item QtShellChrome::titleBar
*
* This property holds the default title bar item of the QtShellChrome. If set, a \l DragHandler
* will be installed on the title bar which moves the window around on user interaction. In
@@ -475,7 +475,7 @@ void QWaylandQtShellChrome::setTitleBar(QQuickItem *item)
}
/*!
- * \qmlproperty Item QtWaylandCompositor::QtShellChrome::leftResizeHandle
+ * \qmlproperty Item QtShellChrome::leftResizeHandle
*
* This property holds the default left resize handle of the QtShellChrome. If set, a \l DragHandler
* will be installed on the resize handle which resizes the window by moving its left edge.
@@ -539,7 +539,7 @@ void QWaylandQtShellChrome::setLeftResizeHandle(QQuickItem *item)
}
/*!
- * \qmlproperty Item QtWaylandCompositor::QtShellChrome::rightResizeHandle
+ * \qmlproperty Item QtShellChrome::rightResizeHandle
*
* This property holds the default right resize handle of the QtShellChrome. If set, a \l DragHandler
* will be installed on the resize handle which resizes the window by moving its right edge.
@@ -603,7 +603,7 @@ void QWaylandQtShellChrome::setRightResizeHandle(QQuickItem *item)
}
/*!
- * \qmlproperty Item QtWaylandCompositor::QtShellChrome::topResizeHandle
+ * \qmlproperty Item QtShellChrome::topResizeHandle
*
* This property holds the default top resize handle of the QtShellChrome. If set, a \l DragHandler
* will be installed on the resize handle which resizes the window by moving its top edge.
@@ -667,7 +667,7 @@ void QWaylandQtShellChrome::setTopResizeHandle(QQuickItem *item)
}
/*!
- * \qmlproperty Item QtWaylandCompositor::QtShellChrome::bottomResizeHandle
+ * \qmlproperty Item QtShellChrome::bottomResizeHandle
*
* This property holds the default bottom resize handle of the QtShellChrome. If set, a \l DragHandler
* will be installed on the resize handle which resizes the window by moving its bottom edge.
@@ -732,7 +732,7 @@ void QWaylandQtShellChrome::setBottomResizeHandle(QQuickItem *item)
}
/*!
- * \qmlproperty Item QtWaylandCompositor::QtShellChrome::topLeftResizeHandle
+ * \qmlproperty Item QtShellChrome::topLeftResizeHandle
*
* This property holds the default top-left resize handle of the QtShellChrome. If set, a \l DragHandler
* will be installed on the resize handle which resizes the window by moving its top and left edges
@@ -789,7 +789,7 @@ void QWaylandQtShellChrome::setTopLeftResizeHandle(QQuickItem *item)
}
/*!
- * \qmlproperty Item QtWaylandCompositor::QtShellChrome::bottomLeftResizeHandle
+ * \qmlproperty Item QtShellChrome::bottomLeftResizeHandle
*
* This property holds the default bottom-left resize handle of the QtShellChrome. If set, a \l DragHandler
* will be installed on the resize handle which resizes the window by moving its bottom and left edges
@@ -846,7 +846,7 @@ void QWaylandQtShellChrome::setBottomLeftResizeHandle(QQuickItem *item)
}
/*!
- * \qmlproperty Item QtWaylandCompositor::QtShellChrome::topRightResizeHandle
+ * \qmlproperty Item QtShellChrome::topRightResizeHandle
*
* This property holds the default top-right resize handle of the QtShellChrome. If set, a \l DragHandler
* will be installed on the resize handle which resizes the window by moving its top and right edges
@@ -903,7 +903,7 @@ void QWaylandQtShellChrome::setTopRightResizeHandle(QQuickItem *item)
}
/*!
- * \qmlproperty Item QtWaylandCompositor::QtShellChrome::bottomRightResizeHandle
+ * \qmlproperty Item QtShellChrome::bottomRightResizeHandle
*
* This property holds the default bottom-right resize handle of the QtShellChrome. If set, a \l DragHandler
* will be installed on the resize handle which resizes the window by moving its bottom and right edges
@@ -960,7 +960,7 @@ void QWaylandQtShellChrome::setBottomRightResizeHandle(QQuickItem *item)
}
/*!
- * \qmlproperty rect QtWaylandCompositor::QtShellChrome::maximizedRect
+ * \qmlproperty rect QtShellChrome::maximizedRect
*
* This property holds the are of the WaylandOutput which is available to be filled by the
* window when it is in maximized state. By default, the window will fill the entire geometry
@@ -1161,7 +1161,7 @@ void QWaylandQtShellChrome::updateWindowFlags()
}
/*!
- * \qmlproperty int QtWaylandCompositor::QtShellChrome::windowFlags
+ * \qmlproperty int QtShellChrome::windowFlags
*
* This property holds the window flags of the QtShellChrome. They will match the \c windowFlags
* property of the associated QtShellSurface, except when this is equal to Qt.Window. In this case,
@@ -1175,7 +1175,7 @@ uint QWaylandQtShellChrome::currentWindowFlags() const
}
/*!
- * \qmlproperty int QtWaylandCompositor::QtShellChrome::windowState
+ * \qmlproperty int QtShellChrome::windowState
*
* This property holds the window state of the shell surface. It will be updated immediately when
* the window state is requested on the compositor-side, before this has been acknowledged by the
@@ -1200,7 +1200,7 @@ bool QWaylandQtShellChrome::hasTitleBar() const
}
/*!
- * \qmlproperty bool QtWaylandCompositor::QtShellChrome::hasDecorations
+ * \qmlproperty bool QtShellChrome::hasDecorations
*
* This property is true if the QtShellChrome's decorations should be visible, based on its window
* state and window flags.
@@ -1290,7 +1290,7 @@ void QWaylandQtShellChrome::updateAutomaticPosition()
}
/*!
- * \qmlmethod void QtWaylandCompositor::QtShellChrome::deactivate()
+ * \qmlmethod void QtShellChrome::deactivate()
*
* Manually deactivates this window. If the window was active, this will activate the next window in
* the stack instead.
@@ -1319,7 +1319,7 @@ void QWaylandQtShellChrome::activateOnGrab(QPointingDevice::GrabTransition trans
}
/*!
- * \qmlmethod void QtWaylandCompositor::QtShellChrome::activate()
+ * \qmlmethod void QtShellChrome::activate()
*
* Manually activate this window. This will also raise the window.
*
@@ -1334,7 +1334,7 @@ void QWaylandQtShellChrome::activate()
}
/*!
- * \qmlmethod void QtWaylandCompositor::QtShellChrome::raise()
+ * \qmlmethod void QtShellChrome::raise()
*
* Raise this window, so that it stacks on top of other windows (except if the other window's
* flags prohibit this.)
@@ -1347,7 +1347,7 @@ void QWaylandQtShellChrome::raise()
}
/*!
- * \qmlmethod void QtWaylandCompositor::QtShellChrome::lower()
+ * \qmlmethod void QtShellChrome::lower()
*
* Lower this window, so that it stacks underneath other windows (except if the other window's
* window flags prohibit this.)
@@ -1374,7 +1374,7 @@ void QWaylandQtShellChrome::updateActiveState()
}
/*!
- * \qmlproperty int QtWaylandCompositor::QtShellChrome::frameMarginLeft
+ * \qmlproperty int QtShellChrome::frameMarginLeft
*
* Sets the size of the left margin of the QtShellChrome which is reserved for window decorations.
* By default, this will equal the width of the \l leftResizeHandle if it is set. Otherwise it will
@@ -1405,7 +1405,7 @@ int QWaylandQtShellChrome::frameMarginLeft() const
}
/*!
- * \qmlproperty int QtWaylandCompositor::QtShellChrome::frameMarginRight
+ * \qmlproperty int QtShellChrome::frameMarginRight
*
* Sets the size of the right margin of the QtShellChrome which is reserved for window decorations.
* By default, this will equal the width of the \l rightResizeHandle if it is set. Otherwise it will
@@ -1436,7 +1436,7 @@ int QWaylandQtShellChrome::frameMarginRight() const
}
/*!
- * \qmlproperty int QtWaylandCompositor::QtShellChrome::frameMarginTop
+ * \qmlproperty int QtShellChrome::frameMarginTop
*
* Sets the size of the top margin of the QtShellChrome which is reserved for window decorations.
* By default, this will equal the sum of the \l leftResizeHandle and the \l{titleBar}'s heights,
@@ -1466,7 +1466,7 @@ int QWaylandQtShellChrome::frameMarginTop() const
}
/*!
- * \qmlproperty int QtWaylandCompositor::QtShellChrome::frameMarginBottom
+ * \qmlproperty int QtShellChrome::frameMarginBottom
*
* Sets the size of the bottom margin of the QtShellChrome which is reserved for window decorations.
* By default, this will equal the height of the \l bottomResizeHandle if it is set. Otherwise it will
diff --git a/src/imports/compositor-extensions/wlshell/CMakeLists.txt b/src/imports/compositor-extensions/wlshell/CMakeLists.txt
index b8c9586bb..0dd155e35 100644
--- a/src/imports/compositor-extensions/wlshell/CMakeLists.txt
+++ b/src/imports/compositor-extensions/wlshell/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from wlshell.pro.
#####################################################################
@@ -19,8 +22,11 @@ qt_internal_add_qml_module(WaylandCompositorWLShell
Qt::Core
Qt::Gui
Qt::WaylandCompositor
+ NO_GENERATE_CPP_EXPORTS
)
+qt_internal_add_autogen_sync_header_dependencies(WaylandCompositorWLShell WaylandCompositor)
+
#### Keys ignored in scope 1:.:.:wlshell.pro:<TRUE>:
# CXX_MODULE = "qml"
# QML_IMPORT_VERSION = "$$QT_VERSION"
diff --git a/src/imports/compositor-extensions/xdgshell/CMakeLists.txt b/src/imports/compositor-extensions/xdgshell/CMakeLists.txt
index 0ff0501f6..d5bfd9dd8 100644
--- a/src/imports/compositor-extensions/xdgshell/CMakeLists.txt
+++ b/src/imports/compositor-extensions/xdgshell/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from xdgshell.pro.
#####################################################################
@@ -19,8 +22,11 @@ qt_internal_add_qml_module(WaylandCompositorXdgShell
Qt::Core
Qt::Gui
Qt::WaylandCompositor
+ NO_GENERATE_CPP_EXPORTS
)
+qt_internal_add_autogen_sync_header_dependencies(WaylandCompositorXdgShell WaylandCompositor)
+
#### Keys ignored in scope 1:.:.:xdgshell.pro:<TRUE>:
# CXX_MODULE = "qml"
# QML_IMPORT_VERSION = "$$QT_VERSION"
diff --git a/src/imports/texture-sharing-extension/CMakeLists.txt b/src/imports/texture-sharing-extension/CMakeLists.txt
index 575f80a1e..564bb6402 100644
--- a/src/imports/texture-sharing-extension/CMakeLists.txt
+++ b/src/imports/texture-sharing-extension/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from texture-sharing-extension.pro.
#####################################################################
@@ -24,8 +27,10 @@ qt_internal_add_qml_module(WaylandTextureSharingExtension
Qt::QuickPrivate
Qt::WaylandCompositor
Qt::WaylandCompositorPrivate
+ NO_GENERATE_CPP_EXPORTS
)
+qt_internal_add_autogen_sync_header_dependencies(WaylandTextureSharingExtension WaylandCompositor)
#### Keys ignored in scope 1:.:.:texture-sharing-extension.pro:<TRUE>:
# CXX_MODULE = "qml"
# IMPORT_VERSION = "1.$$QT_MINOR_VERSION"
diff --git a/src/imports/texture-sharing/CMakeLists.txt b/src/imports/texture-sharing/CMakeLists.txt
index c3c8ca4c7..61d6690e6 100644
--- a/src/imports/texture-sharing/CMakeLists.txt
+++ b/src/imports/texture-sharing/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from texture-sharing.pro.
#####################################################################
@@ -27,6 +30,9 @@ qt_internal_add_qml_module(WaylandTextureSharing
Qt::QuickPrivate
Qt::WaylandClient
Qt::WaylandClientPrivate
+ PRIVATE_HEADER_FILTERS
+ "^qwayland-.*\.h|^wayland-.*-protocol\.h"
+ NO_GENERATE_CPP_EXPORTS
)
qt6_generate_wayland_protocol_client_sources(WaylandTextureSharing
@@ -34,6 +40,8 @@ qt6_generate_wayland_protocol_client_sources(WaylandTextureSharing
${CMAKE_CURRENT_SOURCE_DIR}/../../extensions/qt-texture-sharing-unstable-v1.xml
)
+qt_internal_add_autogen_sync_header_dependencies(WaylandTextureSharing WaylandCompositor)
+
#### Keys ignored in scope 1:.:.:texture-sharing.pro:<TRUE>:
# CXX_MODULE = "qml"
# IMPORT_VERSION = "1.$$QT_MINOR_VERSION"
diff --git a/src/imports/texture-sharing/sharedtextureprovider.cpp b/src/imports/texture-sharing/sharedtextureprovider.cpp
index c4561cff2..ded29b44e 100644
--- a/src/imports/texture-sharing/sharedtextureprovider.cpp
+++ b/src/imports/texture-sharing/sharedtextureprovider.cpp
@@ -19,6 +19,7 @@
#include <QOpenGLTexture>
#include <QImageReader>
+#include <QtCore/qpointer.h>
#include <QTimer>
#include "texturesharingextension_p.h"
@@ -206,7 +207,7 @@ public:
}
-public slots:
+public Q_SLOTS:
void doResponse(const QString &key) {
if (key != m_id)
return; // not our buffer
diff --git a/src/imports/texture-sharing/sharedtextureprovider_p.h b/src/imports/texture-sharing/sharedtextureprovider_p.h
index 8a4fcea23..aac772619 100644
--- a/src/imports/texture-sharing/sharedtextureprovider_p.h
+++ b/src/imports/texture-sharing/sharedtextureprovider_p.h
@@ -40,13 +40,13 @@ public:
static bool preinitialize();
-public slots:
+public Q_SLOTS:
void receiveBuffer(QtWaylandClient::QWaylandServerBuffer *buffer, const QString &id);
-signals:
+Q_SIGNALS:
void replyReceived(const QString &id);
-private slots:
+private Q_SLOTS:
void handleExtensionActive();
private:
diff --git a/src/imports/texture-sharing/texturesharingextension_p.h b/src/imports/texture-sharing/texturesharingextension_p.h
index a7584c097..4a00de8eb 100644
--- a/src/imports/texture-sharing/texturesharingextension_p.h
+++ b/src/imports/texture-sharing/texturesharingextension_p.h
@@ -35,11 +35,11 @@ class TextureSharingExtension : public QWaylandClientExtensionTemplate<TextureSh
public:
TextureSharingExtension();
-public slots:
+public Q_SLOTS:
void requestImage(const QString &key);
void abandonImage(const QString &key);
-signals:
+Q_SIGNALS:
void bufferReceived(QtWaylandClient::QWaylandServerBuffer *buffer, const QString &key);
private:
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt
index ef58376ae..e0c91c5e4 100644
--- a/src/plugins/CMakeLists.txt
+++ b/src/plugins/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from plugins.pro.
add_subdirectory(hardwareintegration)
diff --git a/src/plugins/decorations/CMakeLists.txt b/src/plugins/decorations/CMakeLists.txt
index fd7fbeb20..abe3c375b 100644
--- a/src/plugins/decorations/CMakeLists.txt
+++ b/src/plugins/decorations/CMakeLists.txt
@@ -1,3 +1,9 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from decorations.pro.
+if (QT_FEATURE_wayland_decoration_adwaita)
+ add_subdirectory(adwaita)
+endif()
add_subdirectory(bradient)
diff --git a/src/plugins/decorations/adwaita/CMakeLists.txt b/src/plugins/decorations/adwaita/CMakeLists.txt
new file mode 100644
index 000000000..b318c2b8b
--- /dev/null
+++ b/src/plugins/decorations/adwaita/CMakeLists.txt
@@ -0,0 +1,25 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## QWaylandAdwaitaDecorationPlugin Plugin:
+#####################################################################
+
+qt_internal_add_plugin(QWaylandAdwaitaDecorationPlugin
+ OUTPUT_NAME adwaita
+ PLUGIN_TYPE wayland-decoration-client
+ SOURCES
+ main.cpp
+ qwaylandadwaitadecoration.cpp
+ LIBRARIES
+ Qt::Core
+ Qt::DBus
+ Qt::Gui
+ Qt::Svg
+ Qt::WaylandClientPrivate
+ Wayland::Client
+)
+
+#### Keys ignored in scope 1:.:.:bradient.pro:<TRUE>:
+# OTHER_FILES = "bradient.json"
+
diff --git a/src/plugins/decorations/adwaita/adwaita.json b/src/plugins/decorations/adwaita/adwaita.json
new file mode 100644
index 000000000..69ec79e9b
--- /dev/null
+++ b/src/plugins/decorations/adwaita/adwaita.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "adwaita", "gnome" ]
+}
diff --git a/src/plugins/decorations/adwaita/main.cpp b/src/plugins/decorations/adwaita/main.cpp
new file mode 100644
index 000000000..e5b1be830
--- /dev/null
+++ b/src/plugins/decorations/adwaita/main.cpp
@@ -0,0 +1,36 @@
+// Copyright (C) 2023 Jan Grulich <jgrulich@redhat.com>
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtWaylandClient/private/qwaylanddecorationplugin_p.h>
+
+#include "qwaylandadwaitadecoration_p.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+namespace QtWaylandClient {
+
+class QWaylandAdwaitaDecorationPlugin : public QWaylandDecorationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QWaylandDecorationFactoryInterface_iid FILE "adwaita.json")
+public:
+ QWaylandAbstractDecoration *create(const QString &key, const QStringList &params) override;
+};
+
+QWaylandAbstractDecoration *QWaylandAdwaitaDecorationPlugin::create(const QString &key, const QStringList &params)
+{
+ Q_UNUSED(params);
+ if (!key.compare("adwaita"_L1, Qt::CaseInsensitive) ||
+ !key.compare("gnome"_L1, Qt::CaseInsensitive))
+ return new QWaylandAdwaitaDecoration();
+ return nullptr;
+}
+
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/decorations/adwaita/qwaylandadwaitadecoration.cpp b/src/plugins/decorations/adwaita/qwaylandadwaitadecoration.cpp
new file mode 100644
index 000000000..2d3575bce
--- /dev/null
+++ b/src/plugins/decorations/adwaita/qwaylandadwaitadecoration.cpp
@@ -0,0 +1,731 @@
+// Copyright (C) 2023 Jan Grulich <jgrulich@redhat.com>
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwaylandadwaitadecoration_p.h"
+
+// QtCore
+#include <QtCore/QLoggingCategory>
+#include <QScopeGuard>
+
+// QtDBus
+#include <QtDBus/QDBusArgument>
+#include <QtDBus/QDBusConnection>
+#include <QtDBus/QDBusMessage>
+#include <QtDBus/QDBusPendingCall>
+#include <QtDBus/QDBusPendingCallWatcher>
+#include <QtDBus/QDBusPendingReply>
+#include <QtDBus/QDBusVariant>
+#include <QtDBus/QtDBus>
+
+// QtGui
+#include <QtGui/QColor>
+#include <QtGui/QPainter>
+#include <QtGui/QPainterPath>
+
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/qpa/qplatformtheme.h>
+
+// QtSvg
+#include <QtSvg/QSvgRenderer>
+
+// QtWayland
+#include <QtWaylandClient/private/qwaylandshmbackingstore_p.h>
+#include <QtWaylandClient/private/qwaylandwindow_p.h>
+
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+namespace QtWaylandClient {
+
+static constexpr int ceButtonSpacing = 12;
+static constexpr int ceButtonWidth = 24;
+static constexpr int ceCornerRadius = 12;
+static constexpr int ceShadowsWidth = 10;
+static constexpr int ceTitlebarHeight = 38;
+static constexpr int ceWindowBorderWidth = 1;
+static constexpr qreal ceTitlebarSeperatorWidth = 0.5;
+
+static QMap<QWaylandAdwaitaDecoration::ButtonIcon, QString> buttonMap = {
+ { QWaylandAdwaitaDecoration::CloseIcon, "window-close-symbolic"_L1 },
+ { QWaylandAdwaitaDecoration::MinimizeIcon, "window-minimize-symbolic"_L1 },
+ { QWaylandAdwaitaDecoration::MaximizeIcon, "window-maximize-symbolic"_L1 },
+ { QWaylandAdwaitaDecoration::RestoreIcon, "window-restore-symbolic"_L1 }
+};
+
+const QDBusArgument &operator>>(const QDBusArgument &argument, QMap<QString, QVariantMap> &map)
+{
+ argument.beginMap();
+ map.clear();
+
+ while (!argument.atEnd()) {
+ QString key;
+ QVariantMap value;
+ argument.beginMapEntry();
+ argument >> key >> value;
+ argument.endMapEntry();
+ map.insert(key, value);
+ }
+
+ argument.endMap();
+ return argument;
+}
+
+Q_LOGGING_CATEGORY(lcQWaylandAdwaitaDecorationLog, "qt.qpa.qwaylandadwaitadecoration", QtWarningMsg)
+
+QWaylandAdwaitaDecoration::QWaylandAdwaitaDecoration()
+ : QWaylandAbstractDecoration()
+{
+ m_lastButtonClick = QDateTime::currentDateTime();
+
+ QTextOption option(Qt::AlignHCenter | Qt::AlignVCenter);
+ option.setWrapMode(QTextOption::NoWrap);
+ m_windowTitle.setTextOption(option);
+ m_windowTitle.setTextFormat(Qt::PlainText);
+
+ const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
+ if (const QFont *font = theme->font(QPlatformTheme::TitleBarFont))
+ m_font = std::make_unique<QFont>(*font);
+ if (!m_font) // Fallback to GNOME's default font
+ m_font = std::make_unique<QFont>("Cantarell"_L1, 10);
+
+ QTimer::singleShot(0, this, &QWaylandAdwaitaDecoration::loadConfiguration);
+}
+
+QMargins QWaylandAdwaitaDecoration::margins(QWaylandAbstractDecoration::MarginsType marginsType) const
+{
+ const bool onlyShadows = marginsType == QWaylandAbstractDecoration::ShadowsOnly;
+ const bool shadowsExcluded = marginsType == ShadowsExcluded;
+
+ if (waylandWindow()->windowStates() & Qt::WindowMaximized) {
+ // Maximized windows don't have anything around, no shadows, border,
+ // etc. Only report titlebar height in case we are not asking for shadow
+ // margins.
+ return QMargins(0, onlyShadows ? 0 : ceTitlebarHeight, 0, 0);
+ }
+
+ const QWaylandWindow::ToplevelWindowTilingStates tilingStates = waylandWindow()->toplevelWindowTilingStates();
+
+ // Since all sides (left, right, bottom) are going to be same
+ const int marginsBase = shadowsExcluded ? ceWindowBorderWidth : ceShadowsWidth + ceWindowBorderWidth;
+ const int sideMargins = onlyShadows ? ceShadowsWidth : marginsBase;
+ const int topMargins = onlyShadows ? ceShadowsWidth : ceTitlebarHeight + marginsBase;
+
+ return QMargins(tilingStates & QWaylandWindow::WindowTiledLeft ? 0 : sideMargins,
+ tilingStates & QWaylandWindow::WindowTiledTop ? onlyShadows ? 0 : ceTitlebarHeight : topMargins,
+ tilingStates & QWaylandWindow::WindowTiledRight ? 0 : sideMargins,
+ tilingStates & QWaylandWindow::WindowTiledBottom ? 0 : sideMargins);
+}
+
+void QWaylandAdwaitaDecoration::paint(QPaintDevice *device)
+{
+ const QRect surfaceRect = waylandWindow()->windowContentGeometry() + margins(ShadowsOnly);
+
+ QPainter p(device);
+ p.setRenderHint(QPainter::Antialiasing);
+
+ /*
+ * Titlebar and window border
+ */
+ const int titleBarWidth = surfaceRect.width() - margins().left() - margins().right();
+ QPainterPath path;
+
+ // Maximized or tiled won't have rounded corners
+ if (waylandWindow()->windowStates() & Qt::WindowMaximized
+ || waylandWindow()->toplevelWindowTilingStates() != QWaylandWindow::WindowNoState)
+ path.addRect(margins().left(), margins().bottom(), titleBarWidth, margins().top());
+ else
+ path.addRoundedRect(margins().left(), margins().bottom(), titleBarWidth,
+ margins().top() + ceCornerRadius, ceCornerRadius, ceCornerRadius);
+
+ p.save();
+ p.setPen(color(Border));
+ p.fillPath(path.simplified(), color(Background));
+ p.drawPath(path);
+ p.drawRect(margins().left(), margins().top(), titleBarWidth, surfaceRect.height() - margins().top() - margins().bottom());
+ p.restore();
+
+
+ /*
+ * Titlebar separator
+ */
+ p.save();
+ p.setPen(color(Border));
+ p.drawLine(QLineF(margins().left(), margins().top() - ceTitlebarSeperatorWidth,
+ surfaceRect.width() - margins().right(),
+ margins().top() - ceTitlebarSeperatorWidth));
+ p.restore();
+
+
+ /*
+ * Window title
+ */
+ const QRect top = QRect(margins().left(), margins().bottom(), surfaceRect.width(),
+ margins().top() - margins().bottom());
+ const QString windowTitleText = waylandWindow()->windowTitle();
+ if (!windowTitleText.isEmpty()) {
+ if (m_windowTitle.text() != windowTitleText) {
+ m_windowTitle.setText(windowTitleText);
+ m_windowTitle.prepare();
+ }
+
+ QRect titleBar = top;
+ if (m_placement == Right) {
+ titleBar.setLeft(margins().left());
+ titleBar.setRight(static_cast<int>(buttonRect(Minimize).left()) - 8);
+ } else {
+ titleBar.setLeft(static_cast<int>(buttonRect(Minimize).right()) + 8);
+ titleBar.setRight(surfaceRect.width() - margins().right());
+ }
+
+ p.save();
+ p.setClipRect(titleBar);
+ p.setPen(color(Foreground));
+ QSize size = m_windowTitle.size().toSize();
+ int dx = (top.width() - size.width()) / 2;
+ int dy = (top.height() - size.height()) / 2;
+ p.setFont(*m_font);
+ QPoint windowTitlePoint(top.topLeft().x() + dx, top.topLeft().y() + dy);
+ p.drawStaticText(windowTitlePoint, m_windowTitle);
+ p.restore();
+ }
+
+
+ /*
+ * Buttons
+ */
+ if (m_buttons.contains(Close))
+ drawButton(Close, &p);
+
+ if (m_buttons.contains(Maximize))
+ drawButton(Maximize, &p);
+
+ if (m_buttons.contains(Minimize))
+ drawButton(Minimize, &p);
+}
+
+bool QWaylandAdwaitaDecoration::handleMouse(QWaylandInputDevice *inputDevice, const QPointF &local,
+ const QPointF &global, Qt::MouseButtons b,
+ Qt::KeyboardModifiers mods)
+{
+ Q_UNUSED(global)
+
+ if (local.y() > margins().top())
+ updateButtonHoverState(Button::None);
+
+ // Figure out what area mouse is in
+ QRect surfaceRect = waylandWindow()->windowContentGeometry() + margins(ShadowsOnly);
+ if (local.y() <= surfaceRect.top() + margins().top())
+ processMouseTop(inputDevice, local, b, mods);
+ else if (local.y() > surfaceRect.bottom() - margins().bottom())
+ processMouseBottom(inputDevice, local, b, mods);
+ else if (local.x() <= surfaceRect.left() + margins().left())
+ processMouseLeft(inputDevice, local, b, mods);
+ else if (local.x() > surfaceRect.right() - margins().right())
+ processMouseRight(inputDevice, local, b, mods);
+ else {
+#if QT_CONFIG(cursor)
+ waylandWindow()->restoreMouseCursor(inputDevice);
+#endif
+ }
+
+ // Reset clicking state in case a button press is released outside
+ // the button area
+ if (isLeftReleased(b)) {
+ m_clicking = None;
+ requestRepaint();
+ }
+
+ setMouseButtons(b);
+ return false;
+}
+
+bool QWaylandAdwaitaDecoration::handleTouch(QWaylandInputDevice *inputDevice, const QPointF &local,
+ const QPointF &global, QEventPoint::State state,
+ Qt::KeyboardModifiers mods)
+{
+ Q_UNUSED(inputDevice)
+ Q_UNUSED(global)
+ Q_UNUSED(mods)
+
+ bool handled = state == QEventPoint::Pressed;
+
+ if (handled) {
+ if (buttonRect(Close).contains(local))
+ QWindowSystemInterface::handleCloseEvent(window());
+ else if (m_buttons.contains(Maximize) && buttonRect(Maximize).contains(local))
+ window()->setWindowStates(window()->windowStates() ^ Qt::WindowMaximized);
+ else if (m_buttons.contains(Minimize) && buttonRect(Minimize).contains(local))
+ window()->setWindowState(Qt::WindowMinimized);
+ else if (local.y() <= margins().top())
+ waylandWindow()->shellSurface()->move(inputDevice);
+ else
+ handled = false;
+ }
+
+ return handled;
+}
+
+QString getIconSvg(const QString &iconName)
+{
+ const QStringList themeNames = { QIcon::themeName(), QIcon::fallbackThemeName(), "Adwaita"_L1 };
+
+ qCDebug(lcQWaylandAdwaitaDecorationLog) << "Searched icon themes: " << themeNames;
+
+ for (const QString &themeName : themeNames) {
+ if (themeName.isEmpty())
+ continue;
+
+ for (const QString &path : QIcon::themeSearchPaths()) {
+ if (path.startsWith(QLatin1Char(':')))
+ continue;
+
+ const QString fullPath = QString("%1/%2").arg(path).arg(themeName);
+ QDirIterator dirIt(fullPath, {"*.svg"}, QDir::Files, QDirIterator::Subdirectories);
+ while (dirIt.hasNext()) {
+ const QString fileName = dirIt.next();
+ const QFileInfo fileInfo(fileName);
+
+ if (fileInfo.fileName() == iconName) {
+ qCDebug(lcQWaylandAdwaitaDecorationLog) << "Using " << iconName << " from " << themeName << " theme";
+ QFile readFile(fileInfo.filePath());
+ readFile.open(QFile::ReadOnly);
+ return readFile.readAll();
+ }
+ }
+ }
+ }
+
+ qCWarning(lcQWaylandAdwaitaDecorationLog) << "Failed to find an svg icon for " << iconName;
+
+ return QString();
+}
+
+void QWaylandAdwaitaDecoration::loadConfiguration()
+{
+ qRegisterMetaType<QDBusVariant>();
+ qDBusRegisterMetaType<QMap<QString, QVariantMap>>();
+
+ QDBusConnection connection = QDBusConnection::sessionBus();
+
+ QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.portal.Desktop"_L1,
+ "/org/freedesktop/portal/desktop"_L1,
+ "org.freedesktop.portal.Settings"_L1,
+ "ReadAll"_L1);
+ message << QStringList{ { "org.gnome.desktop.wm.preferences"_L1 },
+ { "org.freedesktop.appearance"_L1 } };
+
+ QDBusPendingCall pendingCall = connection.asyncCall(message);
+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall, this);
+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) {
+ QDBusPendingReply<QMap<QString, QVariantMap>> reply = *watcher;
+ if (reply.isValid()) {
+ QMap<QString, QVariantMap> settings = reply.value();
+ if (!settings.isEmpty()) {
+ const uint colorScheme = settings.value("org.freedesktop.appearance"_L1).value("color-scheme"_L1).toUInt();
+ updateColors(colorScheme == 1); // 1 == Prefer Dark
+ const QString buttonLayout = settings.value("org.gnome.desktop.wm.preferences"_L1).value("button-layout"_L1).toString();
+ if (!buttonLayout.isEmpty())
+ updateTitlebarLayout(buttonLayout);
+ // Workaround for QGtkStyle not having correct titlebar font
+ const QString titlebarFont =
+ settings.value("org.gnome.desktop.wm.preferences"_L1).value("titlebar-font"_L1).toString();
+ if (titlebarFont.contains("bold"_L1, Qt::CaseInsensitive)) {
+ m_font->setBold(true);
+ }
+ }
+ }
+ watcher->deleteLater();
+ });
+
+ QDBusConnection::sessionBus().connect(QString(), "/org/freedesktop/portal/desktop"_L1,
+ "org.freedesktop.portal.Settings"_L1, "SettingChanged"_L1, this,
+ SLOT(settingChanged(QString, QString, QDBusVariant)));
+
+ // Load SVG icons
+ for (auto mapIt = buttonMap.constBegin(); mapIt != buttonMap.constEnd(); mapIt++) {
+ const QString fullName = mapIt.value() + QStringLiteral(".svg");
+ m_icons[mapIt.key()] = getIconSvg(fullName);
+ }
+
+ updateColors(false);
+}
+
+void QWaylandAdwaitaDecoration::updateColors(bool isDark)
+{
+ qCDebug(lcQWaylandAdwaitaDecorationLog) << "Color scheme changed to: " << (isDark ? "dark" : "light");
+
+ m_colors = { { Background, isDark ? QColor(0x303030) : QColor(0xffffff) },
+ { BackgroundInactive, isDark ? QColor(0x242424) : QColor(0xfafafa) },
+ { Foreground, isDark ? QColor(0xffffff) : QColor(0x2e2e2e) },
+ { ForegroundInactive, isDark ? QColor(0x919191) : QColor(0x949494) },
+ { Border, isDark ? QColor(0x3b3b3b) : QColor(0xdbdbdb) },
+ { BorderInactive, isDark ? QColor(0x303030) : QColor(0xdbdbdb) },
+ { ButtonBackground, isDark ? QColor(0x444444) : QColor(0xebebeb) },
+ { ButtonBackgroundInactive, isDark ? QColor(0x2e2e2e) : QColor(0xf0f0f0) },
+ { HoveredButtonBackground, isDark ? QColor(0x4f4f4f) : QColor(0xe0e0e0) },
+ { PressedButtonBackground, isDark ? QColor(0x6e6e6e) : QColor(0xc2c2c2) } };
+ requestRepaint();
+}
+
+void QWaylandAdwaitaDecoration::updateTitlebarLayout(const QString &layout)
+{
+ const QStringList layouts = layout.split(QLatin1Char(':'));
+ if (layouts.count() != 2)
+ return;
+
+ // Remove previous configuration
+ m_buttons.clear();
+
+ const QString &leftLayout = layouts.at(0);
+ const QString &rightLayout = layouts.at(1);
+ m_placement = leftLayout.contains("close"_L1) ? Left : Right;
+
+ int pos = 1;
+ const QString &buttonLayout = m_placement == Right ? rightLayout : leftLayout;
+
+ QStringList buttonList = buttonLayout.split(QLatin1Char(','));
+ if (m_placement == Right)
+ std::reverse(buttonList.begin(), buttonList.end());
+
+ for (const QString &button : buttonList) {
+ if (button == "close"_L1)
+ m_buttons.insert(Close, pos);
+ else if (button == "maximize"_L1)
+ m_buttons.insert(Maximize, pos);
+ else if (button == "minimize"_L1)
+ m_buttons.insert(Minimize, pos);
+
+ pos++;
+ }
+
+ qCDebug(lcQWaylandAdwaitaDecorationLog) << "Button layout changed to: " << layout;
+
+ requestRepaint();
+}
+
+void QWaylandAdwaitaDecoration::settingChanged(const QString &group, const QString &key,
+ const QDBusVariant &value)
+{
+ if (group == "org.gnome.desktop.wm.preferences"_L1 && key == "button-layout"_L1) {
+ const QString layout = value.variant().toString();
+ updateTitlebarLayout(layout);
+ } else if (group == "org.freedesktop.appearance"_L1 && key == "color-scheme"_L1) {
+ const uint colorScheme = value.variant().toUInt();
+ updateColors(colorScheme == 1); // 1 == Prefer Dark
+ }
+}
+
+QRectF QWaylandAdwaitaDecoration::buttonRect(Button button) const
+{
+ int xPos;
+ int yPos;
+ const int btnPos = m_buttons.value(button);
+
+ const QRect surfaceRect = waylandWindow()->windowContentGeometry() + margins(QWaylandAbstractDecoration::ShadowsOnly);
+ if (m_placement == Right) {
+ xPos = surfaceRect.width();
+ xPos -= ceButtonWidth * btnPos;
+ xPos -= ceButtonSpacing * btnPos;
+ xPos -= margins(ShadowsOnly).right();
+ } else {
+ xPos = 0;
+ xPos += ceButtonWidth * btnPos;
+ xPos += ceButtonSpacing * btnPos;
+ xPos += margins(ShadowsOnly).left();
+ // We are painting from the left to the right so the real
+ // position doesn't need to by moved by the size of the button.
+ xPos -= ceButtonWidth;
+ }
+
+ yPos = margins().top();
+ yPos += margins().bottom();
+ yPos -= ceButtonWidth;
+ yPos /= 2;
+
+ return QRectF(xPos, yPos, ceButtonWidth, ceButtonWidth);
+}
+
+static void renderFlatRoundedButtonFrame(QPainter *painter, const QRect &rect, const QColor &color)
+{
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing, true);
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(color);
+ painter->drawEllipse(rect);
+ painter->restore();
+}
+
+static void renderButtonIcon(const QString &svgIcon, QPainter *painter, const QRect &rect, const QColor &color)
+{
+ painter->save();
+ painter->setRenderHints(QPainter::Antialiasing, true);
+
+ QString icon = svgIcon;
+ QRegularExpression regexp("fill=[\"']#[0-9A-F]{6}[\"']", QRegularExpression::CaseInsensitiveOption);
+ QRegularExpression regexpAlt("fill:#[0-9A-F]{6}", QRegularExpression::CaseInsensitiveOption);
+ QRegularExpression regexpCurrentColor("fill=[\"']currentColor[\"']");
+ icon.replace(regexp, QString("fill=\"%1\"").arg(color.name()));
+ icon.replace(regexpAlt, QString("fill:%1").arg(color.name()));
+ icon.replace(regexpCurrentColor, QString("fill=\"%1\"").arg(color.name()));
+ QSvgRenderer svgRenderer(icon.toLocal8Bit());
+ svgRenderer.render(painter, rect);
+
+ painter->restore();
+}
+
+static void renderButtonIcon(QWaylandAdwaitaDecoration::ButtonIcon buttonIcon, QPainter *painter, const QRect &rect)
+{
+ QString iconName = buttonMap[buttonIcon];
+
+ painter->save();
+ painter->setRenderHints(QPainter::Antialiasing, true);
+ painter->drawPixmap(rect, QIcon::fromTheme(iconName).pixmap(ceButtonWidth, ceButtonWidth));
+ painter->restore();
+}
+
+static QWaylandAdwaitaDecoration::ButtonIcon iconFromButtonAndState(QWaylandAdwaitaDecoration::Button button, bool maximized)
+{
+ if (button == QWaylandAdwaitaDecoration::Close)
+ return QWaylandAdwaitaDecoration::CloseIcon;
+ else if (button == QWaylandAdwaitaDecoration::Minimize)
+ return QWaylandAdwaitaDecoration::MinimizeIcon;
+ else if (button == QWaylandAdwaitaDecoration::Maximize && maximized)
+ return QWaylandAdwaitaDecoration::RestoreIcon;
+ else
+ return QWaylandAdwaitaDecoration::MaximizeIcon;
+}
+
+void QWaylandAdwaitaDecoration::drawButton(Button button, QPainter *painter)
+{
+ const Qt::WindowStates windowStates = waylandWindow()->windowStates();
+ const bool maximized = windowStates & Qt::WindowMaximized;
+
+ const QRect btnRect = buttonRect(button).toRect();
+ renderFlatRoundedButtonFrame(painter, btnRect, color(ButtonBackground, button));
+
+ QRect adjustedBtnRect = btnRect;
+ adjustedBtnRect.setSize(QSize(16, 16));
+ adjustedBtnRect.translate(4, 4);
+ const QString svgIcon = m_icons[iconFromButtonAndState(button, maximized)];
+ if (!svgIcon.isEmpty())
+ renderButtonIcon(svgIcon, painter, adjustedBtnRect, color(Foreground));
+ else // Fallback to use QIcon
+ renderButtonIcon(iconFromButtonAndState(button, maximized), painter, adjustedBtnRect);
+}
+
+QColor QWaylandAdwaitaDecoration::color(ColorType type, Button button)
+{
+ const bool active = waylandWindow()->windowStates() & Qt::WindowActive;
+
+ switch (type) {
+ case Background:
+ case BackgroundInactive:
+ return active ? m_colors[Background] : m_colors[BackgroundInactive];
+ case Foreground:
+ case ForegroundInactive:
+ return active ? m_colors[Foreground] : m_colors[ForegroundInactive];
+ case Border:
+ case BorderInactive:
+ return active ? m_colors[Border] : m_colors[BorderInactive];
+ case ButtonBackground:
+ case ButtonBackgroundInactive:
+ case HoveredButtonBackground: {
+ if (m_clicking == button) {
+ return m_colors[PressedButtonBackground];
+ } else if (m_hoveredButtons.testFlag(button)) {
+ return m_colors[HoveredButtonBackground];
+ }
+ return active ? m_colors[ButtonBackground] : m_colors[ButtonBackgroundInactive];
+ }
+ default:
+ return m_colors[Background];
+ }
+}
+
+bool QWaylandAdwaitaDecoration::clickButton(Qt::MouseButtons b, Button btn)
+{
+ auto repaint = qScopeGuard([this] { requestRepaint(); });
+
+ if (isLeftClicked(b)) {
+ m_clicking = btn;
+ return false;
+ } else if (isLeftReleased(b)) {
+ if (m_clicking == btn) {
+ m_clicking = None;
+ return true;
+ } else {
+ m_clicking = None;
+ }
+ }
+ return false;
+}
+
+bool QWaylandAdwaitaDecoration::doubleClickButton(Qt::MouseButtons b, const QPointF &local,
+ const QDateTime &currentTime)
+{
+ if (isLeftClicked(b)) {
+ const qint64 clickInterval = m_lastButtonClick.msecsTo(currentTime);
+ m_lastButtonClick = currentTime;
+ const int doubleClickDistance = 5;
+ const QPointF posDiff = m_lastButtonClickPosition - local;
+ if ((clickInterval <= 500)
+ && ((posDiff.x() <= doubleClickDistance && posDiff.x() >= -doubleClickDistance)
+ && ((posDiff.y() <= doubleClickDistance && posDiff.y() >= -doubleClickDistance)))) {
+ return true;
+ }
+
+ m_lastButtonClickPosition = local;
+ }
+
+ return false;
+}
+
+void QWaylandAdwaitaDecoration::updateButtonHoverState(Button hoveredButton)
+{
+ bool currentCloseButtonState = m_hoveredButtons.testFlag(Close);
+ bool currentMaximizeButtonState = m_hoveredButtons.testFlag(Maximize);
+ bool currentMinimizeButtonState = m_hoveredButtons.testFlag(Minimize);
+
+ m_hoveredButtons.setFlag(Close, hoveredButton == Button::Close);
+ m_hoveredButtons.setFlag(Maximize, hoveredButton == Button::Maximize);
+ m_hoveredButtons.setFlag(Minimize, hoveredButton == Button::Minimize);
+
+ if (m_hoveredButtons.testFlag(Close) != currentCloseButtonState
+ || m_hoveredButtons.testFlag(Maximize) != currentMaximizeButtonState
+ || m_hoveredButtons.testFlag(Minimize) != currentMinimizeButtonState) {
+ requestRepaint();
+ }
+}
+
+void QWaylandAdwaitaDecoration::processMouseTop(QWaylandInputDevice *inputDevice, const QPointF &local,
+ Qt::MouseButtons b, Qt::KeyboardModifiers mods)
+{
+ Q_UNUSED(mods)
+
+ QDateTime currentDateTime = QDateTime::currentDateTime();
+ QRect surfaceRect = waylandWindow()->windowContentGeometry() + margins(ShadowsOnly);
+
+ if (!buttonRect(Close).contains(local) && !buttonRect(Maximize).contains(local)
+ && !buttonRect(Minimize).contains(local))
+ updateButtonHoverState(Button::None);
+
+ if (local.y() <= surfaceRect.top() + margins().bottom()) {
+ if (local.x() <= margins().left()) {
+ // top left bit
+#if QT_CONFIG(cursor)
+ waylandWindow()->setMouseCursor(inputDevice, Qt::SizeFDiagCursor);
+#endif
+ startResize(inputDevice, Qt::TopEdge | Qt::LeftEdge, b);
+ } else if (local.x() > surfaceRect.right() - margins().left()) {
+ // top right bit
+#if QT_CONFIG(cursor)
+ waylandWindow()->setMouseCursor(inputDevice, Qt::SizeBDiagCursor);
+#endif
+ startResize(inputDevice, Qt::TopEdge | Qt::RightEdge, b);
+ } else {
+ // top resize bit
+#if QT_CONFIG(cursor)
+ waylandWindow()->setMouseCursor(inputDevice, Qt::SizeVerCursor);
+#endif
+ startResize(inputDevice, Qt::TopEdge, b);
+ }
+ } else if (local.x() <= surfaceRect.left() + margins().left()) {
+ processMouseLeft(inputDevice, local, b, mods);
+ } else if (local.x() > surfaceRect.right() - margins().right()) {
+ processMouseRight(inputDevice, local, b, mods);
+ } else if (buttonRect(Close).contains(local)) {
+ if (clickButton(b, Close)) {
+ QWindowSystemInterface::handleCloseEvent(window());
+ m_hoveredButtons.setFlag(Close, false);
+ }
+ updateButtonHoverState(Close);
+ } else if (m_buttons.contains(Maximize) && buttonRect(Maximize).contains(local)) {
+ updateButtonHoverState(Maximize);
+ if (clickButton(b, Maximize)) {
+ window()->setWindowStates(window()->windowStates() ^ Qt::WindowMaximized);
+ m_hoveredButtons.setFlag(Maximize, false);
+ }
+ } else if (m_buttons.contains(Minimize) && buttonRect(Minimize).contains(local)) {
+ updateButtonHoverState(Minimize);
+ if (clickButton(b, Minimize)) {
+ window()->setWindowState(Qt::WindowMinimized);
+ m_hoveredButtons.setFlag(Minimize, false);
+ }
+ } else if (doubleClickButton(b, local, currentDateTime)) {
+ window()->setWindowStates(window()->windowStates() ^ Qt::WindowMaximized);
+ } else {
+ // Show window menu
+ if (b == Qt::MouseButton::RightButton)
+ waylandWindow()->shellSurface()->showWindowMenu(inputDevice);
+#if QT_CONFIG(cursor)
+ waylandWindow()->restoreMouseCursor(inputDevice);
+#endif
+ startMove(inputDevice, b);
+ }
+}
+
+void QWaylandAdwaitaDecoration::processMouseBottom(QWaylandInputDevice *inputDevice, const QPointF &local,
+ Qt::MouseButtons b, Qt::KeyboardModifiers mods)
+{
+ Q_UNUSED(mods)
+ if (local.x() <= margins().left()) {
+ // bottom left bit
+#if QT_CONFIG(cursor)
+ waylandWindow()->setMouseCursor(inputDevice, Qt::SizeBDiagCursor);
+#endif
+ startResize(inputDevice, Qt::BottomEdge | Qt::LeftEdge, b);
+ } else if (local.x() > window()->width() + margins().right()) {
+ // bottom right bit
+#if QT_CONFIG(cursor)
+ waylandWindow()->setMouseCursor(inputDevice, Qt::SizeFDiagCursor);
+#endif
+ startResize(inputDevice, Qt::BottomEdge | Qt::RightEdge, b);
+ } else {
+ // bottom bit
+#if QT_CONFIG(cursor)
+ waylandWindow()->setMouseCursor(inputDevice, Qt::SizeVerCursor);
+#endif
+ startResize(inputDevice, Qt::BottomEdge, b);
+ }
+}
+
+void QWaylandAdwaitaDecoration::processMouseLeft(QWaylandInputDevice *inputDevice, const QPointF &local,
+ Qt::MouseButtons b, Qt::KeyboardModifiers mods)
+{
+ Q_UNUSED(local)
+ Q_UNUSED(mods)
+#if QT_CONFIG(cursor)
+ waylandWindow()->setMouseCursor(inputDevice, Qt::SizeHorCursor);
+#endif
+ startResize(inputDevice, Qt::LeftEdge, b);
+}
+
+void QWaylandAdwaitaDecoration::processMouseRight(QWaylandInputDevice *inputDevice, const QPointF &local,
+ Qt::MouseButtons b, Qt::KeyboardModifiers mods)
+{
+ Q_UNUSED(local)
+ Q_UNUSED(mods)
+#if QT_CONFIG(cursor)
+ waylandWindow()->setMouseCursor(inputDevice, Qt::SizeHorCursor);
+#endif
+ startResize(inputDevice, Qt::RightEdge, b);
+}
+
+void QWaylandAdwaitaDecoration::requestRepaint() const
+{
+ // Set dirty flag
+ if (waylandWindow()->decoration())
+ waylandWindow()->decoration()->update();
+
+ // Request re-paint
+ waylandWindow()->window()->requestUpdate();
+}
+
+} // namespace QtWaylandClient
+
+QT_END_NAMESPACE
+
+#include "moc_qwaylandadwaitadecoration_p.cpp"
diff --git a/src/plugins/decorations/adwaita/qwaylandadwaitadecoration_p.h b/src/plugins/decorations/adwaita/qwaylandadwaitadecoration_p.h
new file mode 100644
index 000000000..34874e088
--- /dev/null
+++ b/src/plugins/decorations/adwaita/qwaylandadwaitadecoration_p.h
@@ -0,0 +1,155 @@
+// Copyright (C) 2023 Jan Grulich <jgrulich@redhat.com>
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWAYLANDADWAITADECORATION_P_H
+#define QWAYLANDADWAITADECORATION_P_H
+
+#include <QtWaylandClient/private/qwaylandabstractdecoration_p.h>
+
+#include <QtCore/QDateTime>
+
+QT_BEGIN_NAMESPACE
+
+class QDBusVariant;
+class QPainter;
+
+namespace QtWaylandClient {
+
+//
+// INFO
+// -------------
+//
+// This is a Qt decoration plugin implementing Adwaita-like (GNOME) client-side
+// window decorations. It uses xdg-desktop-portal to get the user configuration.
+// This plugin was originally part of QGnomePlatform and later made a separate
+// project named QAdwaitaDecorations.
+//
+// INFO: How SVG icons are used here?
+// We try to find an SVG icon for a particular button from the current icon theme.
+// This icon is then opened as a file, it's content saved and later loaded to be
+// painted with QSvgRenderer, but before it's painted, we try to find following
+// patterns:
+// 1) fill=[\"']#[0-9A-F]{6}[\"']
+// 2) fill:#[0-9A-F]{6}
+// 3) fill=[\"']currentColor[\"']
+// The color in this case doesn't match the theme and is replaced by Foreground color.
+//
+// FIXME/TODO:
+// This plugin currently have all the colors for the decorations hardcoded.
+// There might be a way to get these from GTK/libadwaita (not sure), but problem is
+// we want Gtk4 version and using Gtk4 together with QGtk3Theme from QtBase that links
+// to Gtk3 will not work out. Possibly in future we can make a QGtk4Theme providing us
+// what we need to paint the decorations without having to deal with the colors ourself.
+//
+// TODO: Implement shadows
+
+
+class QWaylandAdwaitaDecoration : public QWaylandAbstractDecoration
+{
+ Q_OBJECT
+public:
+ enum ColorType {
+ Background,
+ BackgroundInactive,
+ Foreground,
+ ForegroundInactive,
+ Border,
+ BorderInactive,
+ ButtonBackground,
+ ButtonBackgroundInactive,
+ HoveredButtonBackground,
+ PressedButtonBackground
+ };
+
+ enum Placement {
+ Left = 0,
+ Right = 1
+ };
+
+ enum Button {
+ None = 0x0,
+ Close = 0x1,
+ Minimize = 0x02,
+ Maximize = 0x04
+ };
+ Q_DECLARE_FLAGS(Buttons, Button);
+
+ enum ButtonIcon {
+ CloseIcon,
+ MinimizeIcon,
+ MaximizeIcon,
+ RestoreIcon
+ };
+
+ QWaylandAdwaitaDecoration();
+ virtual ~QWaylandAdwaitaDecoration() = default;
+
+protected:
+ QMargins margins(MarginsType marginsType = Full) const override;
+ void paint(QPaintDevice *device) override;
+ bool handleMouse(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global,
+ Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
+ bool handleTouch(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global,
+ QEventPoint::State state, Qt::KeyboardModifiers mods) override;
+
+private Q_SLOTS:
+ void settingChanged(const QString &group, const QString &key, const QDBusVariant &value);
+
+private:
+ // Makes a call to xdg-desktop-portal (Settings) to load initial configuration
+ void loadConfiguration();
+ // Updates color scheme from light to dark and vice-versa
+ void updateColors(bool isDark);
+ // Updates titlebar layout with position and button order
+ void updateTitlebarLayout(const QString &layout);
+
+ // Returns a bounding rect for a given button type
+ QRectF buttonRect(Button button) const;
+ // Draw given button type using SVG icon (when found) or fallback to QPixmap icon
+ void drawButton(Button button, QPainter *painter);
+
+ // Returns color for given type and button
+ QColor color(ColorType type, Button button = None);
+
+ // Returns whether the left button was clicked i.e. pressed and released
+ bool clickButton(Qt::MouseButtons b, Button btn);
+ // Returns whether the left button was double-clicked
+ bool doubleClickButton(Qt::MouseButtons b, const QPointF &local, const QDateTime &currentTime);
+ // Updates button hover state
+ void updateButtonHoverState(Button hoveredButton);
+
+ void processMouseTop(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,
+ Qt::KeyboardModifiers mods);
+ void processMouseBottom(QWaylandInputDevice *inputDevice, const QPointF &local,
+ Qt::MouseButtons b, Qt::KeyboardModifiers mods);
+ void processMouseLeft(QWaylandInputDevice *inputDevice, const QPointF &local,
+ Qt::MouseButtons b, Qt::KeyboardModifiers mods);
+ void processMouseRight(QWaylandInputDevice *inputDevice, const QPointF &local,
+ Qt::MouseButtons b, Qt::KeyboardModifiers mods);
+ // Request to repaint the decorations. This will be invoked when button hover changes or
+ // when there is a setting change (e.g. layout change).
+ void requestRepaint() const;
+
+ // Button states
+ Button m_clicking = None;
+ Buttons m_hoveredButtons = None;
+ QDateTime m_lastButtonClick;
+ QPointF m_lastButtonClickPosition;
+
+ // Configuration
+ QMap<Button, uint> m_buttons;
+ QMap<ColorType, QColor> m_colors;
+ QMap<ButtonIcon, QString> m_icons;
+ std::unique_ptr<QFont> m_font;
+ Placement m_placement = Right;
+
+ QStaticText m_windowTitle;
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QWaylandAdwaitaDecoration::Buttons)
+
+} // namespace QtWaylandClient
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDADWAITADECORATION_P_H
diff --git a/src/plugins/decorations/bradient/CMakeLists.txt b/src/plugins/decorations/bradient/CMakeLists.txt
index 6f36d506c..065d0f18c 100644
--- a/src/plugins/decorations/bradient/CMakeLists.txt
+++ b/src/plugins/decorations/bradient/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from bradient.pro.
#####################################################################
diff --git a/src/plugins/decorations/bradient/main.cpp b/src/plugins/decorations/bradient/main.cpp
index 8669405bf..32f2d8db8 100644
--- a/src/plugins/decorations/bradient/main.cpp
+++ b/src/plugins/decorations/bradient/main.cpp
@@ -42,19 +42,21 @@ protected:
bool handleMouse(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global,Qt::MouseButtons b,Qt::KeyboardModifiers mods) override;
bool handleTouch(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, QEventPoint::State state, Qt::KeyboardModifiers mods) override;
private:
- void processMouseTop(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods);
- void processMouseBottom(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods);
- void processMouseLeft(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods);
- void processMouseRight(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods);
+ enum class PointerType {
+ Mouse,
+ Touch
+ };
+
+ void processPointerTop(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods, PointerType type);
+ void processPointerBottom(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods, PointerType type);
+ void processPointerLeft(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods, PointerType type);
+ void processPointerRight(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods, PointerType type);
bool clickButton(Qt::MouseButtons b, Button btn);
QRectF closeButtonRect() const;
QRectF maximizeButtonRect() const;
QRectF minimizeButtonRect() const;
- QColor m_foregroundColor;
- QColor m_foregroundInactiveColor;
- QColor m_backgroundColor;
QStaticText m_windowTitle;
Button m_clicking = None;
};
@@ -63,33 +65,29 @@ private:
QWaylandBradientDecoration::QWaylandBradientDecoration()
{
- QPalette palette;
- m_foregroundColor = palette.color(QPalette::Active, QPalette::WindowText);
- m_backgroundColor = palette.color(QPalette::Active, QPalette::Window);
- m_foregroundInactiveColor = palette.color(QPalette::Disabled, QPalette::WindowText);
-
QTextOption option(Qt::AlignHCenter | Qt::AlignVCenter);
option.setWrapMode(QTextOption::NoWrap);
m_windowTitle.setTextOption(option);
+ m_windowTitle.setTextFormat(Qt::PlainText);
}
QRectF QWaylandBradientDecoration::closeButtonRect() const
{
- const int windowRight = waylandWindow()->windowContentGeometry().right() + 1;
+ const int windowRight = waylandWindow()->surfaceSize().width() - margins(ShadowsOnly).right();
return QRectF(windowRight - BUTTON_WIDTH - BUTTON_SPACING * 0 - BUTTONS_RIGHT_MARGIN,
(margins().top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH);
}
QRectF QWaylandBradientDecoration::maximizeButtonRect() const
{
- const int windowRight = waylandWindow()->windowContentGeometry().right() + 1;
+ const int windowRight = waylandWindow()->surfaceSize().width() - margins(ShadowsOnly).right();
return QRectF(windowRight - BUTTON_WIDTH * 2 - BUTTON_SPACING * 1 - BUTTONS_RIGHT_MARGIN,
(margins().top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH);
}
QRectF QWaylandBradientDecoration::minimizeButtonRect() const
{
- const int windowRight = waylandWindow()->windowContentGeometry().right() + 1;
+ const int windowRight = waylandWindow()->surfaceSize().width() - margins(ShadowsOnly).right();
return QRectF(windowRight - BUTTON_WIDTH * 3 - BUTTON_SPACING * 2 - BUTTONS_RIGHT_MARGIN,
(margins().top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH);
}
@@ -105,17 +103,23 @@ QMargins QWaylandBradientDecoration::margins(MarginsType marginsType) const
void QWaylandBradientDecoration::paint(QPaintDevice *device)
{
bool active = window()->handle()->isActive();
- QRect wg = waylandWindow()->windowContentGeometry();
+ QRect wg = QRect(QPoint(), waylandWindow()->surfaceSize()).marginsRemoved(margins(ShadowsOnly));
+ QRect cg = wg.marginsRemoved(margins(ShadowsExcluded));
QRect clips[] =
{
- QRect(wg.left(), wg.top(), wg.width(), margins().top()),
- QRect(wg.left(), (wg.bottom() + 1) - margins().bottom(), wg.width(), margins().bottom()),
- QRect(wg.left(), margins().top(), margins().left(), wg.height() - margins().top() - margins().bottom()),
- QRect((wg.right() + 1) - margins().right(), wg.top() + margins().top(), margins().right(), wg.height() - margins().top() - margins().bottom())
+ QRect(wg.left(), wg.top(), wg.width(), margins(ShadowsExcluded).top()),
+ QRect(wg.left(), cg.bottom() + 1, wg.width(), margins(ShadowsExcluded).bottom()),
+ QRect(wg.left(), cg.top(), margins(ShadowsExcluded).left(), cg.height()),
+ QRect(cg.right() + 1, cg.top(), margins(ShadowsExcluded).right(), cg.height())
};
QRect top = clips[0];
+ QPalette palette;
+ const QColor foregroundColor = palette.color(QPalette::Active, QPalette::WindowText);
+ const QColor backgroundColor = palette.color(QPalette::Active, QPalette::Window);
+ const QColor foregroundInactiveColor = palette.color(QPalette::Disabled, QPalette::WindowText);
+
QPainter p(device);
p.setRenderHint(QPainter::Antialiasing);
@@ -125,7 +129,7 @@ void QWaylandBradientDecoration::paint(QPaintDevice *device)
for (int i = 0; i < 4; ++i) {
p.save();
p.setClipRect(clips[i]);
- p.fillPath(roundedRect, m_backgroundColor);
+ p.fillPath(roundedRect, backgroundColor);
p.restore();
}
@@ -139,7 +143,7 @@ void QWaylandBradientDecoration::paint(QPaintDevice *device)
}
// Window title
- QString windowTitleText = window()->title();
+ QString windowTitleText = waylandWindow()->windowTitle();
if (!windowTitleText.isEmpty()) {
if (m_windowTitle.text() != windowTitleText) {
m_windowTitle.setText(windowTitleText);
@@ -153,7 +157,7 @@ void QWaylandBradientDecoration::paint(QPaintDevice *device)
p.save();
p.setClipRect(titleBar);
- p.setPen(active ? m_foregroundColor : m_foregroundInactiveColor);
+ p.setPen(active ? foregroundColor : foregroundInactiveColor);
QSizeF size = m_windowTitle.size();
int dx = (top.width() - size.width()) /2;
int dy = (top.height()- size.height()) /2;
@@ -169,7 +173,7 @@ void QWaylandBradientDecoration::paint(QPaintDevice *device)
QRectF rect;
// Default pen
- QPen pen(active ? m_foregroundColor : m_foregroundInactiveColor);
+ QPen pen(active ? foregroundColor : foregroundInactiveColor);
p.setPen(pen);
// Close button
@@ -193,7 +197,7 @@ void QWaylandBradientDecoration::paint(QPaintDevice *device)
QRectF rect1 = rect.adjusted(inset, 0, 0, -inset);
QRectF rect2 = rect.adjusted(0, inset, -inset, 0);
p.drawRect(rect1);
- p.setBrush(m_backgroundColor); // need to cover up some lines from the other rect
+ p.setBrush(backgroundColor); // need to cover up some lines from the other rect
p.drawRect(rect2);
} else {
p.drawRect(rect);
@@ -233,15 +237,15 @@ bool QWaylandBradientDecoration::handleMouse(QWaylandInputDevice *inputDevice, c
Q_UNUSED(global);
// Figure out what area mouse is in
- QRect wg = waylandWindow()->windowContentGeometry();
- if (local.y() <= wg.top() + margins().top()) {
- processMouseTop(inputDevice,local,b,mods);
- } else if (local.y() > wg.bottom() - margins().bottom()) {
- processMouseBottom(inputDevice,local,b,mods);
- } else if (local.x() <= wg.left() + margins().left()) {
- processMouseLeft(inputDevice,local,b,mods);
- } else if (local.x() > wg.right() - margins().right()) {
- processMouseRight(inputDevice,local,b,mods);
+ QSize ss = waylandWindow()->surfaceSize();
+ if (local.y() <= margins().top()) {
+ processPointerTop(inputDevice, local, b, mods, PointerType::Mouse);
+ } else if (local.y() >= ss.height() - margins().bottom()) {
+ processPointerBottom(inputDevice, local, b, mods, PointerType::Mouse);
+ } else if (local.x() <= margins().left()) {
+ processPointerLeft(inputDevice, local, b, mods, PointerType::Mouse);
+ } else if (local.x() >= ss.width() - margins().right()) {
+ processPointerRight(inputDevice, local, b, mods, PointerType::Mouse);
} else {
#if QT_CONFIG(cursor)
waylandWindow()->restoreMouseCursor(inputDevice);
@@ -256,113 +260,152 @@ bool QWaylandBradientDecoration::handleMouse(QWaylandInputDevice *inputDevice, c
bool QWaylandBradientDecoration::handleTouch(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, QEventPoint::State state, Qt::KeyboardModifiers mods)
{
- Q_UNUSED(inputDevice);
Q_UNUSED(global);
- Q_UNUSED(mods);
+ QSize ss = waylandWindow()->surfaceSize();
+
bool handled = state == QEventPoint::Pressed;
if (handled) {
- if (closeButtonRect().contains(local))
- QWindowSystemInterface::handleCloseEvent(window());
- else if (maximizeButtonRect().contains(local))
- window()->setWindowStates(window()->windowStates() ^ Qt::WindowMaximized);
- else if (minimizeButtonRect().contains(local))
- window()->setWindowState(Qt::WindowMinimized);
- else if (local.y() <= margins().top())
- waylandWindow()->shellSurface()->move(inputDevice);
- else
+ if (local.y() <= margins().top()) {
+ processPointerTop(inputDevice, local, Qt::LeftButton, mods, PointerType::Touch);
+ } else if (local.y() >= ss.height() - margins().bottom()) {
+ processPointerBottom(inputDevice, local, Qt::LeftButton, mods, PointerType::Touch);
+ } else if (local.x() <= margins().left()) {
+ processPointerLeft(inputDevice, local, Qt::LeftButton, mods, PointerType::Touch);
+ } else if (local.x() >= ss.width() - margins().right()) {
+ processPointerRight(inputDevice, local, Qt::LeftButton, mods, PointerType::Touch);
+ } else {
handled = false;
+ }
}
return handled;
}
-void QWaylandBradientDecoration::processMouseTop(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
+void QWaylandBradientDecoration::processPointerTop(QWaylandInputDevice *inputDevice,
+ const QPointF &local,
+ Qt::MouseButtons b,
+ Qt::KeyboardModifiers mods,
+ PointerType type)
{
- QRect wg = waylandWindow()->windowContentGeometry();
+#if !QT_CONFIG(cursor)
+ Q_UNUSED(type);
+#endif
+
+ QSize ss = waylandWindow()->surfaceSize();
Q_UNUSED(mods);
- if (local.y() <= wg.top() + margins().bottom()) {
+ if (local.y() <= margins().bottom()) {
if (local.x() <= margins().left()) {
//top left bit
#if QT_CONFIG(cursor)
- waylandWindow()->setMouseCursor(inputDevice, Qt::SizeFDiagCursor);
+ if (type == PointerType::Mouse)
+ waylandWindow()->setMouseCursor(inputDevice, Qt::SizeFDiagCursor);
#endif
startResize(inputDevice, Qt::TopEdge | Qt::LeftEdge, b);
- } else if (local.x() > wg.right() - margins().right()) {
+ } else if (local.x() >= ss.width() - margins().right()) {
//top right bit
#if QT_CONFIG(cursor)
- waylandWindow()->setMouseCursor(inputDevice, Qt::SizeBDiagCursor);
+ if (type == PointerType::Mouse)
+ waylandWindow()->setMouseCursor(inputDevice, Qt::SizeBDiagCursor);
#endif
startResize(inputDevice, Qt::TopEdge | Qt::RightEdge, b);
} else {
//top resize bit
#if QT_CONFIG(cursor)
- waylandWindow()->setMouseCursor(inputDevice, Qt::SplitVCursor);
+ if (type == PointerType::Mouse)
+ waylandWindow()->setMouseCursor(inputDevice, Qt::SplitVCursor);
#endif
startResize(inputDevice, Qt::TopEdge, b);
}
- } else if (local.x() <= wg.left() + margins().left()) {
- processMouseLeft(inputDevice, local, b, mods);
- } else if (local.x() > wg.right() - margins().right()) {
- processMouseRight(inputDevice, local, b, mods);
+ } else if (local.x() <= margins().left()) {
+ processPointerLeft(inputDevice, local, b, mods, type);
+ } else if (local.x() >= ss.width() - margins().right()) {
+ processPointerRight(inputDevice, local, b, mods, type);
} else if (isRightClicked(b)) {
showWindowMenu(inputDevice);
} else if (closeButtonRect().contains(local)) {
- if (clickButton(b, Close))
+ if (type == PointerType::Touch || clickButton(b, Close))
QWindowSystemInterface::handleCloseEvent(window());
} else if (maximizeButtonRect().contains(local)) {
- if (clickButton(b, Maximize))
+ if (type == PointerType::Touch || clickButton(b, Maximize))
window()->setWindowStates(window()->windowStates() ^ Qt::WindowMaximized);
} else if (minimizeButtonRect().contains(local)) {
- if (clickButton(b, Minimize))
+ if (type == PointerType::Touch || clickButton(b, Minimize))
window()->setWindowState(Qt::WindowMinimized);
} else {
#if QT_CONFIG(cursor)
- waylandWindow()->restoreMouseCursor(inputDevice);
+ if (type == PointerType::Mouse)
+ waylandWindow()->restoreMouseCursor(inputDevice);
#endif
startMove(inputDevice,b);
}
}
-void QWaylandBradientDecoration::processMouseBottom(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
+void QWaylandBradientDecoration::processPointerBottom(QWaylandInputDevice *inputDevice,
+ const QPointF &local,
+ Qt::MouseButtons b,
+ Qt::KeyboardModifiers mods,
+ PointerType type)
{
Q_UNUSED(mods);
+#if !QT_CONFIG(cursor)
+ Q_UNUSED(type);
+#endif
+
+ QSize ss = waylandWindow()->surfaceSize();
if (local.x() <= margins().left()) {
//bottom left bit
#if QT_CONFIG(cursor)
- waylandWindow()->setMouseCursor(inputDevice, Qt::SizeBDiagCursor);
+ if (type == PointerType::Mouse)
+ waylandWindow()->setMouseCursor(inputDevice, Qt::SizeBDiagCursor);
#endif
startResize(inputDevice, Qt::BottomEdge | Qt::LeftEdge, b);
- } else if (local.x() > window()->width() + margins().left()) {
+ } else if (local.x() >= ss.width() - margins().right()) {
//bottom right bit
#if QT_CONFIG(cursor)
- waylandWindow()->setMouseCursor(inputDevice, Qt::SizeFDiagCursor);
+ if (type == PointerType::Mouse)
+ waylandWindow()->setMouseCursor(inputDevice, Qt::SizeFDiagCursor);
#endif
startResize(inputDevice, Qt::BottomEdge | Qt::RightEdge, b);
} else {
//bottom bit
#if QT_CONFIG(cursor)
- waylandWindow()->setMouseCursor(inputDevice, Qt::SplitVCursor);
+ if (type == PointerType::Mouse)
+ waylandWindow()->setMouseCursor(inputDevice, Qt::SizeVerCursor);
#endif
startResize(inputDevice, Qt::BottomEdge, b);
}
}
-void QWaylandBradientDecoration::processMouseLeft(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
+void QWaylandBradientDecoration::processPointerLeft(QWaylandInputDevice *inputDevice,
+ const QPointF &local,
+ Qt::MouseButtons b,
+ Qt::KeyboardModifiers mods,
+ PointerType type)
{
Q_UNUSED(local);
Q_UNUSED(mods);
#if QT_CONFIG(cursor)
- waylandWindow()->setMouseCursor(inputDevice, Qt::SplitHCursor);
+ if (type == PointerType::Mouse)
+ waylandWindow()->setMouseCursor(inputDevice, Qt::SizeHorCursor);
+#else
+ Q_UNUSED(type);
#endif
startResize(inputDevice, Qt::LeftEdge, b);
}
-void QWaylandBradientDecoration::processMouseRight(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
+void QWaylandBradientDecoration::processPointerRight(QWaylandInputDevice *inputDevice,
+ const QPointF &local,
+ Qt::MouseButtons b,
+ Qt::KeyboardModifiers mods,
+ PointerType type)
{
Q_UNUSED(local);
Q_UNUSED(mods);
#if QT_CONFIG(cursor)
- waylandWindow()->setMouseCursor(inputDevice, Qt::SplitHCursor);
+ if (type == PointerType::Mouse)
+ waylandWindow()->setMouseCursor(inputDevice, Qt::SizeHorCursor);
+#else
+ Q_UNUSED(type);
#endif
startResize(inputDevice, Qt::RightEdge, b);
}
diff --git a/src/plugins/hardwareintegration/CMakeLists.txt b/src/plugins/hardwareintegration/CMakeLists.txt
index 656b43b85..472a4f909 100644
--- a/src/plugins/hardwareintegration/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/CMakeLists.txt
@@ -1,8 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from hardwareintegration.pro.
+# When doing unity build, we get symbol collisions with macros defined
+# in X11.h, and Xlib.h
+set(CMAKE_UNITY_BUILD OFF)
+
if(TARGET Qt::WaylandClient)
add_subdirectory(client)
endif()
if(TARGET Qt::WaylandCompositor)
add_subdirectory(compositor)
endif()
+
+set(CMAKE_UNITY_BUILD ${QT_UNITY_BUILD})
diff --git a/src/plugins/hardwareintegration/client/CMakeLists.txt b/src/plugins/hardwareintegration/client/CMakeLists.txt
index e86b6460d..362697197 100644
--- a/src/plugins/hardwareintegration/client/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/client/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from client.pro.
if(QT_FEATURE_wayland_egl)
diff --git a/src/plugins/hardwareintegration/client/brcm-egl/CMakeLists.txt b/src/plugins/hardwareintegration/client/brcm-egl/CMakeLists.txt
index b1304c7f7..90df10d8b 100644
--- a/src/plugins/hardwareintegration/client/brcm-egl/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/client/brcm-egl/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from brcm-egl.pro.
#####################################################################
diff --git a/src/plugins/hardwareintegration/client/dmabuf-server/CMakeLists.txt b/src/plugins/hardwareintegration/client/dmabuf-server/CMakeLists.txt
index 9104dbc75..e20820e3b 100644
--- a/src/plugins/hardwareintegration/client/dmabuf-server/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/client/dmabuf-server/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from dmabuf-server.pro.
#####################################################################
diff --git a/src/plugins/hardwareintegration/client/drm-egl-server/CMakeLists.txt b/src/plugins/hardwareintegration/client/drm-egl-server/CMakeLists.txt
index 1c91dd74b..124c72026 100644
--- a/src/plugins/hardwareintegration/client/drm-egl-server/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/client/drm-egl-server/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from drm-egl-server.pro.
#####################################################################
diff --git a/src/plugins/hardwareintegration/client/libhybris-egl-server/CMakeLists.txt b/src/plugins/hardwareintegration/client/libhybris-egl-server/CMakeLists.txt
index 32c6f6d7e..6bf74c146 100644
--- a/src/plugins/hardwareintegration/client/libhybris-egl-server/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/client/libhybris-egl-server/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from libhybris-egl-server.pro.
#####################################################################
diff --git a/src/plugins/hardwareintegration/client/shm-emulation-server/CMakeLists.txt b/src/plugins/hardwareintegration/client/shm-emulation-server/CMakeLists.txt
index 679039e13..81ff77bab 100644
--- a/src/plugins/hardwareintegration/client/shm-emulation-server/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/client/shm-emulation-server/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from shm-emulation-server.pro.
#####################################################################
diff --git a/src/plugins/hardwareintegration/client/vulkan-server/CMakeLists.txt b/src/plugins/hardwareintegration/client/vulkan-server/CMakeLists.txt
index c6beea9b2..825b85adb 100644
--- a/src/plugins/hardwareintegration/client/vulkan-server/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/client/vulkan-server/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from vulkan-server.pro.
#####################################################################
diff --git a/src/plugins/hardwareintegration/client/wayland-egl/CMakeLists.txt b/src/plugins/hardwareintegration/client/wayland-egl/CMakeLists.txt
index 39f05ca12..61ee4ea9f 100644
--- a/src/plugins/hardwareintegration/client/wayland-egl/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/client/wayland-egl/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from wayland-egl.pro.
#####################################################################
diff --git a/src/plugins/hardwareintegration/compositor/CMakeLists.txt b/src/plugins/hardwareintegration/compositor/CMakeLists.txt
index ff8b8de71..8b281f881 100644
--- a/src/plugins/hardwareintegration/compositor/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/compositor/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from compositor.pro.
add_subdirectory(hardwarelayer)
diff --git a/src/plugins/hardwareintegration/compositor/brcm-egl/CMakeLists.txt b/src/plugins/hardwareintegration/compositor/brcm-egl/CMakeLists.txt
index 93a64ea86..3f0e1d14d 100644
--- a/src/plugins/hardwareintegration/compositor/brcm-egl/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/compositor/brcm-egl/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from brcm-egl.pro.
#####################################################################
diff --git a/src/plugins/hardwareintegration/compositor/dmabuf-server/CMakeLists.txt b/src/plugins/hardwareintegration/compositor/dmabuf-server/CMakeLists.txt
index 2acbf42f7..a6b48e998 100644
--- a/src/plugins/hardwareintegration/compositor/dmabuf-server/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/compositor/dmabuf-server/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from dmabuf-server.pro.
#####################################################################
diff --git a/src/plugins/hardwareintegration/compositor/drm-egl-server/CMakeLists.txt b/src/plugins/hardwareintegration/compositor/drm-egl-server/CMakeLists.txt
index 504874735..7dcd92ec8 100644
--- a/src/plugins/hardwareintegration/compositor/drm-egl-server/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/compositor/drm-egl-server/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from drm-egl-server.pro.
#####################################################################
diff --git a/src/plugins/hardwareintegration/compositor/hardwarelayer/CMakeLists.txt b/src/plugins/hardwareintegration/compositor/hardwarelayer/CMakeLists.txt
index 5a40a66b3..a5deccdb7 100644
--- a/src/plugins/hardwareintegration/compositor/hardwarelayer/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/compositor/hardwarelayer/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from hardwarelayer.pro.
if(QT_FEATURE_wayland_layer_integration_vsp2)
diff --git a/src/plugins/hardwareintegration/compositor/hardwarelayer/vsp2/CMakeLists.txt b/src/plugins/hardwareintegration/compositor/hardwarelayer/vsp2/CMakeLists.txt
index 2dedea44c..27adac5fc 100644
--- a/src/plugins/hardwareintegration/compositor/hardwarelayer/vsp2/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/compositor/hardwarelayer/vsp2/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from vsp2.pro.
#####################################################################
diff --git a/src/plugins/hardwareintegration/compositor/libhybris-egl-server/CMakeLists.txt b/src/plugins/hardwareintegration/compositor/libhybris-egl-server/CMakeLists.txt
index 31c55be9a..cbd5e3740 100644
--- a/src/plugins/hardwareintegration/compositor/libhybris-egl-server/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/compositor/libhybris-egl-server/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from libhybris-egl-server.pro.
#####################################################################
diff --git a/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/CMakeLists.txt b/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/CMakeLists.txt
index 47596a659..f6141b79e 100644
--- a/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from linux-dmabuf-unstable-v1.pro.
#####################################################################
diff --git a/src/plugins/hardwareintegration/compositor/shm-emulation-server/CMakeLists.txt b/src/plugins/hardwareintegration/compositor/shm-emulation-server/CMakeLists.txt
index b271256da..e893102ad 100644
--- a/src/plugins/hardwareintegration/compositor/shm-emulation-server/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/compositor/shm-emulation-server/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from shm-emulation-server.pro.
#####################################################################
diff --git a/src/plugins/hardwareintegration/compositor/vulkan-server/CMakeLists.txt b/src/plugins/hardwareintegration/compositor/vulkan-server/CMakeLists.txt
index 29ad7f7b5..123ec8528 100644
--- a/src/plugins/hardwareintegration/compositor/vulkan-server/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/compositor/vulkan-server/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from vulkan-server.pro.
#####################################################################
diff --git a/src/plugins/hardwareintegration/compositor/wayland-egl/CMakeLists.txt b/src/plugins/hardwareintegration/compositor/wayland-egl/CMakeLists.txt
index 95d4bda24..a85351c29 100644
--- a/src/plugins/hardwareintegration/compositor/wayland-egl/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/compositor/wayland-egl/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from wayland-egl.pro.
#####################################################################
diff --git a/src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/CMakeLists.txt b/src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/CMakeLists.txt
index c7b0cd1ec..39c97bc5f 100644
--- a/src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/CMakeLists.txt
+++ b/src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from wayland-eglstream-controller.pro.
#####################################################################
diff --git a/src/plugins/platforms/CMakeLists.txt b/src/plugins/platforms/CMakeLists.txt
index 21f008ef3..b26c5f2ca 100644
--- a/src/plugins/platforms/CMakeLists.txt
+++ b/src/plugins/platforms/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from platforms.pro.
add_subdirectory(qwayland-generic)
diff --git a/src/plugins/platforms/qwayland-brcm-egl/CMakeLists.txt b/src/plugins/platforms/qwayland-brcm-egl/CMakeLists.txt
index ed3b00e12..944ec5ded 100644
--- a/src/plugins/platforms/qwayland-brcm-egl/CMakeLists.txt
+++ b/src/plugins/platforms/qwayland-brcm-egl/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qwayland-brcm-egl.pro.
#####################################################################
diff --git a/src/plugins/platforms/qwayland-brcm-egl/main.cpp b/src/plugins/platforms/qwayland-brcm-egl/main.cpp
index 9d99bbe30..4a13465c7 100644
--- a/src/plugins/platforms/qwayland-brcm-egl/main.cpp
+++ b/src/plugins/platforms/qwayland-brcm-egl/main.cpp
@@ -22,7 +22,7 @@ QPlatformIntegration *QWaylandBrcmEglPlatformIntegrationPlugin::create(const QSt
Q_UNUSED(system);
auto *integration = new QWaylandBrcmEglPlatformIntegration();
- if (integration->hasFailed()) {
+ if (!integration->init()) {
delete integration;
integration = nullptr;
}
diff --git a/src/plugins/platforms/qwayland-egl/CMakeLists.txt b/src/plugins/platforms/qwayland-egl/CMakeLists.txt
index 4d184f308..6473ba151 100644
--- a/src/plugins/platforms/qwayland-egl/CMakeLists.txt
+++ b/src/plugins/platforms/qwayland-egl/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qwayland-egl.pro.
#####################################################################
diff --git a/src/plugins/platforms/qwayland-egl/main.cpp b/src/plugins/platforms/qwayland-egl/main.cpp
index adcb861b3..149f6fc83 100644
--- a/src/plugins/platforms/qwayland-egl/main.cpp
+++ b/src/plugins/platforms/qwayland-egl/main.cpp
@@ -22,7 +22,7 @@ QPlatformIntegration *QWaylandEglPlatformIntegrationPlugin::create(const QString
Q_UNUSED(system);
auto *integration = new QWaylandEglPlatformIntegration();
- if (integration->hasFailed()) {
+ if (!integration->init()) {
delete integration;
integration = nullptr;
}
diff --git a/src/plugins/platforms/qwayland-generic/CMakeLists.txt b/src/plugins/platforms/qwayland-generic/CMakeLists.txt
index 85bb250cc..ef31e432f 100644
--- a/src/plugins/platforms/qwayland-generic/CMakeLists.txt
+++ b/src/plugins/platforms/qwayland-generic/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qwayland-generic.pro.
#####################################################################
diff --git a/src/plugins/platforms/qwayland-generic/main.cpp b/src/plugins/platforms/qwayland-generic/main.cpp
index 0c5087d62..a3486d0d3 100644
--- a/src/plugins/platforms/qwayland-generic/main.cpp
+++ b/src/plugins/platforms/qwayland-generic/main.cpp
@@ -22,7 +22,7 @@ QPlatformIntegration *QWaylandIntegrationPlugin::create(const QString& system, c
Q_UNUSED(system);
auto *integration = new QWaylandIntegration();
- if (integration->hasFailed()) {
+ if (!integration->init()) {
delete integration;
integration = nullptr;
}
diff --git a/src/plugins/shellintegration/CMakeLists.txt b/src/plugins/shellintegration/CMakeLists.txt
index eefa0227d..35967baf1 100644
--- a/src/plugins/shellintegration/CMakeLists.txt
+++ b/src/plugins/shellintegration/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from shellintegration.pro.
if(QT_FEATURE_wayland_client_fullscreen_shell_v1)
diff --git a/src/plugins/shellintegration/fullscreen-shell-v1/CMakeLists.txt b/src/plugins/shellintegration/fullscreen-shell-v1/CMakeLists.txt
index ee02e1ebf..7413bcdf5 100644
--- a/src/plugins/shellintegration/fullscreen-shell-v1/CMakeLists.txt
+++ b/src/plugins/shellintegration/fullscreen-shell-v1/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from fullscreen-shell-v1.pro.
#####################################################################
diff --git a/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.cpp b/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.cpp
index ddac7d295..7dcdd6e59 100644
--- a/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.cpp
+++ b/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.cpp
@@ -8,26 +8,20 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
-bool QWaylandFullScreenShellV1Integration::initialize(QWaylandDisplay *display)
+QWaylandFullScreenShellV1Integration::QWaylandFullScreenShellV1Integration()
+ : QWaylandShellIntegrationTemplate(1)
{
- for (const QWaylandDisplay::RegistryGlobal &global : display->globals()) {
- if (global.interface == QLatin1String("zwp_fullscreen_shell_v1") && !m_shell) {
- m_shell.reset(new QtWayland::zwp_fullscreen_shell_v1(display->wl_registry(), global.id, global.version));
- break;
- }
- }
-
- if (!m_shell) {
- qCDebug(lcQpaWayland) << "Couldn't find global zwp_fullscreen_shell_v1 for fullscreen-shell";
- return false;
- }
-
- return true;
+}
+
+QWaylandFullScreenShellV1Integration::~QWaylandFullScreenShellV1Integration()
+{
+ if (isActive())
+ release();
}
QWaylandShellSurface *QWaylandFullScreenShellV1Integration::createShellSurface(QWaylandWindow *window)
{
- return new QWaylandFullScreenShellV1Surface(m_shell.data(), window);
+ return new QWaylandFullScreenShellV1Surface(this, window);
}
} // namespace QtWaylandClient
diff --git a/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.h b/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.h
index 48cb80c73..c01af3707 100644
--- a/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.h
+++ b/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1integration.h
@@ -14,14 +14,14 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
-class Q_WAYLANDCLIENT_EXPORT QWaylandFullScreenShellV1Integration : public QWaylandShellIntegration
+class Q_WAYLANDCLIENT_EXPORT QWaylandFullScreenShellV1Integration
+ : public QWaylandShellIntegrationTemplate<QWaylandFullScreenShellV1Integration>,
+ public QtWayland::zwp_fullscreen_shell_v1
{
public:
- bool initialize(QWaylandDisplay *display) override;
+ QWaylandFullScreenShellV1Integration();
+ ~QWaylandFullScreenShellV1Integration() override;
QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
-
-private:
- QScopedPointer<QtWayland::zwp_fullscreen_shell_v1> m_shell;
};
} // namespace QtWaylandClient
diff --git a/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.h b/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.h
index 8affdfd66..0a82e5eee 100644
--- a/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.h
+++ b/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.h
@@ -18,6 +18,7 @@ class Q_WAYLANDCLIENT_EXPORT QWaylandFullScreenShellV1Surface : public QWaylandS
{
public:
QWaylandFullScreenShellV1Surface(QtWayland::zwp_fullscreen_shell_v1 *shell, QWaylandWindow *window);
+ std::any surfaceRole() const override { return m_shell->object(); }
private:
QtWayland::zwp_fullscreen_shell_v1 *m_shell = nullptr;
diff --git a/src/plugins/shellintegration/ivi-shell/CMakeLists.txt b/src/plugins/shellintegration/ivi-shell/CMakeLists.txt
index b80280e50..4aed85dc6 100644
--- a/src/plugins/shellintegration/ivi-shell/CMakeLists.txt
+++ b/src/plugins/shellintegration/ivi-shell/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from ivi-shell.pro.
#####################################################################
diff --git a/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.cpp b/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.cpp
index 1638b1506..8bf9a0301 100644
--- a/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.cpp
+++ b/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.cpp
@@ -20,25 +20,24 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
+class QWaylandIviController : public QWaylandClientExtensionTemplate<QWaylandIviController>,
+ public QtWayland::ivi_controller
+{
+public:
+ QWaylandIviController() : QWaylandClientExtensionTemplate(1) { }
+ void initialize() { QWaylandClientExtensionTemplate::initialize(); }
+};
+
QWaylandIviShellIntegration::QWaylandIviShellIntegration()
+ : QWaylandShellIntegrationTemplate(1), m_iviController(new QWaylandIviController)
{
}
bool QWaylandIviShellIntegration::initialize(QWaylandDisplay *display)
{
- for (QWaylandDisplay::RegistryGlobal global : display->globals()) {
- if (global.interface == QLatin1String("ivi_application") && !m_iviApplication)
- m_iviApplication.reset(new QtWayland::ivi_application(display->wl_registry(), global.id, global.version));
- if (global.interface == QLatin1String("ivi_controller") && !m_iviController)
- m_iviController.reset(new QtWayland::ivi_controller(display->wl_registry(), global.id, global.version));
- }
-
- if (!m_iviApplication) {
- qCDebug(lcQpaWayland) << "Couldn't find global ivi_application for ivi-shell";
- return false;
- }
-
- return true;
+ QWaylandShellIntegrationTemplate::initialize(display);
+ m_iviController->initialize();
+ return isActive();
}
/* get unique id
@@ -91,15 +90,15 @@ uint32_t QWaylandIviShellIntegration::getNextUniqueSurfaceId()
QWaylandShellSurface *QWaylandIviShellIntegration::createShellSurface(QWaylandWindow *window)
{
- if (!m_iviApplication)
+ if (!isActive())
return nullptr;
uint32_t surfaceId = getNextUniqueSurfaceId();
if (surfaceId == 0)
return nullptr;
- struct ivi_surface *surface = m_iviApplication->surface_create(surfaceId, window->wlSurface());
- if (!m_iviController)
+ struct ivi_surface *surface = surface_create(surfaceId, window->wlSurface());
+ if (!m_iviController->isActive())
return new QWaylandIviSurface(surface, window);
struct ::ivi_controller_surface *controller = m_iviController->ivi_controller::surface_create(surfaceId);
diff --git a/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.h b/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.h
index 82fa9b568..14d9770a8 100644
--- a/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.h
+++ b/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.h
@@ -16,8 +16,11 @@ namespace QtWaylandClient {
class QWaylandWindow;
class QWaylandDisplay;
+class QWaylandIviController;
-class Q_WAYLANDCLIENT_EXPORT QWaylandIviShellIntegration : public QWaylandShellIntegration
+class Q_WAYLANDCLIENT_EXPORT QWaylandIviShellIntegration
+ : public QWaylandShellIntegrationTemplate<QWaylandIviShellIntegration>,
+ public QtWayland::ivi_application
{
public:
QWaylandIviShellIntegration();
@@ -29,8 +32,7 @@ private:
uint32_t getNextUniqueSurfaceId();
private:
- QScopedPointer<QtWayland::ivi_application> m_iviApplication;
- QScopedPointer<QtWayland::ivi_controller> m_iviController;
+ QScopedPointer<QWaylandIviController> m_iviController;
uint32_t m_lastSurfaceId = 0;
uint32_t m_surfaceNumber = 0;
bool m_useEnvSurfaceId = false;
diff --git a/src/plugins/shellintegration/ivi-shell/qwaylandivisurface_p.h b/src/plugins/shellintegration/ivi-shell/qwaylandivisurface_p.h
index 7e6811fd6..fc97a835a 100644
--- a/src/plugins/shellintegration/ivi-shell/qwaylandivisurface_p.h
+++ b/src/plugins/shellintegration/ivi-shell/qwaylandivisurface_p.h
@@ -14,7 +14,6 @@ namespace QtWaylandClient {
class QWaylandWindow;
class QWaylandInputDevice;
-class QWindow;
class QWaylandExtendedSurface;
class Q_WAYLANDCLIENT_EXPORT QWaylandIviSurface : public QtWayland::ivi_surface
@@ -28,6 +27,8 @@ public:
void applyConfigure() override;
+ std::any surfaceRole() const override { return ivi_surface::object(); };
+
private:
void createExtendedSurface(QWaylandWindow *window);
void ivi_surface_configure(int32_t width, int32_t height) override;
diff --git a/src/plugins/shellintegration/qt-shell/CMakeLists.txt b/src/plugins/shellintegration/qt-shell/CMakeLists.txt
index 754320541..b4f9f8b5c 100644
--- a/src/plugins/shellintegration/qt-shell/CMakeLists.txt
+++ b/src/plugins/shellintegration/qt-shell/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#####################################################################
## QWaylandQtShellIntegrationPlugin Plugin:
#####################################################################
diff --git a/src/plugins/shellintegration/qt-shell/qwaylandqtsurface_p.h b/src/plugins/shellintegration/qt-shell/qwaylandqtsurface_p.h
index 2f95dd71f..6431bd552 100644
--- a/src/plugins/shellintegration/qt-shell/qwaylandqtsurface_p.h
+++ b/src/plugins/shellintegration/qt-shell/qwaylandqtsurface_p.h
@@ -14,7 +14,6 @@ namespace QtWaylandClient {
class QWaylandWindow;
class QWaylandInputDevice;
-class QWindow;
class Q_WAYLANDCLIENT_EXPORT QWaylandQtSurface : public QWaylandShellSurface
, public QtWayland::zqt_shell_surface_v1
@@ -42,6 +41,8 @@ public:
void raise() override;
void lower() override;
+ std::any surfaceRole() const override { return object(); };
+
private:
void resetConfiguration();
void sendSizeHints();
diff --git a/src/plugins/shellintegration/wl-shell/CMakeLists.txt b/src/plugins/shellintegration/wl-shell/CMakeLists.txt
index 6b9ff55fe..09b076d00 100644
--- a/src/plugins/shellintegration/wl-shell/CMakeLists.txt
+++ b/src/plugins/shellintegration/wl-shell/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from wl-shell.pro.
#####################################################################
@@ -14,6 +17,9 @@ qt_internal_add_module(WlShellIntegrationPrivate
Qt::GuiPrivate
Qt::WaylandClientPrivate
Wayland::Client
+ PRIVATE_HEADER_FILTERS
+ "^qwayland-.*\.h|^wayland-.*-protocol\.h"
+ NO_GENERATE_CPP_EXPORTS
)
qt6_generate_wayland_protocol_client_sources(WlShellIntegrationPrivate
diff --git a/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration.cpp b/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration.cpp
index f0e38a331..2e2076b0a 100644
--- a/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration.cpp
+++ b/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration.cpp
@@ -11,31 +11,22 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
-bool QWaylandWlShellIntegration::initialize(QWaylandDisplay *display)
+QWaylandWlShellIntegration::QWaylandWlShellIntegration() : QWaylandShellIntegrationTemplate(1)
{
- const auto globals = display->globals();
- for (QWaylandDisplay::RegistryGlobal global : globals) {
- if (global.interface == QLatin1String("wl_shell")) {
- m_wlShell = new QtWayland::wl_shell(display->wl_registry(), global.id, 1);
- break;
- }
- }
-
- if (!m_wlShell) {
- qCDebug(lcQpaWayland) << "Couldn't find global wl_shell";
- return false;
- }
-
qCWarning(lcQpaWayland) << "\"wl-shell\" is a deprecated shell extension, prefer using"
<< "\"xdg-shell\" if supported by the compositor"
<< "by setting the environment variable QT_WAYLAND_SHELL_INTEGRATION";
+}
- return true;
+QWaylandWlShellIntegration::~QWaylandWlShellIntegration()
+{
+ if (object())
+ wl_shell_destroy(object());
}
QWaylandShellSurface *QWaylandWlShellIntegration::createShellSurface(QWaylandWindow *window)
{
- return new QWaylandWlShellSurface(m_wlShell->get_shell_surface(window->wlSurface()), window);
+ return new QWaylandWlShellSurface(get_shell_surface(window->wlSurface()), window);
}
void *QWaylandWlShellIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
diff --git a/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration_p.h b/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration_p.h
index 51dac4bcd..312a1089a 100644
--- a/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration_p.h
+++ b/src/plugins/shellintegration/wl-shell/qwaylandwlshellintegration_p.h
@@ -23,16 +23,17 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
-class Q_WAYLANDCLIENT_EXPORT QWaylandWlShellIntegration : public QWaylandShellIntegration
+class Q_WAYLANDCLIENT_EXPORT QWaylandWlShellIntegration
+ : public QWaylandShellIntegrationTemplate<QWaylandWlShellIntegration>,
+ public QtWayland::wl_shell
{
public:
- QWaylandWlShellIntegration() {}
- bool initialize(QWaylandDisplay *) override;
+ QWaylandWlShellIntegration();
+ ~QWaylandWlShellIntegration();
QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) override;
private:
- QtWayland::wl_shell *m_wlShell = nullptr;
};
}
diff --git a/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface_p.h b/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface_p.h
index d3996f43b..246003028 100644
--- a/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface_p.h
+++ b/src/plugins/shellintegration/wl-shell/qwaylandwlshellsurface_p.h
@@ -57,6 +57,8 @@ public:
void applyConfigure() override;
bool wantsDecorations() const override;
+ std::any surfaceRole() const override { return object(); };
+
protected:
void requestWindowStates(Qt::WindowStates states) override;
diff --git a/src/plugins/shellintegration/xdg-shell/CMakeLists.txt b/src/plugins/shellintegration/xdg-shell/CMakeLists.txt
index f840e293b..af5a97fee 100644
--- a/src/plugins/shellintegration/xdg-shell/CMakeLists.txt
+++ b/src/plugins/shellintegration/xdg-shell/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from xdg-shell.pro.
#####################################################################
@@ -13,6 +16,8 @@ qt_internal_add_plugin(QWaylandXdgShellIntegrationPlugin
qwaylandxdgactivationv1.cpp qwaylandxdgactivationv1_p.h
qwaylandxdgshell.cpp qwaylandxdgshell_p.h
qwaylandxdgshellintegration.cpp qwaylandxdgshellintegration_p.h
+ qwaylandxdgexporterv2.cpp qwaylandxdgexporterv2_p.h
+ qwaylandxdgdialogv1.cpp qwaylandxdgdialogv1_p.h
LIBRARIES
Qt::Core
Qt::Gui
@@ -26,6 +31,8 @@ qt6_generate_wayland_protocol_client_sources(QWaylandXdgShellIntegrationPlugin
${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/protocol/xdg-decoration-unstable-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/protocol/xdg-shell.xml
${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/protocol/xdg-activation-v1.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/protocol/xdg-foreign-unstable-v2.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/protocol/xdg-dialog-v1.xml
)
#### Keys ignored in scope 1:.:.:xdg-shell.pro:<TRUE>:
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgactivationv1.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgactivationv1.cpp
index e921ca461..8540724d8 100644
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgactivationv1.cpp
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgactivationv1.cpp
@@ -23,7 +23,8 @@ QWaylandXdgActivationV1::~QWaylandXdgActivationV1()
QWaylandXdgActivationTokenV1 *
QWaylandXdgActivationV1::requestXdgActivationToken(QWaylandDisplay *display,
- struct ::wl_surface *surface, uint32_t serial,
+ struct ::wl_surface *surface,
+ std::optional<uint32_t> serial,
const QString &app_id)
{
auto wl = get_activation_token();
@@ -36,12 +37,16 @@ QWaylandXdgActivationV1::requestXdgActivationToken(QWaylandDisplay *display,
if (!app_id.isEmpty())
provider->set_app_id(app_id);
- if (display->lastInputDevice())
- provider->set_serial(serial, display->lastInputDevice()->wl_seat());
+ if (serial && display->lastInputDevice())
+ provider->set_serial(*serial, display->lastInputDevice()->wl_seat());
provider->commit();
return provider;
}
+QWaylandXdgActivationTokenV1::~QWaylandXdgActivationTokenV1()
+{
+ destroy();
+}
}
QT_END_NAMESPACE
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgactivationv1_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgactivationv1_p.h
index d5d18459c..bddb5c614 100644
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgactivationv1_p.h
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgactivationv1_p.h
@@ -33,6 +33,7 @@ class Q_WAYLANDCLIENT_EXPORT QWaylandXdgActivationTokenV1
{
Q_OBJECT
public:
+ ~QWaylandXdgActivationTokenV1() override;
void xdg_activation_token_v1_done(const QString &token) override { Q_EMIT done(token); }
Q_SIGNALS:
@@ -47,7 +48,8 @@ public:
QWaylandXdgActivationTokenV1 *requestXdgActivationToken(QWaylandDisplay *display,
struct ::wl_surface *surface,
- uint32_t serial, const QString &app_id);
+ std::optional<uint32_t> serial,
+ const QString &app_id);
};
QT_END_NAMESPACE
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgdialogv1.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgdialogv1.cpp
new file mode 100644
index 000000000..abf674623
--- /dev/null
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgdialogv1.cpp
@@ -0,0 +1,33 @@
+// Copyright (C) 2023 David Reondo <kde@david-redondo.de>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwaylandxdgdialogv1_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+QWaylandXdgDialogV1::QWaylandXdgDialogV1(::xdg_dialog_v1 *object) : xdg_dialog_v1(object) { }
+
+QWaylandXdgDialogV1::~QWaylandXdgDialogV1()
+{
+ xdg_dialog_v1_destroy(object());
+}
+
+QWaylandXdgDialogWmV1::QWaylandXdgDialogWmV1(wl_registry *registry, uint32_t id, int version)
+ : xdg_wm_dialog_v1(registry, id, version)
+{
+}
+
+QWaylandXdgDialogWmV1::~QWaylandXdgDialogWmV1()
+{
+ destroy();
+}
+QWaylandXdgDialogV1 *QWaylandXdgDialogWmV1::getDialog(xdg_toplevel *toplevel)
+{
+ return new QWaylandXdgDialogV1(get_xdg_dialog(toplevel));
+}
+
+} // namespace QtWaylandClient
+
+QT_END_NAMESPACE
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgdialogv1_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgdialogv1_p.h
new file mode 100644
index 000000000..f5465a63e
--- /dev/null
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgdialogv1_p.h
@@ -0,0 +1,32 @@
+// Copyright (C) 2022 David Reondo <kde@david-redondo.de>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWAYLANDDIALOGV1_P_H
+#define QWAYLANDDIALOGV1_P_H
+
+#include <qwayland-xdg-dialog-v1.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+class QWaylandXdgDialogV1 : public QtWayland::xdg_dialog_v1
+{
+public:
+ QWaylandXdgDialogV1(::xdg_dialog_v1 *object);
+ ~QWaylandXdgDialogV1() override;
+};
+
+class QWaylandXdgDialogWmV1 : public QtWayland::xdg_wm_dialog_v1
+{
+public:
+ QWaylandXdgDialogWmV1(wl_registry *registry, uint32_t id, int version);
+ ~QWaylandXdgDialogWmV1() override;
+ QWaylandXdgDialogV1 *getDialog(xdg_toplevel *toplevel);
+};
+
+} // namespace QtWaylandClient
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgexporterv2.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgexporterv2.cpp
new file mode 100644
index 000000000..5cbbecc53
--- /dev/null
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgexporterv2.cpp
@@ -0,0 +1,41 @@
+// Copyright (C) 2022 David Reondo <kde@david-redondo.de>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwaylandxdgexporterv2_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+QWaylandXdgExportedV2::QWaylandXdgExportedV2(::zxdg_exported_v2 *object)
+ : QtWayland::zxdg_exported_v2(object)
+{
+}
+
+QWaylandXdgExportedV2::~QWaylandXdgExportedV2()
+{
+ destroy();
+}
+
+void QWaylandXdgExportedV2::zxdg_exported_v2_handle(const QString &handle)
+{
+ mHandle = handle;
+}
+
+QString QWaylandXdgExportedV2::handle() const
+{
+ return mHandle;
+}
+
+QWaylandXdgExporterV2::QWaylandXdgExporterV2(wl_registry *registry, uint32_t id, int version)
+ : QtWayland::zxdg_exporter_v2(registry, id, qMin(version, 1))
+{
+}
+
+QWaylandXdgExporterV2::~QWaylandXdgExporterV2()
+{
+ destroy();
+}
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgexporterv2_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgexporterv2_p.h
new file mode 100644
index 000000000..c993e390a
--- /dev/null
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgexporterv2_p.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2022 David Reondo <kde@david-redondo.de>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWAYLANDXDGEXPORTERV2_H
+#define QWAYLANDXDGEXPORTERV2_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qwayland-xdg-foreign-unstable-v2.h>
+
+#include <QtWaylandClient/qtwaylandclientglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+class QWaylandXdgExportedV2 : public QtWayland::zxdg_exported_v2
+{
+public:
+ explicit QWaylandXdgExportedV2(::zxdg_exported_v2 *object);
+ ~QWaylandXdgExportedV2() override;
+ QString handle() const;
+
+private:
+ void zxdg_exported_v2_handle(const QString &handle) override;
+ QString mHandle;
+};
+
+class QWaylandXdgExporterV2 : public QtWayland::zxdg_exporter_v2
+{
+public:
+ QWaylandXdgExporterV2(wl_registry *registry, uint32_t id, int version);
+ ~QWaylandXdgExporterV2() override;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QWAYLANDXDGEXPORTERV2_H
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
index 3d2fc61d3..c7b95e0d0 100644
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
@@ -1,15 +1,21 @@
// Copyright (C) 2017 The Qt Company Ltd.
// Copyright (C) 2017 Eurogiciel, author: <philippe.coval@eurogiciel.fr>
+// Copyright (C) 2023 David Edmundson <davidedmundson@kde.org>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwaylandxdgshell_p.h"
+#include "qwaylandxdgexporterv2_p.h"
+#include "qwaylandxdgdialogv1_p.h"
+
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtWaylandClient/private/qwaylandwindow_p.h>
#include <QtWaylandClient/private/qwaylandinputdevice_p.h>
#include <QtWaylandClient/private/qwaylandscreen_p.h>
+#include <QtWaylandClient/private/qwaylandcursor_p.h>
#include <QtWaylandClient/private/qwaylandabstractdecoration_p.h>
+#include <QtGui/QGuiApplication>
#include <QtGui/private/qwindow_p.h>
QT_BEGIN_NAMESPACE
@@ -27,6 +33,16 @@ QWaylandXdgSurface::Toplevel::Toplevel(QWaylandXdgSurface *xdgSurface)
}
requestWindowStates(window->windowStates());
requestWindowFlags(window->flags());
+ if (auto transientParent = xdgSurface->window()->transientParent()) {
+ if (auto parentSurface =
+ qobject_cast<QWaylandXdgSurface *>(transientParent->shellSurface())) {
+ set_parent(parentSurface->m_toplevel->object());
+ if (window->modality() != Qt::NonModal && m_xdgSurface->m_shell->m_xdgDialogWm) {
+ m_xdgDialog.reset(m_xdgSurface->m_shell->m_xdgDialogWm->getDialog(object()));
+ m_xdgDialog->set_modal();
+ }
+ }
+ }
}
QWaylandXdgSurface::Toplevel::~Toplevel()
@@ -42,7 +58,7 @@ QWaylandXdgSurface::Toplevel::~Toplevel()
void QWaylandXdgSurface::Toplevel::applyConfigure()
{
if (!(m_applied.states & (Qt::WindowMaximized|Qt::WindowFullScreen)))
- m_normalSize = m_xdgSurface->m_window->windowFrameGeometry().size();
+ m_normalSize = m_xdgSurface->m_window->windowContentGeometry().size();
if ((m_pending.states & Qt::WindowActive) && !(m_applied.states & Qt::WindowActive)
&& !m_xdgSurface->m_window->display()->isKeyboardAvailable())
@@ -55,16 +71,40 @@ void QWaylandXdgSurface::Toplevel::applyConfigure()
m_xdgSurface->m_window->handleToplevelWindowTilingStatesChanged(m_toplevelStates);
m_xdgSurface->m_window->handleWindowStatesChanged(m_pending.states);
- if (m_pending.size.isEmpty()) {
- // An empty size in the configure means it's up to the client to choose the size
- bool normalPending = !(m_pending.states & (Qt::WindowMaximized|Qt::WindowFullScreen));
- if (normalPending && !m_normalSize.isEmpty())
- m_xdgSurface->m_window->resizeFromApplyConfigure(m_normalSize);
+ // If the width or height is zero, the client should decide the size on its own.
+ QSize surfaceSize;
+
+ if (m_pending.size.width() > 0) {
+ surfaceSize.setWidth(m_pending.size.width());
+ } else {
+ if (Q_UNLIKELY(m_pending.states & (Qt::WindowMaximized | Qt::WindowFullScreen))) {
+ qCWarning(lcQpaWayland) << "Configure event with maximized or fullscreen state contains invalid width:" << m_pending.size.width();
+ } else {
+ int width = m_normalSize.width();
+ if (!m_pending.bounds.isEmpty())
+ width = std::min(width, m_pending.bounds.width());
+ surfaceSize.setWidth(width);
+ }
+ }
+
+ if (m_pending.size.height() > 0) {
+ surfaceSize.setHeight(m_pending.size.height());
} else {
- m_xdgSurface->m_window->resizeFromApplyConfigure(m_pending.size);
+ if (Q_UNLIKELY(m_pending.states & (Qt::WindowMaximized | Qt::WindowFullScreen))) {
+ qCWarning(lcQpaWayland) << "Configure event with maximized or fullscreen state contains invalid height:" << m_pending.size.height();
+ } else {
+ int height = m_normalSize.height();
+ if (!m_pending.bounds.isEmpty())
+ height = std::min(height, m_pending.bounds.height());
+ surfaceSize.setHeight(height);
+ }
}
m_applied = m_pending;
+
+ if (!surfaceSize.isEmpty())
+ m_xdgSurface->m_window->resizeFromApplyConfigure(surfaceSize.grownBy(m_xdgSurface->m_window->windowContentMargins()));
+
qCDebug(lcQpaWayland) << "Applied pending xdg_toplevel configure event:" << m_applied.size << m_applied.states;
}
@@ -77,6 +117,11 @@ bool QWaylandXdgSurface::Toplevel::wantsDecorations()
return !(m_pending.states & Qt::WindowFullScreen);
}
+void QWaylandXdgSurface::Toplevel::xdg_toplevel_configure_bounds(int32_t width, int32_t height)
+{
+ m_pending.bounds = QSize(width, height);
+}
+
void QWaylandXdgSurface::Toplevel::xdg_toplevel_configure(int32_t width, int32_t height, wl_array *states)
{
m_pending.size = QSize(width, height);
@@ -84,6 +129,7 @@ void QWaylandXdgSurface::Toplevel::xdg_toplevel_configure(int32_t width, int32_t
auto *xdgStates = static_cast<uint32_t *>(states->data);
size_t numStates = states->size / sizeof(uint32_t);
+ m_pending.suspended = false;
m_pending.states = Qt::WindowNoState;
m_toplevelStates = QWaylandWindow::WindowNoState;
@@ -110,6 +156,9 @@ void QWaylandXdgSurface::Toplevel::xdg_toplevel_configure(int32_t width, int32_t
case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
m_toplevelStates |= QWaylandWindow::WindowTiledBottom;
break;
+ case XDG_TOPLEVEL_STATE_SUSPENDED:
+ m_pending.suspended = true;
+ break;
default:
break;
}
@@ -120,7 +169,7 @@ void QWaylandXdgSurface::Toplevel::xdg_toplevel_configure(int32_t width, int32_t
void QWaylandXdgSurface::Toplevel::xdg_toplevel_close()
{
- m_xdgSurface->m_window->window()->close();
+ QWindowSystemInterface::handleCloseEvent(m_xdgSurface->m_window->window());
}
void QWaylandXdgSurface::Toplevel::requestWindowFlags(Qt::WindowFlags flags)
@@ -140,6 +189,15 @@ void QWaylandXdgSurface::Toplevel::requestWindowStates(Qt::WindowStates states)
// Re-send what's different from the applied state
Qt::WindowStates changedStates = m_applied.states ^ states;
+ // 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);
+ // The internal window state whilst minimized is not maximised or fullscreen, but we don't want to
+ // update the compositors cached version of this state
+ return;
+ }
+
if (changedStates & Qt::WindowMaximized) {
if (states & Qt::WindowMaximized)
set_maximized();
@@ -157,11 +215,7 @@ void QWaylandXdgSurface::Toplevel::requestWindowStates(Qt::WindowStates states)
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);
- }
+
}
QtWayland::xdg_toplevel::resize_edge QWaylandXdgSurface::Toplevel::convertToResizeEdges(Qt::Edges edges)
@@ -173,12 +227,15 @@ QtWayland::xdg_toplevel::resize_edge QWaylandXdgSurface::Toplevel::convertToResi
| ((edges & Qt::RightEdge) ? resize_edge_right : 0));
}
-QWaylandXdgSurface::Popup::Popup(QWaylandXdgSurface *xdgSurface, QWaylandXdgSurface *parent,
+QWaylandXdgSurface::Popup::Popup(QWaylandXdgSurface *xdgSurface, QWaylandWindow *parent,
QtWayland::xdg_positioner *positioner)
- : xdg_popup(xdgSurface->get_popup(parent ? parent->object() : nullptr, positioner->object()))
- , m_xdgSurface(xdgSurface)
+ : m_xdgSurface(xdgSurface)
+ , m_parentXdgSurface(qobject_cast<QWaylandXdgSurface *>(parent->shellSurface()))
, m_parent(parent)
{
+
+ init(xdgSurface->get_popup(m_parentXdgSurface ? m_parentXdgSurface->object() : nullptr,
+ positioner->object()));
}
QWaylandXdgSurface::Popup::~Popup()
@@ -187,9 +244,6 @@ QWaylandXdgSurface::Popup::~Popup()
destroy();
if (m_grabbing) {
- auto *shell = m_xdgSurface->m_shell;
- Q_ASSERT(shell->m_topmostGrabbingPopup == this);
- shell->m_topmostGrabbingPopup = m_parent ? m_parent->m_popup : nullptr;
m_grabbing = false;
// Synthesize Qt enter/leave events for popup
@@ -198,21 +252,45 @@ QWaylandXdgSurface::Popup::~Popup()
leave = m_xdgSurface->window()->window();
QWindowSystemInterface::handleLeaveEvent(leave);
- if (QWindow *enter = QGuiApplication::topLevelAt(QCursor::pos()))
- QWindowSystemInterface::handleEnterEvent(enter, enter->mapFromGlobal(QCursor::pos()), QCursor::pos());
+ QWindow *enter = nullptr;
+ if (m_parentXdgSurface && m_parentXdgSurface->window()) {
+ enter = m_parentXdgSurface->window()->window();
+ const auto pos = m_xdgSurface->window()->display()->waylandCursor()->pos();
+ QWindowSystemInterface::handleEnterEvent(enter, enter->handle()->mapFromGlobal(pos), pos);
+ }
+ }
+}
+
+void QWaylandXdgSurface::Popup::applyConfigure()
+{
+ if (m_pendingGeometry.isValid()) {
+ QRect geometryWithMargins = m_pendingGeometry.marginsAdded(m_xdgSurface->m_window->windowContentMargins());
+ QMargins parentMargins = m_parent->windowContentMargins() - m_parent->clientSideMargins();
+ QRect globalGeometry = geometryWithMargins.translated(m_parent->geometry().topLeft() + QPoint(parentMargins.left(), parentMargins.top()));
+ m_xdgSurface->setGeometryFromApplyConfigure(globalGeometry.topLeft(), globalGeometry.size());
}
+ resetConfiguration();
+}
+
+void QWaylandXdgSurface::Popup::resetConfiguration()
+{
+ m_pendingGeometry = QRect();
}
void QWaylandXdgSurface::Popup::grab(QWaylandInputDevice *seat, uint serial)
{
- m_xdgSurface->m_shell->m_topmostGrabbingPopup = this;
xdg_popup::grab(seat->wl_seat(), serial);
m_grabbing = true;
}
+void QWaylandXdgSurface::Popup::xdg_popup_configure(int32_t x, int32_t y, int32_t width, int32_t height)
+{
+ m_pendingGeometry = QRect(x, y, width, height);
+}
+
void QWaylandXdgSurface::Popup::xdg_popup_popup_done()
{
- m_xdgSurface->m_window->window()->close();
+ QWindowSystemInterface::handleCloseEvent(m_xdgSurface->m_window->window());
}
QWaylandXdgSurface::QWaylandXdgSurface(QWaylandXdgShell *shell, ::xdg_surface *surface, QWaylandWindow *window)
@@ -231,11 +309,6 @@ QWaylandXdgSurface::QWaylandXdgSurface(QWaylandXdgShell *shell, ::xdg_surface *s
setGrabPopup(transientParent, display->lastInputDevice(), display->lastInputSerial());
} else {
setToplevel();
- if (transientParent) {
- auto parentXdgSurface = qobject_cast<QWaylandXdgSurface *>(transientParent->shellSurface());
- if (parentXdgSurface)
- m_toplevel->set_parent(parentXdgSurface->m_toplevel->object());
- }
}
setSizeHints();
}
@@ -304,13 +377,15 @@ void QWaylandXdgSurface::setWindowFlags(Qt::WindowFlags flags)
bool QWaylandXdgSurface::isExposed() const
{
+ if (m_toplevel && m_toplevel->m_applied.suspended)
+ return false;
+
return m_configured || m_pendingConfigureSerial;
}
bool QWaylandXdgSurface::handleExpose(const QRegion &region)
{
if (!isExposed() && !region.isEmpty()) {
- m_exposeRegion = region;
return true;
}
return false;
@@ -324,6 +399,8 @@ void QWaylandXdgSurface::applyConfigure()
if (m_toplevel)
m_toplevel->applyConfigure();
+ if (m_popup)
+ m_popup->applyConfigure();
m_appliedConfigureSerial = m_pendingConfigureSerial;
m_configured = true;
@@ -338,29 +415,35 @@ bool QWaylandXdgSurface::wantsDecorations() const
void QWaylandXdgSurface::propagateSizeHints()
{
setSizeHints();
-
- if (m_toplevel && m_window)
- m_window->commit();
}
void QWaylandXdgSurface::setWindowGeometry(const QRect &rect)
{
- set_window_geometry(rect.x(), rect.y(), rect.width(), rect.height());
+ if (window()->isExposed())
+ set_window_geometry(rect.x(), rect.y(), rect.width(), rect.height());
}
void QWaylandXdgSurface::setSizeHints()
{
if (m_toplevel && m_window) {
- const int minWidth = qMax(0, m_window->windowMinimumSize().width());
- const int minHeight = qMax(0, m_window->windowMinimumSize().height());
- m_toplevel->set_min_size(minWidth, minHeight);
+ const QMargins margins = m_window->windowContentMargins() - m_window->clientSideMargins();
+ const QSize minSize = m_window->windowMinimumSize().shrunkBy(margins);
+ const QSize maxSize = m_window->windowMaximumSize().shrunkBy(margins);
+ const int minWidth = qMax(0, minSize.width());
+ const int minHeight = qMax(0, minSize.height());
+ int maxWidth = qMax(0, maxSize.width());
+ int maxHeight = qMax(0, maxSize.height());
+
+ // It will not change min/max sizes if invalid.
+ if (minWidth > maxWidth || minHeight > maxHeight)
+ return;
- int maxWidth = qMax(minWidth, m_window->windowMaximumSize().width());
if (maxWidth == QWINDOWSIZE_MAX)
maxWidth = 0;
- int maxHeight = qMax(minHeight, m_window->windowMaximumSize().height());
if (maxHeight == QWINDOWSIZE_MAX)
maxHeight = 0;
+
+ m_toplevel->set_min_size(minWidth, minHeight);
m_toplevel->set_max_size(maxWidth, maxHeight);
}
}
@@ -377,6 +460,15 @@ void *QWaylandXdgSurface::nativeResource(const QByteArray &resource)
return nullptr;
}
+std::any QWaylandXdgSurface::surfaceRole() const
+{
+ if (m_toplevel)
+ return m_toplevel->object();
+ if (m_popup)
+ return m_popup->object();
+ return {};
+}
+
void QWaylandXdgSurface::requestWindowStates(Qt::WindowStates states)
{
if (m_toplevel)
@@ -395,64 +487,127 @@ void QWaylandXdgSurface::setPopup(QWaylandWindow *parent)
{
Q_ASSERT(!m_toplevel && !m_popup);
- auto parentXdgSurface = qobject_cast<QWaylandXdgSurface *>(parent->shellSurface());
-
- auto positioner = new QtWayland::xdg_positioner(m_shell->create_positioner());
+ auto positioner = new QtWayland::xdg_positioner(m_shell->m_xdgWmBase->create_positioner());
// set_popup expects a position relative to the parent
- QPoint transientPos = m_window->geometry().topLeft(); // this is absolute
- transientPos -= parent->geometry().topLeft();
- if (parent->decoration()) {
- transientPos.setX(transientPos.x() + parent->decoration()->margins().left());
- transientPos.setY(transientPos.y() + parent->decoration()->margins().top());
- }
- positioner->set_anchor_rect(transientPos.x(), transientPos.y(), 1, 1);
- positioner->set_anchor(QtWayland::xdg_positioner::anchor_top_left);
- positioner->set_gravity(QtWayland::xdg_positioner::gravity_bottom_right);
- positioner->set_size(m_window->geometry().width(), m_window->geometry().height());
- positioner->set_constraint_adjustment(QtWayland::xdg_positioner::constraint_adjustment_slide_x
- | QtWayland::xdg_positioner::constraint_adjustment_slide_y
- | QtWayland::xdg_positioner::constraint_adjustment_flip_x
- | QtWayland::xdg_positioner::constraint_adjustment_flip_y);
- m_popup = new Popup(this, parentXdgSurface, positioner);
+ QRect windowGeometry = m_window->windowContentGeometry();
+ QMargins windowMargins = m_window->windowContentMargins() - m_window->clientSideMargins();
+ QMargins parentMargins = parent->windowContentMargins() - parent->clientSideMargins();
+
+ // These property overrides may be removed when public API becomes available
+ QRect placementAnchor = m_window->window()->property("_q_waylandPopupAnchorRect").toRect();
+ if (!placementAnchor.isValid()) {
+ placementAnchor = QRect(m_window->geometry().topLeft() - parent->geometry().topLeft(), QSize(1,1));
+ }
+ placementAnchor.translate(windowMargins.left(), windowMargins.top());
+ placementAnchor.translate(-parentMargins.left(), -parentMargins.top());
+
+ uint32_t anchor = QtWayland::xdg_positioner::anchor_top_right;
+ const QVariant anchorVariant = m_window->window()->property("_q_waylandPopupAnchor");
+ if (anchorVariant.isValid()) {
+ switch (anchorVariant.value<Qt::Edges>()) {
+ case Qt::Edges():
+ anchor = QtWayland::xdg_positioner::anchor_none;
+ break;
+ case Qt::TopEdge:
+ anchor = QtWayland::xdg_positioner::anchor_top;
+ break;
+ case Qt::TopEdge | Qt::RightEdge:
+ anchor = QtWayland::xdg_positioner::anchor_top_right;
+ break;
+ case Qt::RightEdge:
+ anchor = QtWayland::xdg_positioner::anchor_right;
+ break;
+ case Qt::BottomEdge | Qt::RightEdge:
+ anchor = QtWayland::xdg_positioner::anchor_bottom_right;
+ break;
+ case Qt::BottomEdge:
+ anchor = QtWayland::xdg_positioner::anchor_bottom;
+ break;
+ case Qt::BottomEdge | Qt::LeftEdge:
+ anchor = QtWayland::xdg_positioner::anchor_bottom_left;
+ break;
+ case Qt::LeftEdge:
+ anchor = QtWayland::xdg_positioner::anchor_left;
+ break;
+ case Qt::TopEdge | Qt::LeftEdge:
+ anchor = QtWayland::xdg_positioner::anchor_top_left;
+ break;
+ }
+ }
+
+ uint32_t gravity = QtWayland::xdg_positioner::gravity_bottom_right;
+ const QVariant popupGravityVariant = m_window->window()->property("_q_waylandPopupGravity");
+ if (popupGravityVariant.isValid()) {
+ switch (popupGravityVariant.value<Qt::Edges>()) {
+ case Qt::Edges():
+ gravity = QtWayland::xdg_positioner::gravity_none;
+ break;
+ case Qt::TopEdge:
+ gravity = QtWayland::xdg_positioner::gravity_top;
+ break;
+ case Qt::TopEdge | Qt::RightEdge:
+ gravity = QtWayland::xdg_positioner::gravity_top_right;
+ break;
+ case Qt::RightEdge:
+ gravity = QtWayland::xdg_positioner::gravity_right;
+ break;
+ case Qt::BottomEdge | Qt::RightEdge:
+ gravity = QtWayland::xdg_positioner::gravity_bottom_right;
+ break;
+ case Qt::BottomEdge:
+ gravity = QtWayland::xdg_positioner::gravity_bottom;
+ break;
+ case Qt::BottomEdge | Qt::LeftEdge:
+ gravity = QtWayland::xdg_positioner::gravity_bottom_left;
+ break;
+ case Qt::LeftEdge:
+ gravity = QtWayland::xdg_positioner::gravity_left;
+ break;
+ case Qt::TopEdge | Qt::LeftEdge:
+ gravity = QtWayland::xdg_positioner::gravity_top_left;
+ break;
+ }
+ }
+
+ uint32_t constraintAdjustment = QtWayland::xdg_positioner::constraint_adjustment_slide_x | QtWayland::xdg_positioner::constraint_adjustment_slide_y;
+ const QVariant constraintAdjustmentVariant = m_window->window()->property("_q_waylandPopupConstraintAdjustment");
+ if (constraintAdjustmentVariant.isValid()) {
+ constraintAdjustment = constraintAdjustmentVariant.toUInt();
+ }
+
+ positioner->set_anchor_rect(placementAnchor.x(),
+ placementAnchor.y(),
+ placementAnchor.width(),
+ placementAnchor.height());
+ positioner->set_anchor(anchor);
+ positioner->set_gravity(gravity);
+ positioner->set_size(windowGeometry.width(), windowGeometry.height());
+ positioner->set_constraint_adjustment(constraintAdjustment);
+ m_popup = new Popup(this, parent, positioner);
positioner->destroy();
+
delete positioner;
}
void QWaylandXdgSurface::setGrabPopup(QWaylandWindow *parent, QWaylandInputDevice *device, int serial)
{
- auto parentXdgSurface = qobject_cast<QWaylandXdgSurface *>(parent->shellSurface());
- auto *top = m_shell->m_topmostGrabbingPopup;
-
- if (top && top->m_xdgSurface != parentXdgSurface) {
- qCWarning(lcQpaWayland) << "setGrabPopup called with a parent," << parentXdgSurface
- << "which does not match the current topmost grabbing popup,"
- << top->m_xdgSurface << "According to the xdg-shell protocol, this"
- << "is not allowed. The wayland QPA plugin is currently handling"
- << "it by setting the parent to the topmost grabbing popup."
- << "Note, however, that this may cause positioning errors and"
- << "popups closing unxpectedly because xdg-shell mandate that child"
- << "popups close before parents";
- parent = top->m_xdgSurface->m_window;
- }
setPopup(parent);
m_popup->grab(device, serial);
// Synthesize Qt enter/leave events for popup
if (!parent)
return;
- QWindow *current = QGuiApplication::topLevelAt(QCursor::pos());
QWindow *leave = parent->window();
- if (current != leave)
- return;
-
QWindowSystemInterface::handleLeaveEvent(leave);
QWindow *enter = nullptr;
if (m_popup && m_popup->m_xdgSurface && m_popup->m_xdgSurface->window())
enter = m_popup->m_xdgSurface->window()->window();
- if (enter)
- QWindowSystemInterface::handleEnterEvent(enter, enter->mapFromGlobal(QCursor::pos()), QCursor::pos());
+ if (enter) {
+ const auto pos = m_popup->m_xdgSurface->window()->display()->waylandCursor()->pos();
+ QWindowSystemInterface::handleEnterEvent(enter, enter->handle()->mapFromGlobal(pos), pos);
+ }
}
void QWaylandXdgSurface::xdg_surface_configure(uint32_t serial)
@@ -461,28 +616,64 @@ void QWaylandXdgSurface::xdg_surface_configure(uint32_t serial)
if (!m_configured) {
// We have to do the initial applyConfigure() immediately, since that is the expose.
applyConfigure();
- m_exposeRegion = QRegion(QRect(QPoint(), m_window->geometry().size()));
+ if (isExposed())
+ m_window->sendRecursiveExposeEvent();
} else {
// Later configures are probably resizes, so we have to queue them up for a time when we
// are not painting to the window.
m_window->applyConfigureWhenPossible();
}
-
- if (!m_exposeRegion.isEmpty()) {
- m_window->handleExpose(m_exposeRegion);
- m_exposeRegion = QRegion();
- }
}
bool QWaylandXdgSurface::requestActivate()
{
if (auto *activation = m_shell->activation()) {
- activation->activate(m_activationToken, window()->wlSurface());
- return true;
+ if (!m_activationToken.isEmpty()) {
+ activation->activate(m_activationToken, window()->wlSurface());
+ m_activationToken = {};
+ return true;
+ } else if (const auto token = qEnvironmentVariable("XDG_ACTIVATION_TOKEN"); !token.isEmpty()) {
+ activation->activate(token, window()->wlSurface());
+ qunsetenv("XDG_ACTIVATION_TOKEN");
+ return true;
+ } else {
+ const auto focusWindow = QGuiApplication::focusWindow();
+ // At least GNOME requires to request the token in order to get the
+ // focus stealing prevention indication, so requestXdgActivationToken call
+ // is still necessary in that case.
+ const auto wlWindow = focusWindow ? static_cast<QWaylandWindow*>(focusWindow->handle()) : m_window;
+
+ QString appId;
+ if (const auto xdgSurface = qobject_cast<QWaylandXdgSurface *>(wlWindow->shellSurface()))
+ appId = xdgSurface->m_appId;
+
+ if (const auto seat = wlWindow->display()->lastInputDevice()) {
+ const auto tokenProvider = activation->requestXdgActivationToken(
+ wlWindow->display(), wlWindow->wlSurface(), seat->serial(), appId);
+ connect(tokenProvider, &QWaylandXdgActivationTokenV1::done, this,
+ [this, tokenProvider](const QString &token) {
+ m_shell->activation()->activate(token, window()->wlSurface());
+ tokenProvider->deleteLater();
+ });
+ return true;
+ }
+ }
}
return false;
}
+bool QWaylandXdgSurface::requestActivateOnShow()
+{
+ const Qt::WindowType type = m_window->window()->type();
+ if (type == Qt::ToolTip || type == Qt::Popup || type == Qt::SplashScreen)
+ return false;
+
+ if (m_window->window()->property("_q_showWithoutActivating").toBool())
+ return false;
+
+ return requestActivate();
+}
+
void QWaylandXdgSurface::requestXdgActivationToken(quint32 serial)
{
if (auto *activation = m_shell->activation()) {
@@ -507,27 +698,60 @@ void QWaylandXdgSurface::setXdgActivationToken(const QString &token)
}
}
-QWaylandXdgShell::QWaylandXdgShell(QWaylandDisplay *display, uint32_t id, uint32_t availableVersion)
- : QtWayland::xdg_wm_base(display->wl_registry(), id, qMin(availableVersion, 2u))
- , m_display(display)
+void QWaylandXdgSurface::setAlertState(bool enabled)
{
- display->addRegistryListener(&QWaylandXdgShell::handleRegistryGlobal, this);
+ if (m_alertState == enabled)
+ return;
+
+ m_alertState = enabled;
+
+ if (!m_alertState)
+ return;
+
+ auto *activation = m_shell->activation();
+ if (!activation)
+ return;
+
+ const auto tokenProvider = activation->requestXdgActivationToken(
+ m_shell->m_display, m_window->wlSurface(), std::nullopt, m_appId);
+ connect(tokenProvider, &QWaylandXdgActivationTokenV1::done, this,
+ [this, tokenProvider](const QString &token) {
+ m_shell->activation()->activate(token, m_window->wlSurface());
+ tokenProvider->deleteLater();
+ });
}
-QWaylandXdgShell::~QWaylandXdgShell()
+QString QWaylandXdgSurface::externWindowHandle()
{
- m_display->removeListener(&QWaylandXdgShell::handleRegistryGlobal, this);
- destroy();
+ if (!m_toplevel || !m_shell->exporter()) {
+ return QString();
+ }
+ if (!m_toplevel->m_exported) {
+ auto *exporterWrapper = static_cast<zxdg_exporter_v2 *>(
+ wl_proxy_create_wrapper(m_shell->exporter()->object()));
+ auto exportQueue = wl_display_create_queue(m_shell->display()->wl_display());
+ wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(exporterWrapper), exportQueue);
+ m_toplevel->m_exported.reset(new QWaylandXdgExportedV2(
+ zxdg_exporter_v2_export_toplevel(exporterWrapper, m_window->wlSurface())));
+ // handle events is sent immediately
+ wl_display_roundtrip_queue(m_shell->display()->wl_display(), exportQueue);
+
+ wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(m_toplevel->m_exported->object()), nullptr);
+ wl_proxy_wrapper_destroy(exporterWrapper);
+ wl_event_queue_destroy(exportQueue);
+ }
+ return m_toplevel->m_exported->handle();
}
-QWaylandXdgSurface *QWaylandXdgShell::getXdgSurface(QWaylandWindow *window)
+QWaylandXdgShell::QWaylandXdgShell(QWaylandDisplay *display, QtWayland::xdg_wm_base *xdgWmBase)
+ : m_display(display), m_xdgWmBase(xdgWmBase)
{
- return new QWaylandXdgSurface(this, get_xdg_surface(window->wlSurface()), window);
+ display->addRegistryListener(&QWaylandXdgShell::handleRegistryGlobal, this);
}
-void QWaylandXdgShell::xdg_wm_base_ping(uint32_t serial)
+QWaylandXdgShell::~QWaylandXdgShell()
{
- pong(serial);
+ m_display->removeListener(&QWaylandXdgShell::handleRegistryGlobal, this);
}
void QWaylandXdgShell::handleRegistryGlobal(void *data, wl_registry *registry, uint id,
@@ -540,6 +764,14 @@ void QWaylandXdgShell::handleRegistryGlobal(void *data, wl_registry *registry, u
if (interface == QLatin1String(QWaylandXdgActivationV1::interface()->name)) {
xdgShell->m_xdgActivation.reset(new QWaylandXdgActivationV1(registry, id, version));
}
+
+ if (interface == QLatin1String(QWaylandXdgExporterV2::interface()->name)) {
+ xdgShell->m_xdgExporter.reset(new QWaylandXdgExporterV2(registry, id, version));
+ }
+
+ if (interface == QLatin1String(QWaylandXdgDialogWmV1::interface()->name)) {
+ xdgShell->m_xdgDialogWm.reset(new QWaylandXdgDialogWmV1(registry, id, version));
+ }
}
}
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
index 30366168c..fa33259f7 100644
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
@@ -37,6 +37,10 @@ namespace QtWaylandClient {
class QWaylandDisplay;
class QWaylandInputDevice;
class QWaylandXdgShell;
+class QWaylandXdgExportedV2;
+class QWaylandXdgExporterV2;
+class QWaylandXdgDialogWmV1;
+class QWaylandXdgDialogV1;
class Q_WAYLANDCLIENT_EXPORT QWaylandXdgSurface : public QWaylandShellSurface, public QtWayland::xdg_surface
{
@@ -60,13 +64,19 @@ public:
void propagateSizeHints() override;
void setWindowGeometry(const QRect &rect) override;
bool requestActivate() override;
+ bool requestActivateOnShow() override;
void setXdgActivationToken(const QString &token) override;
void requestXdgActivationToken(quint32 serial) override;
+ void setAlertState(bool enabled) override;
+ bool isAlertState() const override { return m_alertState; }
+ QString externWindowHandle() override;
void setSizeHints();
void *nativeResource(const QByteArray &resource);
+ std::any surfaceRole() const override;
+
protected:
void requestWindowStates(Qt::WindowStates states) override;
void xdg_surface_configure(uint32_t serial) override;
@@ -83,6 +93,7 @@ private:
void xdg_toplevel_configure(int32_t width, int32_t height, wl_array *states) override;
void xdg_toplevel_close() override;
+ void xdg_toplevel_configure_bounds(int32_t width, int32_t height) override;
void requestWindowFlags(Qt::WindowFlags flags);
void requestWindowStates(Qt::WindowStates states);
@@ -90,27 +101,38 @@ private:
static resize_edge convertToResizeEdges(Qt::Edges edges);
struct {
+ QSize bounds = {0, 0};
QSize size = {0, 0};
Qt::WindowStates states = Qt::WindowNoState;
+ bool suspended = false;
} m_pending, m_applied;
QWaylandWindow::ToplevelWindowTilingStates m_toplevelStates = QWaylandWindow::WindowNoState;
QSize m_normalSize;
QWaylandXdgSurface *m_xdgSurface = nullptr;
QWaylandXdgToplevelDecorationV1 *m_decoration = nullptr;
+ QScopedPointer<QWaylandXdgExportedV2> m_exported;
+ QScopedPointer<QWaylandXdgDialogV1> m_xdgDialog;
};
class Popup : public QtWayland::xdg_popup {
public:
- Popup(QWaylandXdgSurface *xdgSurface, QWaylandXdgSurface *parent, QtWayland::xdg_positioner *positioner);
+ Popup(QWaylandXdgSurface *xdgSurface, QWaylandWindow *parent, QtWayland::xdg_positioner *positioner);
~Popup() override;
+ void applyConfigure();
+ void resetConfiguration();
+
void grab(QWaylandInputDevice *seat, uint serial);
+ void xdg_popup_configure(int32_t x, int32_t y, int32_t width, int32_t height) override;
void xdg_popup_popup_done() override;
QWaylandXdgSurface *m_xdgSurface = nullptr;
- QWaylandXdgSurface *m_parent = nullptr;
+ QWaylandXdgSurface *m_parentXdgSurface = nullptr;
+ QWaylandWindow *m_parent = nullptr;
bool m_grabbing = false;
+
+ QRect m_pendingGeometry;
};
void setToplevel();
@@ -122,36 +144,38 @@ private:
Toplevel *m_toplevel = nullptr;
Popup *m_popup = nullptr;
bool m_configured = false;
- QRegion m_exposeRegion;
uint m_pendingConfigureSerial = 0;
uint m_appliedConfigureSerial = 0;
QString m_activationToken;
QString m_appId;
+ bool m_alertState = false;
friend class QWaylandXdgShell;
};
-class Q_WAYLANDCLIENT_EXPORT QWaylandXdgShell : public QtWayland::xdg_wm_base
+class Q_WAYLANDCLIENT_EXPORT QWaylandXdgShell
{
public:
- QWaylandXdgShell(QWaylandDisplay *display, uint32_t id, uint32_t availableVersion);
- ~QWaylandXdgShell() override;
+ QWaylandXdgShell(QWaylandDisplay *display, QtWayland::xdg_wm_base *xdg_wm_base);
+ ~QWaylandXdgShell();
+
+ QWaylandDisplay *display() const { return m_display; }
QWaylandXdgDecorationManagerV1 *decorationManager() { return m_xdgDecorationManager.data(); }
QWaylandXdgActivationV1 *activation() const { return m_xdgActivation.data(); }
+ QWaylandXdgExporterV2 *exporter() const { return m_xdgExporter.data(); }
QWaylandXdgSurface *getXdgSurface(QWaylandWindow *window);
-protected:
- void xdg_wm_base_ping(uint32_t serial) override;
-
private:
static void handleRegistryGlobal(void *data, ::wl_registry *registry, uint id,
const QString &interface, uint version);
QWaylandDisplay *m_display = nullptr;
+ QtWayland::xdg_wm_base *m_xdgWmBase = nullptr;
QScopedPointer<QWaylandXdgDecorationManagerV1> m_xdgDecorationManager;
QScopedPointer<QWaylandXdgActivationV1> m_xdgActivation;
- QWaylandXdgSurface::Popup *m_topmostGrabbingPopup = nullptr;
+ QScopedPointer<QWaylandXdgExporterV2> m_xdgExporter;
+ QScopedPointer<QWaylandXdgDialogWmV1> m_xdgDialogWm;
friend class QWaylandXdgSurface;
};
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
index 8d648b628..f1bb8bee4 100644
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
@@ -1,6 +1,7 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qwaylandxdgshell_p.h"
#include "qwaylandxdgshellintegration_p.h"
#include "qwaylandxdgdecorationv1_p.h"
@@ -11,26 +12,38 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
-bool QWaylandXdgShellIntegration::initialize(QWaylandDisplay *display)
+QWaylandXdgShellIntegration::QWaylandXdgShellIntegration() : QWaylandShellIntegrationTemplate(6)
{
- for (QWaylandDisplay::RegistryGlobal global : display->globals()) {
- if (global.interface == QLatin1String("xdg_wm_base")) {
- m_xdgShell.reset(new QWaylandXdgShell(display, global.id, global.version));
- break;
+ connect(this, &QWaylandShellIntegrationTemplate::activeChanged, this, [this] {
+ if (isActive()) {
+ mXdgShell.reset(new QWaylandXdgShell(mDisplay, this));
+ } else {
+ mXdgShell.reset(nullptr);
+ destroy();
}
- }
+ });
+}
- if (!m_xdgShell) {
- qCDebug(lcQpaWayland) << "Couldn't find global xdg_wm_base for xdg-shell stable";
- return false;
- }
+QWaylandXdgShellIntegration::~QWaylandXdgShellIntegration()
+{
+ if (isActive())
+ destroy();
+}
- return true;
+bool QWaylandXdgShellIntegration::initialize(QWaylandDisplay *display)
+{
+ mDisplay = display;
+ return QWaylandShellIntegrationTemplate::initialize(display);
+}
+
+void QWaylandXdgShellIntegration::xdg_wm_base_ping(uint32_t serial)
+{
+ pong(serial);
}
QWaylandShellSurface *QWaylandXdgShellIntegration::createShellSurface(QWaylandWindow *window)
{
- return m_xdgShell->getXdgSurface(window);
+ return new QWaylandXdgSurface(mXdgShell.get(), get_xdg_surface(window->wlSurface()), window);
}
void *QWaylandXdgShellIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
index 2caa3a6e8..b7627d804 100644
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
@@ -15,7 +15,7 @@
// We mean it.
//
-#include "qwaylandxdgshell_p.h"
+#include "qwayland-xdg-shell.h"
#include <QtWaylandClient/private/qwaylandshellintegration_p.h>
@@ -23,16 +23,25 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
-class Q_WAYLANDCLIENT_EXPORT QWaylandXdgShellIntegration : public QWaylandShellIntegration
+class QWaylandXdgShell;
+
+class Q_WAYLANDCLIENT_EXPORT QWaylandXdgShellIntegration
+ : public QWaylandShellIntegrationTemplate<QWaylandXdgShellIntegration>,
+ public QtWayland::xdg_wm_base
{
public:
- QWaylandXdgShellIntegration() {}
- bool initialize(QWaylandDisplay *display) override;
+ QWaylandXdgShellIntegration();
+ ~QWaylandXdgShellIntegration() override;
QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) override;
+ bool initialize(QWaylandDisplay *display) override;
+
+protected:
+ void xdg_wm_base_ping(uint32_t serial) override;
private:
- QScopedPointer<QWaylandXdgShell> m_xdgShell;
+ QWaylandDisplay *mDisplay;
+ QScopedPointer<QWaylandXdgShell> mXdgShell;
};
}
diff --git a/src/qtwaylandscanner/CMakeLists.txt b/src/qtwaylandscanner/CMakeLists.txt
index 20a570bd6..0bd91387e 100644
--- a/src/qtwaylandscanner/CMakeLists.txt
+++ b/src/qtwaylandscanner/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qtwaylandscanner.pro.
#####################################################################
diff --git a/src/qtwaylandscanner/qtwaylandscanner.cpp b/src/qtwaylandscanner/qtwaylandscanner.cpp
index 0e9eb0e5c..6bdcb8da5 100644
--- a/src/qtwaylandscanner/qtwaylandscanner.cpp
+++ b/src/qtwaylandscanner/qtwaylandscanner.cpp
@@ -3,6 +3,7 @@
#include <QCoreApplication>
#include <QFile>
+#include <QFileInfo>
#include <QXmlStreamReader>
#include <vector>
@@ -196,7 +197,7 @@ Scanner::WaylandEvent Scanner::readEvent(QXmlStreamReader &xml, bool request)
.type = byteArrayValue(xml, "type"),
.interface = byteArrayValue(xml, "interface"),
.summary = byteArrayValue(xml, "summary"),
- .allowNull = boolValue(xml, "allowNull"),
+ .allowNull = boolValue(xml, "allow-null"),
};
event.arguments.push_back(std::move(argument));
}
@@ -422,6 +423,8 @@ bool Scanner::process()
//QByteArray preProcessorProtocolName = QByteArray(m_protocolName).replace('-', '_').toUpper();
QByteArray preProcessorProtocolName = QByteArray(m_protocolName).toUpper();
+ const QByteArray fileBaseName = QFileInfo(file).completeBaseName().toLocal8Bit();
+
std::vector<WaylandInterface> interfaces;
while (m_xml->readNextStartElement()) {
@@ -437,7 +440,7 @@ bool Scanner::process()
printf("// This file was generated by qtwaylandscanner\n");
printf("// source file is %s\n\n", qPrintable(m_protocolFilePath));
- for (auto b : qAsConst(m_includes))
+ for (auto b : std::as_const(m_includes))
printf("#include %s\n", b.constData());
auto printExportMacro = [this](const char *prefix, const QByteArray &preProcessorProtocolName) {
@@ -467,9 +470,9 @@ bool Scanner::process()
printf("\n");
printf("#include \"wayland-server-core.h\"\n");
if (m_headerPath.isEmpty())
- printf("#include \"wayland-%s-server-protocol.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData());
+ printf("#include \"wayland-%s-server-protocol.h\"\n", fileBaseName.constData());
else
- printf("#include <%s/wayland-%s-server-protocol.h>\n", m_headerPath.constData(), QByteArray(m_protocolName).replace('_', '-').constData());
+ printf("#include <%s/wayland-%s-server-protocol.h>\n", m_headerPath.constData(), fileBaseName.constData());
printf("#include <QByteArray>\n");
printf("#include <QMultiMap>\n");
printf("#include <QString>\n");
@@ -632,13 +635,14 @@ bool Scanner::process()
if (m_option == ServerCode) {
if (m_headerPath.isEmpty())
- printf("#include \"qwayland-server-%s.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData());
+ printf("#include \"qwayland-server-%s.h\"\n", fileBaseName.constData());
else
- printf("#include <%s/qwayland-server-%s.h>\n", m_headerPath.constData(), QByteArray(m_protocolName).replace('_', '-').constData());
+ printf("#include <%s/qwayland-server-%s.h>\n", m_headerPath.constData(), fileBaseName.constData());
printf("\n");
printf("QT_BEGIN_NAMESPACE\n");
printf("QT_WARNING_PUSH\n");
printf("QT_WARNING_DISABLE_GCC(\"-Wmissing-field-initializers\")\n");
+ printf("QT_WARNING_DISABLE_CLANG(\"-Wmissing-field-initializers\")\n");
printf("\n");
printf("namespace QtWaylandServer {\n");
@@ -695,7 +699,7 @@ bool Scanner::process()
printf(" %s::~%s()\n", interfaceName, interfaceName);
printf(" {\n");
- printf(" for (auto resource : qAsConst(m_resource_map))\n");
+ printf(" for (auto resource : std::as_const(m_resource_map))\n");
printf(" resource->%s_object = nullptr;\n", interfaceNameStripped);
printf("\n");
printf(" if (m_resource)\n");
@@ -936,9 +940,12 @@ bool Scanner::process()
printf(",\n");
QByteArray cType = waylandToCType(a.type, a.interface);
QByteArray qtType = waylandToQtType(a.type, a.interface, e.request);
- if (a.type == "string")
- printf(" %s.toUtf8().constData()", a.name.constData());
- else if (a.type == "array")
+ if (a.type == "string") {
+ printf(" ");
+ if (a.allowNull)
+ printf("%s.isNull() ? nullptr : ", a.name.constData());
+ printf("%s.toUtf8().constData()", a.name.constData());
+ } else if (a.type == "array")
printf(" &%s_data", a.name.constData());
else if (cType == qtType)
printf(" %s", a.name.constData());
@@ -961,9 +968,9 @@ bool Scanner::process()
printf("#define %s\n", inclusionGuard.constData());
printf("\n");
if (m_headerPath.isEmpty())
- printf("#include \"wayland-%s-client-protocol.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData());
+ printf("#include \"wayland-%s-client-protocol.h\"\n", fileBaseName.constData());
else
- printf("#include <%s/wayland-%s-client-protocol.h>\n", m_headerPath.constData(), QByteArray(m_protocolName).replace('_', '-').constData());
+ printf("#include <%s/wayland-%s-client-protocol.h>\n", m_headerPath.constData(), fileBaseName.constData());
printf("#include <QByteArray>\n");
printf("#include <QString>\n");
printf("\n");
@@ -972,6 +979,7 @@ bool Scanner::process()
printf("QT_BEGIN_NAMESPACE\n");
printf("QT_WARNING_PUSH\n");
printf("QT_WARNING_DISABLE_GCC(\"-Wmissing-field-initializers\")\n");
+ printf("QT_WARNING_DISABLE_CLANG(\"-Wmissing-field-initializers\")\n");
QByteArray clientExport;
if (m_headerPath.size())
@@ -1072,13 +1080,14 @@ bool Scanner::process()
if (m_option == ClientCode) {
if (m_headerPath.isEmpty())
- printf("#include \"qwayland-%s.h\"\n", QByteArray(m_protocolName).replace('_', '-').constData());
+ printf("#include \"qwayland-%s.h\"\n", fileBaseName.constData());
else
- printf("#include <%s/qwayland-%s.h>\n", m_headerPath.constData(), QByteArray(m_protocolName).replace('_', '-').constData());
+ printf("#include <%s/qwayland-%s.h>\n", m_headerPath.constData(), fileBaseName.constData());
printf("\n");
printf("QT_BEGIN_NAMESPACE\n");
printf("QT_WARNING_PUSH\n");
printf("QT_WARNING_DISABLE_GCC(\"-Wmissing-field-initializers\")\n");
+ printf("QT_WARNING_DISABLE_CLANG(\"-Wmissing-field-initializers\")\n");
printf("\n");
printf("namespace QtWayland {\n");
printf("\n");
@@ -1222,9 +1231,12 @@ bool Scanner::process()
} else {
QByteArray cType = waylandToCType(a.type, a.interface);
QByteArray qtType = waylandToQtType(a.type, a.interface, e.request);
- if (a.type == "string")
- printf(" %s.toUtf8().constData()", a.name.constData());
- else if (a.type == "array")
+ if (a.type == "string") {
+ printf(" ");
+ if (a.allowNull)
+ printf("%s.isNull() ? nullptr : ", a.name.constData());
+ printf("%s.toUtf8().constData()", a.name.constData());
+ } else if (a.type == "array")
printf(" &%s_data", a.name.constData());
else if (cType == qtType)
printf(" %s", a.name.constData());
diff --git a/src/shared/qwaylandinputmethodeventbuilder.cpp b/src/shared/qwaylandinputmethodeventbuilder.cpp
index 256a0c423..0f07a6958 100644
--- a/src/shared/qwaylandinputmethodeventbuilder.cpp
+++ b/src/shared/qwaylandinputmethodeventbuilder.cpp
@@ -11,10 +11,10 @@
#ifdef QT_BUILD_WAYLANDCOMPOSITOR_LIB
#include <QtWaylandCompositor/private/qwayland-server-text-input-unstable-v2.h>
-#include <QtWaylandCompositor/private/qwayland-server-text-input-unstable-v4-wip.h>
+#include <QtWaylandCompositor/private/qwayland-server-text-input-unstable-v3.h>
#else
#include <QtWaylandClient/private/qwayland-text-input-unstable-v2.h>
-#include <QtWaylandClient/private/qwayland-text-input-unstable-v4-wip.h>
+#include <QtWaylandClient/private/qwayland-text-input-unstable-v3.h>
#endif
QT_BEGIN_NAMESPACE
@@ -106,7 +106,7 @@ QInputMethodEvent *QWaylandInputMethodEventBuilder::buildCommit(const QString &t
const int absoluteOffset = absoluteCursor - cursor;
- const int cursorAfterCommit = qMin(anchor, cursor) + replacement.first + text.length();
+ const int cursorAfterCommit = qMin(anchor, cursor) + replacement.first + text.size();
surrounding.replace(qMin(anchor, cursor) + replacement.first,
qAbs(anchor - cursor) + replacement.second, text);
@@ -132,7 +132,7 @@ QInputMethodEvent *QWaylandInputMethodEventBuilder::buildPreedit(const QString &
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, indexFromWayland(text, m_preeditCursor), 1, QVariant()));
}
- for (const QInputMethodEvent::Attribute &attr : qAsConst(m_preeditStyles)) {
+ for (const QInputMethodEvent::Attribute &attr : std::as_const(m_preeditStyles)) {
int start = indexFromWayland(text, attr.start);
int length = indexFromWayland(text, attr.start + attr.length) - start;
attributes.append(QInputMethodEvent::Attribute(attr.type, start, length, attr.value));
@@ -218,55 +218,55 @@ QWaylandInputMethodContentType QWaylandInputMethodContentType::convert(Qt::Input
return QWaylandInputMethodContentType{hint, purpose};
}
-QWaylandInputMethodContentType QWaylandInputMethodContentType::convertV4(Qt::InputMethodHints hints)
+QWaylandInputMethodContentType QWaylandInputMethodContentType::convertV3(Qt::InputMethodHints hints)
{
- uint32_t hint = ZWP_TEXT_INPUT_V4_CONTENT_HINT_NONE;
- uint32_t purpose = ZWP_TEXT_INPUT_V4_CONTENT_PURPOSE_NORMAL;
+ uint32_t hint = ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE;
+ uint32_t purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL;
if (hints & Qt::ImhHiddenText)
- hint |= ZWP_TEXT_INPUT_V4_CONTENT_HINT_HIDDEN_TEXT;
+ hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_HIDDEN_TEXT;
if (hints & Qt::ImhSensitiveData)
- hint |= ZWP_TEXT_INPUT_V4_CONTENT_HINT_SENSITIVE_DATA;
+ hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA;
if ((hints & Qt::ImhNoAutoUppercase) == 0)
- hint |= ZWP_TEXT_INPUT_V4_CONTENT_HINT_AUTO_CAPITALIZATION;
+ hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_AUTO_CAPITALIZATION;
if (hints & Qt::ImhPreferNumbers) {
// Nothing yet
}
if (hints & Qt::ImhPreferUppercase)
- hint |= ZWP_TEXT_INPUT_V4_CONTENT_HINT_UPPERCASE;
+ hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_UPPERCASE;
if (hints & Qt::ImhPreferLowercase)
- hint |= ZWP_TEXT_INPUT_V4_CONTENT_HINT_LOWERCASE;
+ hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_LOWERCASE;
if ((hints & Qt::ImhNoPredictiveText) == 0) {
- hint |= (ZWP_TEXT_INPUT_V4_CONTENT_HINT_COMPLETION
- | ZWP_TEXT_INPUT_V4_CONTENT_HINT_SPELLCHECK);
+ hint |= (ZWP_TEXT_INPUT_V3_CONTENT_HINT_COMPLETION
+ | ZWP_TEXT_INPUT_V3_CONTENT_HINT_SPELLCHECK);
}
if ((hints & Qt::ImhDate) && (hints & Qt::ImhTime) == 0)
- purpose = ZWP_TEXT_INPUT_V4_CONTENT_PURPOSE_DATE;
+ purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DATE;
else if ((hints & Qt::ImhDate) && (hints & Qt::ImhTime))
- purpose = ZWP_TEXT_INPUT_V4_CONTENT_PURPOSE_DATETIME;
+ purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DATETIME;
else if ((hints & Qt::ImhDate) == 0 && (hints & Qt::ImhTime))
- purpose = ZWP_TEXT_INPUT_V4_CONTENT_PURPOSE_TIME;
+ purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TIME;
if (hints & Qt::ImhPreferLatin)
- hint |= ZWP_TEXT_INPUT_V4_CONTENT_HINT_LATIN;
+ hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_LATIN;
if (hints & Qt::ImhMultiLine)
- hint |= ZWP_TEXT_INPUT_V4_CONTENT_HINT_MULTILINE;
+ hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_MULTILINE;
if (hints & Qt::ImhDigitsOnly)
- purpose = ZWP_TEXT_INPUT_V4_CONTENT_PURPOSE_DIGITS;
+ purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DIGITS;
if (hints & Qt::ImhFormattedNumbersOnly)
- purpose = ZWP_TEXT_INPUT_V4_CONTENT_PURPOSE_NUMBER;
+ purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER;
if (hints & Qt::ImhUppercaseOnly)
- hint |= ZWP_TEXT_INPUT_V4_CONTENT_HINT_UPPERCASE;
+ hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_UPPERCASE;
if (hints & Qt::ImhLowercaseOnly)
- hint |= ZWP_TEXT_INPUT_V4_CONTENT_HINT_LOWERCASE;
+ hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_LOWERCASE;
if (hints & Qt::ImhDialableCharactersOnly)
- purpose = ZWP_TEXT_INPUT_V4_CONTENT_PURPOSE_PHONE;
+ purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PHONE;
if (hints & Qt::ImhEmailCharactersOnly)
- purpose = ZWP_TEXT_INPUT_V4_CONTENT_PURPOSE_EMAIL;
+ purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_EMAIL;
if (hints & Qt::ImhUrlCharactersOnly)
- purpose = ZWP_TEXT_INPUT_V4_CONTENT_PURPOSE_URL;
+ purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_URL;
if (hints & Qt::ImhLatinOnly)
- hint |= ZWP_TEXT_INPUT_V4_CONTENT_HINT_LATIN;
+ hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_LATIN;
return QWaylandInputMethodContentType{hint, purpose};
}
@@ -278,10 +278,10 @@ int QWaylandInputMethodEventBuilder::indexFromWayland(const QString &text, int l
if (length < 0) {
const QByteArray &utf8 = QStringView{text}.left(base).toUtf8();
- return QString::fromUtf8(utf8.left(qMax(utf8.length() + length, 0))).length();
+ return QString::fromUtf8(utf8.left(qMax(utf8.size() + length, 0))).size();
} else {
const QByteArray &utf8 = QStringView{text}.mid(base).toUtf8();
- return QString::fromUtf8(utf8.left(length)).length() + base;
+ return QString::fromUtf8(utf8.left(length)).size() + base;
}
}
@@ -304,20 +304,20 @@ int QWaylandInputMethodEventBuilder::trimmedIndexFromWayland(const QString &text
const unsigned char ch = utf8.at(start + i);
// check if current character is a utf8's initial character.
if (ch < 0x80 || ch > 0xbf)
- return QString::fromUtf8(utf8.left(start + i)).length();
+ return QString::fromUtf8(utf8.left(start + i)).size();
}
} else {
const QByteArray &utf8 = QStringView{text}.mid(base).toUtf8();
const int len = utf8.size();
const int start = length;
if (start >= len)
- return base + QString::fromUtf8(utf8).length();
+ return base + QString::fromUtf8(utf8).size();
for (int i = 0; i < 4; i++) {
const unsigned char ch = utf8.at(start - i);
// check if current character is a utf8's initial character.
if (ch < 0x80 || ch > 0xbf)
- return base + QString::fromUtf8(utf8.left(start - i)).length();
+ return base + QString::fromUtf8(utf8.left(start - i)).size();
}
}
return -1;
diff --git a/src/shared/qwaylandinputmethodeventbuilder_p.h b/src/shared/qwaylandinputmethodeventbuilder_p.h
index 1ccfa11a2..6926dac56 100644
--- a/src/shared/qwaylandinputmethodeventbuilder_p.h
+++ b/src/shared/qwaylandinputmethodeventbuilder_p.h
@@ -47,7 +47,7 @@ struct QWaylandInputMethodContentType {
uint32_t purpose = 0;
static QWaylandInputMethodContentType convert(Qt::InputMethodHints hints);
- static QWaylandInputMethodContentType convertV4(Qt::InputMethodHints hints);
+ static QWaylandInputMethodContentType convertV3(Qt::InputMethodHints hints);
};
diff --git a/src/shared/qwaylandmimehelper.cpp b/src/shared/qwaylandmimehelper.cpp
index 86d50b02a..3bbbad97b 100644
--- a/src/shared/qwaylandmimehelper.cpp
+++ b/src/shared/qwaylandmimehelper.cpp
@@ -36,9 +36,9 @@ QByteArray QWaylandMimeHelper::getByteArray(QMimeData *mimeData, const QString &
content = qvariant_cast<QColor>(mimeData->colorData()).name().toLatin1();
} else if (mimeType == QLatin1String("text/uri-list")) {
QList<QUrl> urls = mimeData->urls();
- for (int i = 0; i < urls.count(); ++i) {
+ for (int i = 0; i < urls.size(); ++i) {
content.append(urls.at(i).toEncoded());
- content.append('\n');
+ content.append("\r\n");
}
} else {
content = mimeData->data(mimeType);
diff --git a/src/shared/qwaylandsharedmemoryformathelper_p.h b/src/shared/qwaylandsharedmemoryformathelper_p.h
index 55bcfc41c..c8a9c2865 100644
--- a/src/shared/qwaylandsharedmemoryformathelper_p.h
+++ b/src/shared/qwaylandsharedmemoryformathelper_p.h
@@ -24,6 +24,7 @@ public:
case WL_SHM_FORMAT_RGB565: return QImage::Format_RGB16;
case WL_SHM_FORMAT_XRGB1555: return QImage::Format_RGB555;
case WL_SHM_FORMAT_RGB888: return QImage::Format_RGB888;
+ case WL_SHM_FORMAT_BGR888: return QImage::Format_BGR888;
case WL_SHM_FORMAT_XRGB4444: return QImage::Format_RGB444;
case WL_SHM_FORMAT_ARGB4444: return QImage::Format_ARGB4444_Premultiplied;
case WL_SHM_FORMAT_XBGR8888: return QImage::Format_RGBX8888;
@@ -76,7 +77,13 @@ private:
WL_SHM_FORMAT_XRGB2101010, //Format_RGB30,
WL_SHM_FORMAT_ARGB2101010, //Format_A2RGB30_Premultiplied,
WL_SHM_FORMAT_C8, //Format_Alpha8,
- WL_SHM_FORMAT_C8 //Format_Grayscale8,
+ WL_SHM_FORMAT_C8, //Format_Grayscale8,
+ wl_shm_format(INT_MIN), //Format_RGBX64,
+ wl_shm_format(INT_MIN), //Format_RGBA64,
+ wl_shm_format(INT_MIN), //Format_RGBA64_Premultiplied,
+ wl_shm_format(INT_MIN), //Format_Grayscale16,
+ WL_SHM_FORMAT_BGR888, //Format_BGR888
+
};
const size_t size = sizeof(formats_array) / sizeof(*formats_array);
return Array(size, formats_array);
diff --git a/sync.profile b/sync.profile
deleted file mode 100644
index c78827c24..000000000
--- a/sync.profile
+++ /dev/null
@@ -1,108 +0,0 @@
-%modules = ( # path to module name map
- "QtWaylandGlobal" => "$basedir/src/global",
- "QtWaylandCompositor" => "$basedir/src/compositor",
- "QtWaylandClient" => "$basedir/src/client",
- "QtWaylandEglClientHwIntegration" => "$basedir/src/hardwareintegration/client/wayland-egl",
- "QtWaylandEglCompositorHwIntegration" => "$basedir/src/hardwareintegration/compositor/wayland-egl",
- "QtWlShellIntegration" => "$basedir/src/plugins/shellintegration/wl-shell",
-);
-%moduleheaders = ( # restrict the module headers to those found in relative path
-);
-%classnames = (
-);
-%deprecatedheaders = (
- "QtWaylandClient" => {
- "qwaylandclientexport.h" => "QtWaylandClient/qtwaylandclientglobal.h"
- },
- "QtWaylandCompositor" => {
- "qwaylandexport.h" => "QtWaylandCompositor/qtwaylandcompositorglobal.h"
- }
-);
-%classnames = (
- "qwaylandquickextension.h" => "QWaylandQuickExtension",
-);
-%inject_headers = (
- "$basedir/src/client" => [
- "^qwayland-hardware-integration.h",
- "^qwayland-pointer-gestures-unstable-v1.h",
- "^qwayland-qt-windowmanager.h",
- "^qwayland-qt-key-unstable-v1.h" ,
- "^qwayland-server-buffer-extension.h",
- "^qwayland-surface-extension.h",
- "^qwayland-tablet-unstable-v2.h",
- "^qwayland-text-input-unstable-v1.h",
- "^qwayland-text-input-unstable-v2.h",
- "^qwayland-text-input-unstable-v4-wip.h",
- "^qwayland-qt-text-input-method-unstable-v1.h",
- "^qwayland-touch-extension.h",
- "^qwayland-wayland.h",
- "^qwayland-wp-primary-selection-unstable-v1.h",
- "^qwayland-xdg-output-unstable-v1.h",
- "^wayland-hardware-integration-client-protocol.h",
- "^wayland-pointer-gestures-unstable-v1-client-protocol.h",
- "^wayland-qt-windowmanager-client-protocol.h",
- "^wayland-qt-key-unstable-v1-client-protocol.h",
- "^wayland-server-buffer-extension-client-protocol.h",
- "^wayland-surface-extension-client-protocol.h",
- "^wayland-tablet-unstable-v2-client-protocol.h",
- "^wayland-text-input-unstable-v1-client-protocol.h",
- "^wayland-text-input-unstable-v2-client-protocol.h",
- "^wayland-text-input-unstable-v4-wip-client-protocol.h",
- "^wayland-qt-text-input-method-unstable-v1-client-protocol.h",
- "^wayland-touch-extension-client-protocol.h",
- "^wayland-wayland-client-protocol.h",
- "^wayland-wp-primary-selection-unstable-v1-client-protocol.h",
- "^wayland-xdg-output-unstable-v1-client-protocol.h",
- ],
- "$basedir/src/plugins/shellintegration/xdg-shell" => [
- "^qwayland-xdg-shell.h",
- "^qwayland-xdg-decoration-unstable-v1.h",
- "^wayland-xdg-shell-client-protocol.h",
- "^wayland-xdg-decoration-unstable-v1-client-protocol.h",
- ],
- "$basedir/src/compositor" => [
- "^qwayland-server-wayland.h",
- "^qwayland-server-hardware-integration.h",
- "^qwayland-server-idle-inhibit-unstable-v1.h",
- "^qwayland-server-ivi-application.h",
- "^qwayland-server-qt-windowmanager.h",
- "^qwayland-server-qt-key-unstable-v1.h",
- "^qwayland-server-qt-texture-sharing-unstable-v1.h",
- "^qwayland-server-scaler.h",
- "^qwayland-server-server-buffer-extension.h",
- "^qwayland-server-text-input-unstable-v2.h",
- "^qwayland-server-text-input-unstable-v4-wip.h",
- "^qwayland-server-qt-text-input-method-unstable-v1.h",
- "^qwayland-server-touch-extension.h",
- "^qwayland-server-viewporter.h",
- "^qwayland-server-xdg-decoration-unstable-v1.h",
- "^qwayland-server-xdg-output-unstable-v1.h",
- "^qwayland-server-xdg-shell.h",
- "^qwayland-server-presentation-time.h",
- "^wayland-hardware-integration-server-protocol.h",
- "^wayland-idle-inhibit-unstable-v1-server-protocol.h",
- "^wayland-ivi-application-server-protocol.h",
- "^wayland-qt-windowmanager-server-protocol.h",
- "^wayland-qt-key-unstable-v1-server-protocol.h",
- "^wayland-qt-texture-sharing-unstable-v1-server-protocol.h",
- "^wayland-scaler-server-protocol.h",
- "^wayland-server-buffer-extension-server-protocol.h",
- "^wayland-text-input-unstable-v2-server-protocol.h",
- "^wayland-text-input-unstable-v4-wip-server-protocol.h",
- "^wayland-qt-text-input-method-unstable-v1-server-protocol.h",
- "^wayland-viewporter-server-protocol.h",
- "^wayland-touch-extension-server-protocol.h",
- "^wayland-wayland-server-protocol.h",
- "^wayland-xdg-decoration-unstable-v1-server-protocol.h",
- "^wayland-xdg-output-unstable-v1-server-protocol.h",
- "^wayland-xdg-shell-server-protocol.h",
- "^qwayland-server-qt-shell-unstable-v1.h",
- "^wayland-qt-shell-unstable-v1-server-protocol.h",
- "^wayland-presentation-time-server-protocol.h",
- ],
- "$basedir/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1" => [
- "^qwayland-server-linux-dmabuf-unstable-v1.h",
- "^wayland-linux-dmabuf-unstable-v1-server-protocol.h",
- ],
-);
-@private_headers = ( qr/^qwayland-.*\.h/, qr/^wayland-.*-protocol\.h/ );
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 44ef5c3d6..fd2887624 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from tests.pro.
# special case begin
diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt
index 763b7cd4d..87e83b552 100644
--- a/tests/auto/CMakeLists.txt
+++ b/tests/auto/CMakeLists.txt
@@ -1,10 +1,13 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from auto.pro.
if(TARGET Qt::WaylandClient)
add_subdirectory(client)
endif()
if(TARGET Qt::WaylandClient AND TARGET Qt::WaylandCompositor)
- #add_subdirectory(cmake) # special case
+ add_subdirectory(cmake)
endif()
if(TARGET Qt::WaylandCompositor)
add_subdirectory(compositor)
diff --git a/tests/auto/client/CMakeLists.txt b/tests/auto/client/CMakeLists.txt
index e187d1daf..79bcd442e 100644
--- a/tests/auto/client/CMakeLists.txt
+++ b/tests/auto/client/CMakeLists.txt
@@ -1,24 +1,36 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from client.pro.
add_subdirectory(shared)
-add_subdirectory(client)
-add_subdirectory(clientextension)
-add_subdirectory(datadevicev1)
-add_subdirectory(fullscreenshellv1)
-add_subdirectory(iviapplication)
+# webOS has a modified version of QtWayland and does not support e.g. multiple window creation
+# in a single client, attempting to do so will cause a segmentation fault
+if (NOT WEBOS)
+ add_subdirectory(client)
+ add_subdirectory(clientextension)
+ add_subdirectory(cursor)
+ add_subdirectory(datadevicev1)
+ add_subdirectory(fullscreenshellv1)
+ add_subdirectory(iviapplication)
+ add_subdirectory(nooutput)
+ add_subdirectory(output)
+ add_subdirectory(primaryselectionv1)
+ add_subdirectory(reconnect)
+ add_subdirectory(seatv4)
+ add_subdirectory(seatv7)
+ add_subdirectory(seat)
+ add_subdirectory(surface)
+ add_subdirectory(tabletv2)
+ add_subdirectory(wl_connect)
+ add_subdirectory(xdgdecorationv1)
+ add_subdirectory(xdgoutput)
+ add_subdirectory(xdgshell)
+ add_subdirectory(scaling)
+endif()
add_subdirectory(multithreaded)
-add_subdirectory(nooutput)
-add_subdirectory(output)
-add_subdirectory(primaryselectionv1)
-add_subdirectory(seatv4)
-add_subdirectory(seat)
-add_subdirectory(surface)
-add_subdirectory(tabletv2)
-add_subdirectory(wl_connect)
-add_subdirectory(xdgdecorationv1)
-add_subdirectory(xdgoutput)
-add_subdirectory(xdgshell)
+
if(QT_FEATURE_im)
add_subdirectory(inputcontext)
endif()
diff --git a/tests/auto/client/client/CMakeLists.txt b/tests/auto/client/client/CMakeLists.txt
index 9373b9826..c6495eb6b 100644
--- a/tests/auto/client/client/CMakeLists.txt
+++ b/tests/auto/client/client/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from client.pro.
#####################################################################
@@ -7,7 +10,7 @@
qt_internal_add_test(tst_client
SOURCES
tst_client.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
SharedClientTest
)
diff --git a/tests/auto/client/client/tst_client.cpp b/tests/auto/client/client/tst_client.cpp
index 1c2883249..253a98b73 100644
--- a/tests/auto/client/client/tst_client.cpp
+++ b/tests/auto/client/client/tst_client.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockcompositor.h"
@@ -21,8 +21,6 @@
using namespace MockCompositor;
-static const QSize screenSize(1600, 1200);
-
constexpr int dataDeviceVersion = 1;
class TestCompositor : public WlShellCompositor {
@@ -174,21 +172,21 @@ void tst_WaylandClient::activeWindowFollowsKeyboardFocus()
Surface *s = nullptr;
QCOMPOSITOR_TRY_VERIFY(s = surface());
- exec([=] {
+ exec([&] {
sendShellSurfaceConfigure(s);
});
QCOMPOSITOR_TRY_VERIFY(window.isExposed());
QCOMPARE(window.focusInEventCount, 0);
- exec([=] {
+ exec([&] {
keyboard()->sendEnter(s);
});
QTRY_COMPARE(window.focusInEventCount, 1);
QCOMPARE(QGuiApplication::focusWindow(), &window);
QCOMPARE(window.focusOutEventCount, 0);
- exec([=] {
+ exec([&] {
keyboard()->sendLeave(s); // or implement setFocus in Keyboard
});
QTRY_COMPARE(window.focusOutEventCount, 1);
@@ -202,7 +200,7 @@ void tst_WaylandClient::events()
Surface *s = nullptr;
QCOMPOSITOR_TRY_VERIFY(s = surface());
- exec([=] {
+ exec([&] {
sendShellSurfaceConfigure(s);
});
@@ -210,7 +208,7 @@ void tst_WaylandClient::events()
QCOMPARE(window.focusInEventCount, 0);
- exec([=] {
+ exec([&] {
keyboard()->sendEnter(s);
});
QTRY_COMPARE(window.focusInEventCount, 1);
@@ -224,14 +222,14 @@ void tst_WaylandClient::events()
// xkb_v1 1 libxkbcommon compatible; to determine the xkb keycode, clients must add 8 to the key event keycode
uint keyCode = 80; // arbitrarily chosen
QCOMPARE(window.keyPressEventCount, 0);
- exec([=] {
+ exec([&] {
keyboard()->sendKey(client(), keyCode - 8, Keyboard::key_state_pressed); // related with native scan code
});
QTRY_COMPARE(window.keyPressEventCount, 1);
QCOMPARE(window.keyCode, keyCode);
QCOMPARE(window.keyReleaseEventCount, 0);
- exec([=] {
+ exec([&] {
keyboard()->sendKey(client(), keyCode - 8, Keyboard::key_state_released); // related with native scan code
});
QTRY_COMPARE(window.keyReleaseEventCount, 1);
@@ -243,12 +241,12 @@ void tst_WaylandClient::events()
});
// Note: wl_touch.frame should not be the last event in a test until QTBUG-66563 is fixed.
// See also: QTBUG-66537
- exec([=] {
+ exec([&] {
touch()->sendFrame(client());
});
QTRY_COMPARE(window.touchEventCount, 1);
- exec([=] {
+ exec([&] {
touch()->sendUp(client(), touchId);
touch()->sendFrame(client());
});
@@ -268,7 +266,7 @@ void tst_WaylandClient::events()
QTRY_COMPARE(window.mousePressPos, mousePressPos);
QCOMPARE(window.mouseReleaseEventCount, 0);
- exec([=] {
+ exec([&] {
pointer()->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
pointer()->sendFrame(client());
});
@@ -282,7 +280,7 @@ void tst_WaylandClient::backingStore()
Surface *s = nullptr;
QCOMPOSITOR_TRY_VERIFY(s = surface());
- exec([=] {
+ exec([&] {
sendShellSurfaceConfigure(s);
});
@@ -393,7 +391,7 @@ void tst_WaylandClient::touchDrag()
Surface *s = nullptr;
QCOMPOSITOR_TRY_VERIFY(s = surface());
- exec([=] {
+ exec([&] {
sendShellSurfaceConfigure(s);
});
@@ -407,7 +405,7 @@ void tst_WaylandClient::touchDrag()
&test, &DNDTest::touchDrag);
});
- exec([=] {
+ exec([&] {
keyboard()->sendEnter(s);
});
QTRY_COMPARE(QGuiApplication::focusWindow(), &window);
@@ -430,7 +428,7 @@ void tst_WaylandClient::mouseDrag()
Surface *s = nullptr;
QCOMPOSITOR_TRY_VERIFY(s = surface());
- exec([=] {
+ exec([&] {
sendShellSurfaceConfigure(s);
});
@@ -443,7 +441,7 @@ void tst_WaylandClient::mouseDrag()
&test, &DNDTest::finishMouseDrag);
});
- exec([=] {
+ exec([&] {
keyboard()->sendEnter(s);
});
QTRY_COMPARE(QGuiApplication::focusWindow(), &window);
@@ -518,7 +516,7 @@ void tst_WaylandClient::hiddenPopupParent()
// with the set_popup request.
Surface *s = nullptr;
QCOMPOSITOR_TRY_VERIFY(s = surface());
- exec([=] {
+ exec([&] {
sendShellSurfaceConfigure(s);
});
QCOMPOSITOR_TRY_VERIFY(toplevel.isExposed());
@@ -555,7 +553,7 @@ void tst_WaylandClient::glWindow()
testWindow->show();
Surface *s = nullptr;
QCOMPOSITOR_TRY_VERIFY(s = surface());
- exec([=] {
+ exec([&] {
sendShellSurfaceConfigure(s);
});
@@ -590,7 +588,7 @@ void tst_WaylandClient::longWindowTitleWithUtf16Characters()
{
QWindow window;
QString absurdlyLongTitle = QString("三").repeated(10000);
- Q_ASSERT(absurdlyLongTitle.length() == 10000); // just making sure the test isn't broken
+ Q_ASSERT(absurdlyLongTitle.size() == 10000); // just making sure the test isn't broken
window.setTitle(absurdlyLongTitle);
window.show();
QCOMPOSITOR_TRY_VERIFY(surface());
diff --git a/tests/auto/client/clientextension/CMakeLists.txt b/tests/auto/client/clientextension/CMakeLists.txt
index efcd575d2..4997b7d77 100644
--- a/tests/auto/client/clientextension/CMakeLists.txt
+++ b/tests/auto/client/clientextension/CMakeLists.txt
@@ -1,7 +1,10 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
qt_internal_add_test(tst_clientextension
SOURCES
tst_clientextension.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
SharedClientTest
)
diff --git a/tests/auto/client/clientextension/tst_clientextension.cpp b/tests/auto/client/clientextension/tst_clientextension.cpp
index 209afa822..8dd4e0d98 100644
--- a/tests/auto/client/clientextension/tst_clientextension.cpp
+++ b/tests/auto/client/clientextension/tst_clientextension.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2021 David Redondo <qt@david-redondo.de>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QSignalSpy>
#include <QtGui/private/qguiapplication_p.h>
@@ -14,17 +14,12 @@
using namespace MockCompositor;
-class TestExtension : public QWaylandClientExtensionTemplate<TestExtension>,
- public QtWayland::test_interface
+class TestExtension
+ : public QWaylandClientExtensionTemplate<TestExtension, &QtWayland::test_interface::release>,
+ public QtWayland::test_interface
{
public:
- TestExtension() : QWaylandClientExtensionTemplate<TestExtension>(1) { }
- ~TestExtension()
- {
- if (object()) {
- release();
- }
- }
+ TestExtension() : QWaylandClientExtensionTemplate(1){};
void initialize() { QWaylandClientExtension::initialize(); }
};
@@ -69,10 +64,10 @@ void tst_clientextension::createWithoutGlobal()
QSignalSpy spy(&extension, &QWaylandClientExtension::activeChanged);
QVERIFY(spy.isValid());
QVERIFY(!extension.isActive());
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
extension.initialize();
QVERIFY(!extension.isActive());
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
}
void tst_clientextension::createWithGlobalAutomatic()
@@ -83,7 +78,7 @@ void tst_clientextension::createWithGlobalAutomatic()
QSignalSpy spy(&extension, &QWaylandClientExtension::activeChanged);
QVERIFY(spy.isValid());
QTRY_VERIFY(extension.isActive());
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
}
void tst_clientextension::createWithGlobalManual()
@@ -96,7 +91,7 @@ void tst_clientextension::createWithGlobalManual()
QVERIFY(spy.isValid());
extension.initialize();
QVERIFY(extension.isActive());
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
}
void tst_clientextension::globalBecomesAvailable()
@@ -106,7 +101,7 @@ void tst_clientextension::globalBecomesAvailable()
QVERIFY(spy.isValid());
exec([this] { add<TestGlobal>(); });
QTRY_VERIFY(extension.isActive());
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
}
void tst_clientextension::globalRemoved()
@@ -120,8 +115,20 @@ void tst_clientextension::globalRemoved()
exec([this] { removeAll<TestGlobal>(); });
QTRY_VERIFY(!extension.isActive());
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
+}
+
+int main(int argc, char **argv)
+{
+ QTemporaryDir tmpRuntimeDir;
+ setenv("XDG_RUNTIME_DIR", tmpRuntimeDir.path().toLocal8Bit(), 1);
+ setenv("QT_QPA_PLATFORM", "wayland", 1);
+ setenv("QT_WAYLAND_DONT_CHECK_SHELL_INTEGRATION", "1", 1);
+
+ tst_clientextension tc;
+ QGuiApplication app(argc, argv);
+ QTEST_SET_MAIN_SOURCE_PATH
+ return QTest::qExec(&tc, argc, argv);
}
-QCOMPOSITOR_TEST_MAIN(tst_clientextension)
#include "tst_clientextension.moc"
diff --git a/tests/auto/client/cursor/CMakeLists.txt b/tests/auto/client/cursor/CMakeLists.txt
new file mode 100644
index 000000000..a7814a2c2
--- /dev/null
+++ b/tests/auto/client/cursor/CMakeLists.txt
@@ -0,0 +1,11 @@
+#####################################################################
+## tst_cursor Test:
+#####################################################################
+
+qt_internal_add_test(tst_wayland_cursor
+ SOURCES
+ tst_cursor.cpp
+ cursorshapev1.cpp
+ LIBRARIES
+ SharedClientTest
+)
diff --git a/tests/auto/client/cursor/cursorshapev1.cpp b/tests/auto/client/cursor/cursorshapev1.cpp
new file mode 100644
index 000000000..93750df95
--- /dev/null
+++ b/tests/auto/client/cursor/cursorshapev1.cpp
@@ -0,0 +1,47 @@
+// Copyright (C) 2023 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "cursorshapev1.h"
+
+namespace MockCompositor {
+
+CursorShapeManager::CursorShapeManager(CoreCompositor *compositor, int version)
+ : QtWaylandServer::wp_cursor_shape_manager_v1(compositor->m_display, version)
+{
+}
+
+void CursorShapeManager::wp_cursor_shape_manager_v1_get_pointer(Resource *resource, uint32_t id, wl_resource *pointer)
+{
+ auto *p = fromResource<Pointer>(pointer);
+ auto *cursorShape = new CursorShapeDevice(p, resource->client(), id, resource->version());
+ connect(cursorShape, &QObject::destroyed, this, [this, cursorShape]() {
+ m_cursorDevices.removeOne(cursorShape);
+ });
+ m_cursorDevices << cursorShape;
+}
+
+CursorShapeDevice::CursorShapeDevice(Pointer *pointer, wl_client *client, int id, int version)
+ : QtWaylandServer::wp_cursor_shape_device_v1(client, id, version)
+ , m_pointer(pointer)
+{
+}
+
+void CursorShapeDevice::wp_cursor_shape_device_v1_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource)
+ delete this;
+}
+
+void CursorShapeDevice::wp_cursor_shape_device_v1_destroy(Resource *resource)
+{
+ wl_resource_destroy(resource->handle);
+}
+
+void CursorShapeDevice::wp_cursor_shape_device_v1_set_shape(Resource *resource, uint32_t serial, uint32_t shape)
+{
+ Q_UNUSED(resource);
+ m_currentShape = static_cast<CursorShapeDevice::shape>(shape);
+ emit setCursor(serial);
+}
+
+}
diff --git a/tests/auto/client/cursor/cursorshapev1.h b/tests/auto/client/cursor/cursorshapev1.h
new file mode 100644
index 000000000..0befc3223
--- /dev/null
+++ b/tests/auto/client/cursor/cursorshapev1.h
@@ -0,0 +1,44 @@
+// Copyright (C) 2023 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef MOCKCOMPOSITOR_CURSORSHAPE_H
+#define MOCKCOMPOSITOR_CURSORSHAPE_H
+
+#include "coreprotocol.h"
+#include <qwayland-server-cursor-shape-v1.h>
+
+namespace MockCompositor {
+
+class CursorShapeDevice;
+
+class CursorShapeManager : public Global, public QtWaylandServer::wp_cursor_shape_manager_v1
+{
+ Q_OBJECT
+public:
+ explicit CursorShapeManager(CoreCompositor *compositor, int version = 1);
+ QList<CursorShapeDevice *> m_cursorDevices;
+
+protected:
+ void wp_cursor_shape_manager_v1_get_pointer(Resource *resource, uint32_t id, wl_resource *pointer) override;
+};
+
+class CursorShapeDevice : public QObject, public QtWaylandServer::wp_cursor_shape_device_v1
+{
+ Q_OBJECT
+public:
+ explicit CursorShapeDevice(Pointer *pointer, wl_client *client, int id, int version);
+ Pointer *m_pointer;
+ shape m_currentShape = shape_default;
+
+Q_SIGNALS:
+ void setCursor(uint serial);
+
+protected:
+ void wp_cursor_shape_device_v1_destroy_resource(Resource *resource) override;
+ void wp_cursor_shape_device_v1_destroy(Resource *resource) override;
+ void wp_cursor_shape_device_v1_set_shape(Resource *resource, uint32_t serial, uint32_t shape) override;
+};
+
+}
+
+#endif
diff --git a/tests/auto/client/cursor/tst_cursor.cpp b/tests/auto/client/cursor/tst_cursor.cpp
new file mode 100644
index 000000000..070e062f6
--- /dev/null
+++ b/tests/auto/client/cursor/tst_cursor.cpp
@@ -0,0 +1,103 @@
+// Copyright (C) 2023 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "mockcompositor.h"
+#include <QtGui/QRasterWindow>
+#include <QtGui/qpa/qplatformnativeinterface.h>
+#include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
+#include <QtWaylandClient/private/qwaylandwindow_p.h>
+
+#include "cursorshapev1.h"
+
+using namespace MockCompositor;
+
+class tst_cursor : public QObject, private DefaultCompositor
+{
+ Q_OBJECT
+public:
+ tst_cursor();
+ CursorShapeDevice* cursorShape();
+private slots:
+ void init();
+ void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); }
+ void setCursor();
+};
+
+tst_cursor::tst_cursor()
+{
+ exec([this] {
+ m_config.autoConfigure = true;
+ add<CursorShapeManager>(1);
+ });
+}
+
+CursorShapeDevice* tst_cursor::cursorShape()
+{
+ auto manager = get<CursorShapeManager>();
+ if (!manager->m_cursorDevices.count())
+ return nullptr;
+ return manager->m_cursorDevices[0];
+}
+
+void tst_cursor::init()
+{
+ setenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1", 1);
+}
+
+void tst_cursor::setCursor()
+{
+ QCOMPOSITOR_TRY_VERIFY(cursorShape());
+ QSignalSpy setCursorSpy(exec([&] { return pointer(); }), &Pointer::setCursor);
+ QSignalSpy setCursorShapeSpy(exec([&] { return cursorShape(); }), &CursorShapeDevice::setCursor);
+
+ QRasterWindow window;
+ window.resize(64, 64);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ uint enterSerial = exec([&] {
+ return pointer()->sendEnter(xdgSurface()->m_surface, {32, 32});
+ });
+ setCursorShapeSpy.wait();
+ // verify we got given a cursor on enter
+ QCOMPOSITOR_COMPARE(cursorShape()->m_currentShape, CursorShapeDevice::shape_default);
+ QVERIFY(setCursorSpy.isEmpty());
+ QCOMPARE(setCursorShapeSpy.takeFirst().at(0).toUInt(), enterSerial);
+
+ // client sets a different shape
+ window.setCursor(QCursor(Qt::WaitCursor));
+ QVERIFY(setCursorShapeSpy.wait());
+ QCOMPOSITOR_COMPARE(cursorShape()->m_currentShape, CursorShapeDevice::shape_wait);
+
+ setCursorShapeSpy.clear();
+
+ // client hides the cursor
+ // CursorShape will not be used, instead, it uses the old path
+ window.setCursor(QCursor(Qt::BlankCursor));
+ QVERIFY(setCursorSpy.wait());
+ QVERIFY(setCursorShapeSpy.isEmpty());
+ QCOMPOSITOR_VERIFY(!pointer()->cursorSurface());
+
+ // same for bitmaps
+ QPixmap myCustomPixmap(10, 10);
+ myCustomPixmap.fill(Qt::red);
+ window.setCursor(QCursor(myCustomPixmap));
+ QVERIFY(setCursorSpy.wait());
+ QVERIFY(setCursorShapeSpy.isEmpty());
+
+ // set a shape again
+ window.setCursor(QCursor(Qt::BusyCursor));
+ QVERIFY(setCursorShapeSpy.wait());
+ QCOMPOSITOR_COMPARE(cursorShape()->m_currentShape, CursorShapeDevice::shape_progress);
+
+ setCursorShapeSpy.clear();
+
+ // set the same bitmap again, make sure switching from new to old path works
+ // even if the bitmap cursor's properties haven't changed
+ window.setCursor(QCursor(myCustomPixmap));
+ QVERIFY(setCursorSpy.wait());
+ QVERIFY(setCursorShapeSpy.isEmpty());
+}
+
+QCOMPOSITOR_TEST_MAIN(tst_cursor)
+#include "tst_cursor.moc"
diff --git a/tests/auto/client/datadevicev1/CMakeLists.txt b/tests/auto/client/datadevicev1/CMakeLists.txt
index 9f87eb996..cfc2f5beb 100644
--- a/tests/auto/client/datadevicev1/CMakeLists.txt
+++ b/tests/auto/client/datadevicev1/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from datadevicev1.pro.
#####################################################################
@@ -7,6 +10,6 @@
qt_internal_add_test(tst_datadevicev1
SOURCES
tst_datadevicev1.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
SharedClientTest
)
diff --git a/tests/auto/client/datadevicev1/tst_datadevicev1.cpp b/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
index d4dfa2da0..50d78130a 100644
--- a/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
+++ b/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
@@ -1,9 +1,8 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockcompositor.h"
-#include <QtOpenGL/QOpenGLWindow>
#include <QtGui/QRasterWindow>
#include <QtGui/QClipboard>
#include <QtGui/QDrag>
@@ -32,6 +31,8 @@ private slots:
void initTestCase();
void pasteAscii();
void pasteUtf8();
+ void pasteMozUrl();
+ void pasteSingleUtf8MozUrl();
void destroysPreviousSelection();
void destroysSelectionWithSurface();
void destroysSelectionOnLeave();
@@ -64,13 +65,13 @@ void tst_datadevicev1::pasteAscii()
exec([&] {
auto *client = xdgSurface()->resource()->client();
auto *offer = dataDevice()->sendDataOffer(client, {"text/plain"});
- connect(offer, &DataOffer::receive, [](QString mimeType, int fd) {
+ connect(offer, &DataOffer::receive, offer, [](QString mimeType, int fd) {
QFile file;
file.open(fd, QIODevice::WriteOnly, QFile::FileHandleFlag::AutoCloseHandle);
QCOMPARE(mimeType, "text/plain");
file.write(QByteArray("normal ascii"));
file.close();
- });
+ }, Qt::DirectConnection);
dataDevice()->sendSelection(offer);
auto *surface = xdgSurface()->m_surface;
@@ -102,13 +103,13 @@ void tst_datadevicev1::pasteUtf8()
exec([&] {
auto *client = xdgSurface()->resource()->client();
auto *offer = dataDevice()->sendDataOffer(client, {"text/plain", "text/plain;charset=utf-8"});
- connect(offer, &DataOffer::receive, [](QString mimeType, int fd) {
+ connect(offer, &DataOffer::receive, offer, [](QString mimeType, int fd) {
QFile file;
file.open(fd, QIODevice::WriteOnly, QFile::FileHandleFlag::AutoCloseHandle);
QCOMPARE(mimeType, "text/plain;charset=utf-8");
file.write(QByteArray("face with tears of joy: 😂"));
file.close();
- });
+ }, Qt::DirectConnection);
dataDevice()->sendSelection(offer);
auto *surface = xdgSurface()->m_surface;
@@ -124,6 +125,90 @@ void tst_datadevicev1::pasteUtf8()
QTRY_COMPARE(window.m_text, "face with tears of joy: 😂");
}
+void tst_datadevicev1::pasteMozUrl()
+{
+ class Window : public QRasterWindow {
+ public:
+ void mousePressEvent(QMouseEvent *) override { m_urls = QGuiApplication::clipboard()->mimeData()->urls(); }
+ QList<QUrl> m_urls;
+ };
+
+ Window window;
+ window.resize(64, 64);
+ window.show();
+
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+ exec([&] {
+ auto *client = xdgSurface()->resource()->client();
+ auto *offer = dataDevice()->sendDataOffer(client, {"text/x-moz-url"});
+ connect(offer, &DataOffer::receive, offer, [](QString mimeType, int fd) {
+ QFile file;
+ file.open(fd, QIODevice::WriteOnly, QFile::FileHandleFlag::AutoCloseHandle);
+ QCOMPARE(mimeType, "text/x-moz-url");
+ const QString content("https://www.qt.io/\nQt\nhttps://www.example.com/\nExample Website");
+ // Need UTF-16.
+ file.write(reinterpret_cast<const char *>(content.data()), content.size() * 2);
+ file.close();
+ }, Qt::DirectConnection);
+ dataDevice()->sendSelection(offer);
+
+ auto *surface = xdgSurface()->m_surface;
+ keyboard()->sendEnter(surface); // Need to set keyboard focus according to protocol
+
+ pointer()->sendEnter(surface, {32, 32});
+ pointer()->sendFrame(client);
+ pointer()->sendButton(client, BTN_LEFT, 1);
+ pointer()->sendFrame(client);
+ pointer()->sendButton(client, BTN_LEFT, 0);
+ pointer()->sendFrame(client);
+ });
+
+ QTRY_COMPARE(window.m_urls.count(), 2);
+ QCOMPARE(window.m_urls.at(0), QUrl("https://www.qt.io/"));
+ QCOMPARE(window.m_urls.at(1), QUrl("https://www.example.com/"));
+}
+
+void tst_datadevicev1::pasteSingleUtf8MozUrl()
+{
+ class Window : public QRasterWindow {
+ public:
+ void mousePressEvent(QMouseEvent *) override { m_urls = QGuiApplication::clipboard()->mimeData()->urls(); }
+ QList<QUrl> m_urls;
+ };
+
+ Window window;
+ window.resize(64, 64);
+ window.show();
+
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+ exec([&] {
+ auto *client = xdgSurface()->resource()->client();
+ auto *offer = dataDevice()->sendDataOffer(client, {"text/x-moz-url"});
+ connect(offer, &DataOffer::receive, offer, [](QString mimeType, int fd) {
+ QFile file;
+ file.open(fd, QIODevice::WriteOnly, QFile::FileHandleFlag::AutoCloseHandle);
+ QCOMPARE(mimeType, "text/x-moz-url");
+ const QString content("https://www.qt.io/");
+ file.write(content.toUtf8());
+ file.close();
+ }, Qt::DirectConnection);
+ dataDevice()->sendSelection(offer);
+
+ auto *surface = xdgSurface()->m_surface;
+ keyboard()->sendEnter(surface); // Need to set keyboard focus according to protocol
+
+ pointer()->sendEnter(surface, {32, 32});
+ pointer()->sendFrame(client);
+ pointer()->sendButton(client, BTN_LEFT, 1);
+ pointer()->sendFrame(client);
+ pointer()->sendButton(client, BTN_LEFT, 0);
+ pointer()->sendFrame(client);
+ });
+
+ QTRY_COMPARE(window.m_urls.count(), 1);
+ QCOMPARE(window.m_urls.at(0), QUrl("https://www.qt.io/"));
+}
+
void tst_datadevicev1::destroysPreviousSelection()
{
QRasterWindow window;
@@ -213,7 +298,7 @@ void tst_datadevicev1::destroysSelectionOnLeave()
keyboard()->sendLeave(surface);
});
- QTRY_COMPARE(dataChangedSpy.count(), 1);
+ QTRY_COMPARE(dataChangedSpy.size(), 1);
QVERIFY(!QGuiApplication::clipboard()->mimeData(QClipboard::Clipboard)->hasText());
}
diff --git a/tests/auto/client/fullscreenshellv1/CMakeLists.txt b/tests/auto/client/fullscreenshellv1/CMakeLists.txt
index 4c9a99406..7bc14c50d 100644
--- a/tests/auto/client/fullscreenshellv1/CMakeLists.txt
+++ b/tests/auto/client/fullscreenshellv1/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from fullscreenshellv1.pro.
#####################################################################
@@ -7,6 +10,6 @@
qt_internal_add_test(tst_client_fullscreenshellv1
SOURCES
tst_fullscreenshellv1.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
SharedClientTest
)
diff --git a/tests/auto/client/fullscreenshellv1/tst_fullscreenshellv1.cpp b/tests/auto/client/fullscreenshellv1/tst_fullscreenshellv1.cpp
index c48e5532b..ba897d53f 100644
--- a/tests/auto/client/fullscreenshellv1/tst_fullscreenshellv1.cpp
+++ b/tests/auto/client/fullscreenshellv1/tst_fullscreenshellv1.cpp
@@ -1,7 +1,7 @@
// Copyright (C) 2021 David Edmundson <davidedmundson@kde.org>
// Copyright (C) 2018 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockcompositor.h"
@@ -25,7 +25,7 @@ void tst_WaylandClientFullScreenShellV1::createDestroyWindow()
window.resize(800, 600);
window.show();
- QCOMPOSITOR_TRY_VERIFY(fullScreenShellV1()->surfaces().count() == 1);
+ QCOMPOSITOR_TRY_VERIFY(fullScreenShellV1()->surfaces().size() == 1);
QCOMPOSITOR_VERIFY(surface(0));
window.destroy();
diff --git a/tests/auto/client/inputcontext/CMakeLists.txt b/tests/auto/client/inputcontext/CMakeLists.txt
index 06ea08e01..66e5ca825 100644
--- a/tests/auto/client/inputcontext/CMakeLists.txt
+++ b/tests/auto/client/inputcontext/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from inputcontext.pro.
#####################################################################
@@ -7,6 +10,6 @@
qt_internal_add_test(tst_inputcontext
SOURCES
tst_inputcontext.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
SharedClientTest
)
diff --git a/tests/auto/client/inputcontext/tst_inputcontext.cpp b/tests/auto/client/inputcontext/tst_inputcontext.cpp
index 9e3d75e0f..47a453bb5 100644
--- a/tests/auto/client/inputcontext/tst_inputcontext.cpp
+++ b/tests/auto/client/inputcontext/tst_inputcontext.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockcompositor.h"
#include "textinput.h"
@@ -36,9 +36,9 @@ private:
{
exec([&] {
QList<arg_type *> extensions = getAll<arg_type>();
- if (extensions.length() > 1)
+ if (extensions.size() > 1)
QFAIL("Requested type is a singleton, hence there should not be more then one object returned");
- if (extensions.length() == 0)
+ if (extensions.size() == 0)
add<arg_type>();
});
}
@@ -48,9 +48,9 @@ private:
{
exec([&] {
QList<arg_type *> extensions = getAll<arg_type>();
- if (extensions.length() > 1)
+ if (extensions.size() > 1)
QFAIL("Requested type is a singleton, hence there should not be more then one object returned");
- if (extensions.length() == 1)
+ if (extensions.size() == 1)
remove(extensions.first());
});
}
@@ -98,8 +98,9 @@ void tst_inputcontext::selectingInputContext_data()
// Test compositor with Text Input extension
QTest::newRow("ibus:text-input") << QByteArray("ibus") << mIbusModule;
QTest::newRow("compose:text-input") << QByteArray("compose") << mComposeModule;
- QTest::newRow("empty:text-input") << QByteArray("") << mComposeModule;
+ QTest::newRow("empty:text-input") << QByteArray("") << mTextInputModule;
QTest::newRow("null:text-input") << QByteArray() << mTextInputModule;
+ QTest::newRow("wayland:text-input") << QByteArray("wayland") << mTextInputModule;
QTest::newRow("fake:text-input") << QByteArray("fake") << mComposeModule;
}
diff --git a/tests/auto/client/iviapplication/CMakeLists.txt b/tests/auto/client/iviapplication/CMakeLists.txt
index 427322777..a138d3429 100644
--- a/tests/auto/client/iviapplication/CMakeLists.txt
+++ b/tests/auto/client/iviapplication/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from iviapplication.pro.
#####################################################################
@@ -7,6 +10,6 @@
qt_internal_add_test(tst_client_iviapplication
SOURCES
tst_iviapplication.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
SharedClientTest
)
diff --git a/tests/auto/client/iviapplication/tst_iviapplication.cpp b/tests/auto/client/iviapplication/tst_iviapplication.cpp
index e5545ff29..082149f36 100644
--- a/tests/auto/client/iviapplication/tst_iviapplication.cpp
+++ b/tests/auto/client/iviapplication/tst_iviapplication.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockcompositor.h"
@@ -44,7 +44,7 @@ void tst_WaylandClientIviApplication::configure()
// Unconfigured ivi surfaces decide their own size
QTRY_COMPARE(window.frameGeometry(), QRect(QPoint(), QSize(32, 32)));
- exec([=] {
+ exec([&] {
iviSurface()->send_configure(123, 456);
});
QTRY_COMPARE(window.frameGeometry(), QRect(QPoint(), QSize(123, 456)));
@@ -62,7 +62,7 @@ void tst_WaylandClientIviApplication::uniqueIviIds()
QCOMPOSITOR_TRY_VERIFY(iviSurface(0));
QCOMPOSITOR_TRY_VERIFY(iviSurface(1));
- exec([=] {
+ exec([&] {
QVERIFY(iviSurface(0)->m_iviId != iviSurface(1)->m_iviId);
});
}
diff --git a/tests/auto/client/multithreaded/CMakeLists.txt b/tests/auto/client/multithreaded/CMakeLists.txt
index 49d93297f..62d935905 100644
--- a/tests/auto/client/multithreaded/CMakeLists.txt
+++ b/tests/auto/client/multithreaded/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from multithreaded.pro.
#####################################################################
@@ -7,6 +10,6 @@
qt_internal_add_test(tst_multithreaded
SOURCES
tst_multithreaded.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
SharedClientTest
)
diff --git a/tests/auto/client/multithreaded/tst_multithreaded.cpp b/tests/auto/client/multithreaded/tst_multithreaded.cpp
index 562d9b388..a1a7d367e 100644
--- a/tests/auto/client/multithreaded/tst_multithreaded.cpp
+++ b/tests/auto/client/multithreaded/tst_multithreaded.cpp
@@ -1,6 +1,6 @@
// Copyright (C) 2018 The Qt Company Ltd.
// Copyright (C) 2020 UBports Foundataion.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <unistd.h>
#include <poll.h>
diff --git a/tests/auto/client/nooutput/CMakeLists.txt b/tests/auto/client/nooutput/CMakeLists.txt
index ab9dd3a6d..eeee57909 100644
--- a/tests/auto/client/nooutput/CMakeLists.txt
+++ b/tests/auto/client/nooutput/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from nooutput.pro.
#####################################################################
@@ -7,6 +10,6 @@
qt_internal_add_test(tst_nooutput
SOURCES
tst_nooutput.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
SharedClientTest
)
diff --git a/tests/auto/client/nooutput/tst_nooutput.cpp b/tests/auto/client/nooutput/tst_nooutput.cpp
index 35b4e0e95..1d8a838f3 100644
--- a/tests/auto/client/nooutput/tst_nooutput.cpp
+++ b/tests/auto/client/nooutput/tst_nooutput.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockcompositor.h"
#include <QtGui/QScreen>
@@ -41,7 +41,7 @@ void tst_nooutput::noScreens()
// The window should not be exposed before the first xdg_surface configure event
QTRY_VERIFY(!window.isExposed());
- exec([=] {
+ exec([&] {
xdgToplevel()->sendConfigure({0, 0}, {}); // Let the window decide the size
xdgSurface()->sendConfigure(nextSerial());
});
diff --git a/tests/auto/client/output/CMakeLists.txt b/tests/auto/client/output/CMakeLists.txt
index 45b6be4fb..a9c5cea3c 100644
--- a/tests/auto/client/output/CMakeLists.txt
+++ b/tests/auto/client/output/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from output.pro.
#####################################################################
@@ -7,6 +10,6 @@
qt_internal_add_test(tst_output
SOURCES
tst_output.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
SharedClientTest
)
diff --git a/tests/auto/client/output/tst_output.cpp b/tests/auto/client/output/tst_output.cpp
index 3509a7771..2129e167b 100644
--- a/tests/auto/client/output/tst_output.cpp
+++ b/tests/auto/client/output/tst_output.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockcompositor.h"
#include <QtGui/QScreen>
@@ -48,7 +48,7 @@ void tst_output::primaryScreen()
void tst_output::secondaryHiDpiScreen()
{
- exec([=] {
+ exec([&] {
OutputData d;
d.position = {1920, 0}; // in global compositor space (not pixels)
d.mode.resolution = {800, 640};
@@ -74,15 +74,15 @@ void tst_output::secondaryHiDpiScreen()
QCOMPARE(screen->geometry(), QRect(QPoint(1920, 0), QSize(400, 320)));
QCOMPARE(screen->virtualGeometry(), QRect(QPoint(0, 0), QSize(1920 + 800 / 2, 1080)));
- exec([=] { remove(output(1)); });
+ exec([&] { remove(output(1)); });
}
// QTBUG-62044
void tst_output::addScreenWithGeometryChange()
{
- const QPoint initialPosition = exec([=] { return output(0)->m_data.position; });
+ const QPoint initialPosition = exec([&] { return output(0)->m_data.position; });
- exec([=] {
+ exec([&] {
auto *oldOutput = output(0);
auto *newOutput = add<Output>();
newOutput->m_data.mode.resolution = {1280, 720};
@@ -98,7 +98,7 @@ void tst_output::addScreenWithGeometryChange()
QTRY_COMPARE(QGuiApplication::primaryScreen()->geometry(), QRect(QPoint(1280, 0), QSize(1920, 1080)));
// Remove the extra output and move the old one back
- exec([=] {
+ exec([&] {
remove(output(1));
output()->m_data.position = initialPosition;
output()->sendGeometry();
@@ -119,7 +119,7 @@ void tst_output::windowScreens()
QScreen *primaryScreen = QGuiApplication::screens().first();
QCOMPARE(window.screen(), primaryScreen);
- exec([=] { add<Output>(); });
+ exec([&] { add<Output>(); });
QTRY_COMPARE(QGuiApplication::screens().size(), 2);
QScreen *secondaryScreen = QGuiApplication::screens().at(1);
@@ -128,19 +128,19 @@ void tst_output::windowScreens()
window.setScreen(secondaryScreen);
QCOMPARE(window.screen(), secondaryScreen);
- exec([=] {
+ exec([&] {
xdgToplevel()->surface()->sendEnter(output(0));
xdgToplevel()->surface()->sendEnter(output(1));
});
QTRY_COMPARE(window.screen(), primaryScreen);
- exec([=] {
+ exec([&] {
xdgToplevel()->surface()->sendLeave(output(0));
});
QTRY_COMPARE(window.screen(), secondaryScreen);
- exec([=] {
+ exec([&] {
remove(output(1));
});
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
@@ -186,7 +186,7 @@ void tst_output::removePrimaryScreen()
// QTBUG-72828
void tst_output::screenOrder()
{
- exec([=] {
+ exec([&] {
add<Output>()->m_data.model = "Screen 1";
add<Output>()->m_data.model = "Screen 2";
});
@@ -197,7 +197,7 @@ void tst_output::screenOrder()
QCOMPARE(screens[1]->model(), "Screen 1");
QCOMPARE(screens[2]->model(), "Screen 2");
- exec([=] {
+ exec([&] {
remove(output(2));
remove(output(1));
});
@@ -215,8 +215,8 @@ void tst_output::removeAllScreens()
const QString wlOutputPrimaryScreenModel = QGuiApplication::primaryScreen()->model();
// Get screen info so we can restore it after
- auto screenInfo = exec([=] { return output()->m_data; });
- exec([=] { remove(output()); });
+ auto screenInfo = exec([&] { return output()->m_data; });
+ exec([&] { remove(output()); });
// Make sure the wl_output is actually removed before we continue
QTRY_VERIFY(!QGuiApplication::primaryScreen() || QGuiApplication::primaryScreen()->model() != wlOutputPrimaryScreenModel);
@@ -226,7 +226,7 @@ void tst_output::removeAllScreens()
window2.resize(400, 320);
window2.show();
- exec([=] { add<Output>(screenInfo); });
+ exec([&] { add<Output>(screenInfo); });
// Things should be back to normal
QTRY_VERIFY(QGuiApplication::primaryScreen());
diff --git a/tests/auto/client/primaryselectionv1/CMakeLists.txt b/tests/auto/client/primaryselectionv1/CMakeLists.txt
index c95a7fb18..0235ae33e 100644
--- a/tests/auto/client/primaryselectionv1/CMakeLists.txt
+++ b/tests/auto/client/primaryselectionv1/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from primaryselectionv1.pro.
#####################################################################
@@ -7,6 +10,6 @@
qt_internal_add_test(tst_primaryselectionv1
SOURCES
tst_primaryselectionv1.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
SharedClientTest
)
diff --git a/tests/auto/client/primaryselectionv1/tst_primaryselectionv1.cpp b/tests/auto/client/primaryselectionv1/tst_primaryselectionv1.cpp
index d947d3006..53a048a35 100644
--- a/tests/auto/client/primaryselectionv1/tst_primaryselectionv1.cpp
+++ b/tests/auto/client/primaryselectionv1/tst_primaryselectionv1.cpp
@@ -1,11 +1,10 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockcompositor.h"
#include <qwayland-server-wp-primary-selection-unstable-v1.h>
-#include <QtOpenGL/QOpenGLWindow>
#include <QtGui/QRasterWindow>
#include <QtGui/QClipboard>
#include <QtCore/private/qcore_unix_p.h>
@@ -130,11 +129,6 @@ protected:
{
wl_resource_destroy(resource->handle);
}
- void zwp_primary_selection_device_v1_destroy_resource(Resource *resource) override
- {
- Q_UNUSED(resource);
- delete this;
- }
};
class PrimarySelectionDeviceManagerV1 : public Global, public QtWaylandServer::zwp_primary_selection_device_manager_v1
@@ -145,9 +139,13 @@ public:
: QtWaylandServer::zwp_primary_selection_device_manager_v1(compositor->m_display, version)
, m_version(version)
{}
+ ~PrimarySelectionDeviceManagerV1() override
+ {
+ qDeleteAll(m_devices);
+ }
bool isClean() override
{
- for (auto *device : qAsConst(m_devices)) {
+ for (auto *device : std::as_const(m_devices)) {
// The client should not leak selection offers, i.e. if this fails, there is a missing
// zwp_primary_selection_offer_v1.destroy request
if (!device->m_sentSelectionOffers.empty())
@@ -262,7 +260,7 @@ void tst_primaryselectionv1::createsPrimaryDevice()
void tst_primaryselectionv1::createsPrimaryDeviceForNewSeats()
{
- exec([=] { add<Seat>(); });
+ exec([&] { add<Seat>(); });
QCOMPOSITOR_TRY_VERIFY(primarySelectionDevice(1));
}
@@ -292,13 +290,13 @@ void tst_primaryselectionv1::pasteAscii()
auto *device = primarySelectionDevice();
auto *offer = device->sendDataOffer({"text/plain"});
- connect(offer, &PrimarySelectionOfferV1::receive, [](QString mimeType, int fd) {
+ connect(offer, &PrimarySelectionOfferV1::receive, offer, [](QString mimeType, int fd) {
QFile file;
file.open(fd, QIODevice::WriteOnly, QFile::FileHandleFlag::AutoCloseHandle);
QCOMPARE(mimeType, "text/plain");
file.write(QByteArray("normal ascii"));
file.close();
- });
+ }, Qt::DirectConnection);
device->sendSelection(offer);
pointer()->sendEnter(surface, {32, 32});
@@ -338,13 +336,13 @@ void tst_primaryselectionv1::pasteUtf8()
auto *device = primarySelectionDevice();
auto *offer = device->sendDataOffer({"text/plain", "text/plain;charset=utf-8"});
- connect(offer, &PrimarySelectionOfferV1::receive, [](QString mimeType, int fd) {
+ connect(offer, &PrimarySelectionOfferV1::receive, offer, [](QString mimeType, int fd) {
QFile file;
file.open(fd, QIODevice::WriteOnly, QFile::FileHandleFlag::AutoCloseHandle);
QCOMPARE(mimeType, "text/plain;charset=utf-8");
file.write(QByteArray("face with tears of joy: 😂"));
file.close();
- });
+ }, Qt::DirectConnection);
device->sendSelection(offer);
pointer()->sendEnter(surface, {32, 32});
@@ -409,7 +407,7 @@ void tst_primaryselectionv1::destroysSelectionOnLeave()
keyboard()->sendLeave(surface);
});
- QTRY_COMPARE(selectionChangedSpy.count(), 1);
+ QTRY_COMPARE(selectionChangedSpy.size(), 1);
QVERIFY(!QGuiApplication::clipboard()->mimeData(QClipboard::Selection)->hasText());
}
@@ -466,7 +464,7 @@ void tst_primaryselectionv1::copy()
pastedBuf.append(buf, n);
}
});
- });
+ }, Qt::DirectConnection);
});
QCOMPOSITOR_TRY_VERIFY(pastedBuf.size()); // this assumes we got everything in one read
diff --git a/tests/auto/client/reconnect/CMakeLists.txt b/tests/auto/client/reconnect/CMakeLists.txt
new file mode 100644
index 000000000..07d4c7143
--- /dev/null
+++ b/tests/auto/client/reconnect/CMakeLists.txt
@@ -0,0 +1,11 @@
+#####################################################################
+## tst_wl_reconnect Test:
+#####################################################################
+
+qt_internal_add_test(tst_wl_reconnect
+ SOURCES
+ wl-socket.c
+ tst_reconnect.cpp
+ LIBRARIES
+ SharedClientTest
+)
diff --git a/tests/auto/client/reconnect/tst_reconnect.cpp b/tests/auto/client/reconnect/tst_reconnect.cpp
new file mode 100644
index 000000000..ff806af6a
--- /dev/null
+++ b/tests/auto/client/reconnect/tst_reconnect.cpp
@@ -0,0 +1,253 @@
+// Copyright (C) 2023 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "mockcompositor.h"
+
+#include <QBackingStore>
+#include <QPainter>
+#include <QScreen>
+#include <QWindow>
+#include <QMimeData>
+#include <QPixmap>
+#include <QDrag>
+#include <QWindow>
+#if QT_CONFIG(opengl)
+#include <QOpenGLWindow>
+#endif
+#include <QRasterWindow>
+
+#include <QtTest/QtTest>
+#include <QtWaylandClient/private/qwaylandintegration_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+
+#include "wl-socket.h"
+
+using namespace MockCompositor;
+
+class TestWindow : public QRasterWindow
+{
+public:
+ TestWindow()
+ {
+ }
+
+ void focusInEvent(QFocusEvent *) override
+ {
+ ++focusInEventCount;
+ }
+
+ void focusOutEvent(QFocusEvent *) override
+ {
+ ++focusOutEventCount;
+ }
+
+ void keyPressEvent(QKeyEvent *event) override
+ {
+ ++keyPressEventCount;
+ keyCode = event->nativeScanCode();
+ }
+
+ void keyReleaseEvent(QKeyEvent *event) override
+ {
+ ++keyReleaseEventCount;
+ keyCode = event->nativeScanCode();
+ }
+
+ void mousePressEvent(QMouseEvent *event) override
+ {
+ ++mousePressEventCount;
+ mousePressPos = event->position().toPoint();
+ }
+
+ void mouseReleaseEvent(QMouseEvent *) override
+ {
+ ++mouseReleaseEventCount;
+ }
+
+ void touchEvent(QTouchEvent *event) override
+ {
+ Q_UNUSED(event);
+ ++touchEventCount;
+ }
+
+ QPoint frameOffset() const { return QPoint(frameMargins().left(), frameMargins().top()); }
+
+ int focusInEventCount = 0;
+ int focusOutEventCount = 0;
+ int keyPressEventCount = 0;
+ int keyReleaseEventCount = 0;
+ int mousePressEventCount = 0;
+ int mouseReleaseEventCount = 0;
+ int touchEventCount = 0;
+
+ uint keyCode = 0;
+ QPoint mousePressPos;
+};
+
+class tst_WaylandReconnect : public QObject
+{
+ Q_OBJECT
+public:
+ tst_WaylandReconnect();
+ void triggerReconnect();
+
+ template<typename function_type, typename... arg_types>
+ auto exec(function_type func, arg_types&&... args) -> decltype(func())
+ {
+ return m_comp->exec(func, std::forward<arg_types>(args)...);
+ }
+
+private Q_SLOTS:
+//core
+ void cleanup() { QTRY_VERIFY2(m_comp->isClean(), qPrintable(m_comp->dirtyMessage())); }
+ void basicWindow();
+ void multipleScreens();
+
+//input
+ void keyFocus();
+
+private:
+ void configureWindow();
+ QScopedPointer<DefaultCompositor> m_comp;
+ wl_socket *m_socket;
+};
+
+tst_WaylandReconnect::tst_WaylandReconnect()
+{
+ m_socket = wl_socket_create();
+ QVERIFY(m_socket);
+ const int socketFd = wl_socket_get_fd(m_socket);
+ const QByteArray socketName = wl_socket_get_display_name(m_socket);
+ qputenv("WAYLAND_DISPLAY", socketName);
+
+ m_comp.reset(new DefaultCompositor(CoreCompositor::Default, dup(socketFd)));
+}
+
+void tst_WaylandReconnect::triggerReconnect()
+{
+ const int socketFd = wl_socket_get_fd(m_socket);
+ m_comp.reset(new DefaultCompositor(CoreCompositor::Default, dup(socketFd)));
+ QTest::qWait(50); //we need to spin the main loop to actually reconnect
+}
+
+void tst_WaylandReconnect::basicWindow()
+{
+ QRasterWindow window;
+ window.resize(64, 48);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(m_comp->xdgToplevel());
+
+ triggerReconnect();
+
+ QCOMPOSITOR_TRY_VERIFY(m_comp->xdgToplevel());
+}
+
+void tst_WaylandReconnect::multipleScreens()
+{
+
+ exec([this] { m_comp->add<Output>(); });
+ QRasterWindow window1;
+ window1.resize(64, 48);
+ window1.show();
+ QRasterWindow window2;
+ window2.resize(64, 48);
+ window2.show();
+ QCOMPOSITOR_TRY_VERIFY(m_comp->xdgToplevel(0));
+ QCOMPOSITOR_TRY_VERIFY(m_comp->xdgToplevel(1));
+
+ // ensure they are on different outputs
+ exec([this] {
+ m_comp->surface(0)->sendEnter(m_comp->output(0));
+ m_comp->surface(1)->sendEnter(m_comp->output(1));
+ });
+ QTRY_VERIFY(window1.screen() != window2.screen());
+
+ auto originalScreens = QGuiApplication::screens();
+
+ QSignalSpy screenRemovedSpy(qGuiApp, &QGuiApplication::screenRemoved);
+ QVERIFY(screenRemovedSpy.isValid());
+
+ triggerReconnect();
+
+ // All screens plus temporary placeholder screen removed
+ QCOMPARE(screenRemovedSpy.count(), originalScreens.count() + 1);
+ for (const auto &screen : std::as_const(screenRemovedSpy)) {
+ originalScreens.removeOne(screen[0].value<QScreen *>());
+ }
+ QVERIFY(originalScreens.isEmpty());
+
+ QCOMPOSITOR_TRY_VERIFY(m_comp->xdgToplevel(0));
+ QCOMPOSITOR_TRY_VERIFY(m_comp->xdgToplevel(1));
+ QVERIFY(window1.screen());
+ QVERIFY(window2.screen());
+ QVERIFY(QGuiApplication::screens().contains(window1.screen()));
+ QVERIFY(QGuiApplication::screens().contains(window2.screen()));
+}
+
+void tst_WaylandReconnect::keyFocus()
+{
+ TestWindow window;
+ window.resize(64, 48);
+ window.show();
+
+ configureWindow();
+ QTRY_VERIFY(window.isExposed());
+ exec([&] {
+ m_comp->keyboard()->sendEnter(m_comp->surface());
+ });
+ QTRY_COMPARE(window.focusInEventCount, 1);
+
+ uint keyCode = 80;
+ QCOMPARE(window.keyPressEventCount, 0);
+ exec([&] {
+ m_comp->keyboard()->sendKey(m_comp->client(), keyCode - 8, Keyboard::key_state_pressed);
+ });
+ QTRY_COMPARE(window.keyPressEventCount, 1);
+ QCOMPARE(QGuiApplication::focusWindow(), &window);
+
+ triggerReconnect();
+ configureWindow();
+
+ // on reconnect our knowledge of focus is reset to a clean slate
+ QCOMPARE(QGuiApplication::focusWindow(), nullptr);
+ QTRY_COMPARE(window.focusOutEventCount, 1);
+
+ // fake the user explicitly focussing this window afterwards
+ exec([&] {
+ m_comp->keyboard()->sendEnter(m_comp->surface());
+ });
+ exec([&] {
+ m_comp->keyboard()->sendKey(m_comp->client(), keyCode - 8, Keyboard::key_state_pressed);
+ });
+ QTRY_COMPARE(window.focusInEventCount, 2);
+ QTRY_COMPARE(window.keyPressEventCount, 2);
+}
+
+
+void tst_WaylandReconnect::configureWindow()
+{
+ QCOMPOSITOR_TRY_VERIFY(m_comp->xdgToplevel());
+ m_comp->exec([&] {
+ m_comp->xdgToplevel()->sendConfigure({0, 0}, {});
+ const uint serial = m_comp->nextSerial(); // Let the window decide the size
+ m_comp->xdgSurface()->sendConfigure(serial);
+ });
+}
+
+int main(int argc, char **argv)
+{
+ // Note when debugging that a failing reconnect will exit this
+ // test rather than fail. Making sure it finishes is important!
+
+ QTemporaryDir tmpRuntimeDir;
+ setenv("QT_QPA_PLATFORM", "wayland", 1); // force QGuiApplication to use wayland plugin
+ setenv("QT_WAYLAND_RECONNECT", "1", 1);
+ setenv("XDG_CURRENT_DESKTOP", "qtwaylandtests", 1);
+
+ tst_WaylandReconnect tc;
+ QGuiApplication app(argc, argv);
+ QTEST_SET_MAIN_SOURCE_PATH
+ return QTest::qExec(&tc, argc, argv);
+}
+
+#include "tst_reconnect.moc"
diff --git a/tests/auto/client/reconnect/wl-socket.c b/tests/auto/client/reconnect/wl-socket.c
new file mode 100644
index 000000000..3d4491622
--- /dev/null
+++ b/tests/auto/client/reconnect/wl-socket.c
@@ -0,0 +1,166 @@
+// Copyright (C) 2023 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#define _DEFAULT_SOURCE
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+/* This is the size of the char array in struct sock_addr_un.
+ * No Wayland socket can be created with a path longer than this,
+ * including the null terminator.
+ */
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX 108
+#endif
+
+#define LOCK_SUFFIX ".lock"
+#define LOCK_SUFFIXLEN 5
+
+struct wl_socket {
+ int fd;
+ int fd_lock;
+ struct sockaddr_un addr;
+ char lock_addr[UNIX_PATH_MAX + LOCK_SUFFIXLEN];
+ char display_name[16];
+};
+
+static struct wl_socket *wl_socket_alloc(void)
+{
+ struct wl_socket *s;
+
+ s = malloc(sizeof *s);
+ if (!s)
+ return NULL;
+
+ s->fd = -1;
+ s->fd_lock = -1;
+
+ return s;
+}
+
+static int wl_socket_lock(struct wl_socket *socket)
+{
+ struct stat socket_stat;
+
+ snprintf(socket->lock_addr, sizeof socket->lock_addr, "%s%s", socket->addr.sun_path, LOCK_SUFFIX);
+
+ // differening from kwin, we're back to setting CLOEXEC as we're all in process
+ socket->fd_lock = open(socket->lock_addr, O_CREAT | O_RDWR | O_CLOEXEC, (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
+
+ if (socket->fd_lock < 0) {
+ printf("unable to open lockfile %s check permissions\n", socket->lock_addr);
+ goto err;
+ }
+
+ if (flock(socket->fd_lock, LOCK_EX | LOCK_NB) < 0) {
+ printf("unable to lock lockfile %s, maybe another compositor is running\n", socket->lock_addr);
+ goto err_fd;
+ }
+
+ if (lstat(socket->addr.sun_path, &socket_stat) < 0) {
+ if (errno != ENOENT) {
+ printf("did not manage to stat file %s\n", socket->addr.sun_path);
+ goto err_fd;
+ }
+ } else if (socket_stat.st_mode & S_IWUSR || socket_stat.st_mode & S_IWGRP) {
+ unlink(socket->addr.sun_path);
+ }
+
+ return 0;
+err_fd:
+ close(socket->fd_lock);
+ socket->fd_lock = -1;
+err:
+ *socket->lock_addr = 0;
+ /* we did not set this value here, but without lock the
+ * socket won't be created anyway. This prevents the
+ * wl_socket_destroy from unlinking already existing socket
+ * created by other compositor */
+ *socket->addr.sun_path = 0;
+
+ return -1;
+}
+
+void wl_socket_destroy(struct wl_socket *s)
+{
+ if (s->addr.sun_path[0])
+ unlink(s->addr.sun_path);
+ if (s->fd >= 0)
+ close(s->fd);
+ if (s->lock_addr[0])
+ unlink(s->lock_addr);
+ if (s->fd_lock >= 0)
+ close(s->fd_lock);
+
+ free(s);
+}
+
+const char *wl_socket_get_display_name(struct wl_socket *s)
+{
+ return s->display_name;
+}
+
+int wl_socket_get_fd(struct wl_socket *s)
+{
+ return s->fd;
+}
+
+struct wl_socket *wl_socket_create()
+{
+ struct wl_socket *s;
+ int displayno = 0;
+ int name_size;
+
+ /* A reasonable number of maximum default sockets. If
+ * you need more than this, use the explicit add_socket API. */
+ const int MAX_DISPLAYNO = 32;
+ const char *runtime_dir = getenv("XDG_RUNTIME_DIR");
+ if (!runtime_dir) {
+ printf("XDG_RUNTIME_DIR not set");
+ return NULL;
+ }
+
+ s = wl_socket_alloc();
+ if (s == NULL)
+ return NULL;
+
+ do {
+ snprintf(s->display_name, sizeof s->display_name, "wayland-%d", displayno);
+ s->addr.sun_family = AF_LOCAL;
+ name_size = snprintf(s->addr.sun_path, sizeof s->addr.sun_path, "%s/%s", runtime_dir, s->display_name) + 1;
+ assert(name_size > 0);
+
+ if (name_size > (int)sizeof s->addr.sun_path) {
+ goto fail;
+ }
+
+ if (wl_socket_lock(s) < 0)
+ continue;
+
+ s->fd = socket(PF_LOCAL, SOCK_STREAM, 0);
+
+ int size = SUN_LEN(&s->addr);
+ int ret = bind(s->fd, (struct sockaddr*)&s->addr, size);
+ if (ret < 0) {
+ goto fail;
+ }
+ ret = listen(s->fd, 128);
+ if (ret < 0) {
+ goto fail;
+ }
+ return s;
+ } while (displayno++ < MAX_DISPLAYNO);
+
+fail:
+ wl_socket_destroy(s);
+ return NULL;
+}
diff --git a/tests/auto/client/reconnect/wl-socket.h b/tests/auto/client/reconnect/wl-socket.h
new file mode 100644
index 000000000..c2e68120f
--- /dev/null
+++ b/tests/auto/client/reconnect/wl-socket.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2023 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * Allocate and create a socket
+ * It is bound and accepted
+ */
+struct wl_socket *wl_socket_create();
+
+/**
+ * Returns the file descriptor for the socket
+ */
+int wl_socket_get_fd(struct wl_socket *);
+
+/**
+ * Returns the name of the socket, i.e "wayland-0"
+ */
+char *wl_socket_get_display_name(struct wl_socket *);
+
+/**
+ * Cleanup resources and close the FD
+ */
+void wl_socket_destroy(struct wl_socket *socket);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/tests/auto/client/scaling/CMakeLists.txt b/tests/auto/client/scaling/CMakeLists.txt
new file mode 100644
index 000000000..e58981388
--- /dev/null
+++ b/tests/auto/client/scaling/CMakeLists.txt
@@ -0,0 +1,10 @@
+#####################################################################
+## tst_scaling Test:
+#####################################################################
+
+qt_internal_add_test(tst_scaling
+ SOURCES
+ tst_scaling.cpp
+ LIBRARIES
+ SharedClientTest
+)
diff --git a/tests/auto/client/scaling/tst_scaling.cpp b/tests/auto/client/scaling/tst_scaling.cpp
new file mode 100644
index 000000000..b4d2995ea
--- /dev/null
+++ b/tests/auto/client/scaling/tst_scaling.cpp
@@ -0,0 +1,134 @@
+// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "mockcompositor.h"
+#include <QtGui/QRasterWindow>
+#include <QtGui/qpa/qplatformnativeinterface.h>
+#include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
+#include <QtWaylandClient/private/qwaylandwindow_p.h>
+
+using namespace MockCompositor;
+
+class tst_scaling : public QObject, private DefaultCompositor
+{
+ Q_OBJECT
+private slots:
+ void init();
+ void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); }
+ void scaledWindow();
+ void roundingPolicy_data();
+ void roundingPolicy();
+
+};
+
+void tst_scaling::init()
+{
+ setenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1", 1);
+}
+
+void tst_scaling::scaledWindow()
+{
+ QRasterWindow window;
+ window.resize(100, 100);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+
+ QSignalSpy configureSpy(exec([&] { return xdgSurface(); }), &XdgSurface::configureCommitted);
+ QSignalSpy surfaceCommitSpy(exec([&] { return surface(); }), &Surface::commit);
+
+ const QSize configureSize(100, 100);
+
+ exec([&] {
+ QVERIFY(fractionalScale());
+ fractionalScale()->send_preferred_scale(1.5 * 120);
+ xdgToplevel()->sendCompleteConfigure(configureSize);
+ });
+
+ QTRY_COMPARE(configureSpy.count(), 1);
+ QCOMPARE(window.devicePixelRatio(), 1.5);
+
+ exec([&] {
+ Buffer *buffer = xdgToplevel()->surface()->m_committed.buffer;
+ QVERIFY(buffer);
+ QCOMPARE(buffer->size(), QSize(150, 150));
+ Viewport *vp = viewport();
+ QVERIFY(vp);
+ QCOMPARE(vp->m_destination, QSize(100, 100));
+ });
+
+ // resize the window
+ window.resize(200,200);
+ QCOMPARE(window.size(), QSize(200,200));
+
+ QVERIFY(surfaceCommitSpy.wait());
+ exec([&] {
+ Buffer *buffer = xdgToplevel()->surface()->m_committed.buffer;
+ QVERIFY(buffer);
+ QCOMPARE(buffer->size(), QSize(300, 300));
+ Viewport *vp = viewport();
+ QVERIFY(vp);
+ QCOMPARE(vp->m_destination, QSize(200, 200));
+ });
+
+ // dynamic scale change
+ exec([&] {
+ QVERIFY(fractionalScale());
+ fractionalScale()->send_preferred_scale(2.5 * 120);
+ });
+ QTRY_COMPARE(window.devicePixelRatio(), 2.5);
+ QCOMPARE(window.size(), QSize(200,200));
+
+ QVERIFY(surfaceCommitSpy.wait());
+ exec([&] {
+ Buffer *buffer = xdgToplevel()->surface()->m_committed.buffer;
+ QVERIFY(buffer);
+ QCOMPARE(buffer->size(), QSize(500, 500));
+ Viewport *vp = viewport();
+ QVERIFY(vp);
+ QCOMPARE(vp->m_destination, QSize(200, 200));
+ });
+}
+
+void tst_scaling::roundingPolicy_data()
+{
+ QTest::addColumn<QSize>("windowSize");
+ QTest::addColumn<qreal>("scale");
+ QTest::addColumn<QSize>("expectedBufferSize");
+
+ QTest::newRow("1.125 - round down") << QSize(10, 10) << 1.125 << QSize(11,11);
+ QTest::newRow("1.25 - round up") << QSize(10, 10) << 1.25 << QSize(13,13);
+ QTest::newRow("1.5 - don't round") << QSize(10, 10) << 1.5 << QSize(15,15);
+}
+
+void tst_scaling::roundingPolicy()
+{
+ QFETCH(QSize, windowSize);
+ QFETCH(qreal, scale);
+ QFETCH(QSize, expectedBufferSize);
+
+
+ QRasterWindow window;
+ window.resize(windowSize);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+
+ QSignalSpy surfaceCommitSpy(exec([&] { return surface(); }), &Surface::commit);
+
+ exec([&] {
+ QVERIFY(fractionalScale());
+ fractionalScale()->send_preferred_scale(scale * 120);
+ xdgToplevel()->sendCompleteConfigure();
+ });
+
+ QVERIFY(surfaceCommitSpy.wait());
+
+ exec([&] {
+ Buffer *buffer = xdgToplevel()->surface()->m_committed.buffer;
+ QVERIFY(buffer);
+ QCOMPARE(buffer->size(), expectedBufferSize);
+ });
+}
+
+
+QCOMPOSITOR_TEST_MAIN(tst_scaling)
+#include "tst_scaling.moc"
diff --git a/tests/auto/client/seat/CMakeLists.txt b/tests/auto/client/seat/CMakeLists.txt
index fe59acee0..0ac9ec49f 100644
--- a/tests/auto/client/seat/CMakeLists.txt
+++ b/tests/auto/client/seat/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from seatv5.pro.
#####################################################################
@@ -7,6 +10,6 @@
qt_internal_add_test(tst_seat
SOURCES
tst_seat.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
SharedClientTest
)
diff --git a/tests/auto/client/seat/tst_seat.cpp b/tests/auto/client/seat/tst_seat.cpp
index dd52789b4..45ae7251c 100644
--- a/tests/auto/client/seat/tst_seat.cpp
+++ b/tests/auto/client/seat/tst_seat.cpp
@@ -1,8 +1,7 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockcompositor.h"
-#include <QtOpenGL/QOpenGLWindow>
#include <QtGui/QRasterWindow>
#include <QtGui/QEventPoint>
@@ -18,7 +17,7 @@ public:
removeAll<Seat>();
uint capabilities = MockCompositor::Seat::capability_pointer | MockCompositor::Seat::capability_touch;
- int version = 7;
+ int version = 9;
add<Seat>(capabilities, version);
});
}
@@ -40,8 +39,7 @@ private slots:
void fingerScroll();
void fingerScrollSlow();
void continuousScroll();
- void wheelDiscreteScroll_data();
- void wheelDiscreteScroll();
+ void highResolutionScroll();
// Touch tests
void createsTouch();
@@ -50,18 +48,19 @@ private slots:
void multiTouch();
void multiTouchUpAndMotionFrame();
void tapAndMoveInSameFrame();
+ void cancelTouch();
};
void tst_seat::bindsToSeat()
{
QCOMPOSITOR_COMPARE(get<Seat>()->resourceMap().size(), 1);
- QCOMPOSITOR_COMPARE(get<Seat>()->resourceMap().first()->version(), 7);
+ QCOMPOSITOR_COMPARE(get<Seat>()->resourceMap().first()->version(), 9);
}
void tst_seat::createsPointer()
{
QCOMPOSITOR_TRY_COMPARE(pointer()->resourceMap().size(), 1);
- QCOMPOSITOR_TRY_COMPARE(pointer()->resourceMap().first()->version(), 7);
+ QCOMPOSITOR_TRY_COMPARE(pointer()->resourceMap().first()->version(), 9);
}
void tst_seat::setsCursorOnEnter()
@@ -71,7 +70,7 @@ void tst_seat::setsCursorOnEnter()
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
- exec([=] {
+ exec([&] {
auto *surface = xdgSurface()->m_surface;
pointer()->sendEnter(surface, {0, 0});
pointer()->sendFrame(surface->resource()->client());
@@ -82,18 +81,18 @@ void tst_seat::setsCursorOnEnter()
void tst_seat::usesEnterSerial()
{
- QSignalSpy setCursorSpy(exec([=] { return pointer(); }), &Pointer::setCursor);
+ QSignalSpy setCursorSpy(exec([&] { return pointer(); }), &Pointer::setCursor);
QRasterWindow window;
window.resize(64, 64);
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
- uint enterSerial = exec([=] {
+ uint enterSerial = exec([&] {
return pointer()->sendEnter(xdgSurface()->m_surface, {0, 0});
});
QCOMPOSITOR_TRY_VERIFY(pointer()->cursorSurface());
- QTRY_COMPARE(setCursorSpy.count(), 1);
+ QTRY_COMPARE(setCursorSpy.size(), 1);
QCOMPARE(setCursorSpy.takeFirst().at(0).toUInt(), enterSerial);
}
@@ -115,10 +114,6 @@ public:
QCOMPARE(event->pixelDelta(), QPoint(0, 0));
}
- // The axis vector of the event is already in surface space, so there is now way to tell
- // whether it is inverted or not.
- QCOMPARE(event->inverted(), false);
-
// We didn't press any buttons
QCOMPARE(event->buttons(), Qt::NoButton);
@@ -132,12 +127,14 @@ public:
, pixelDelta(event->pixelDelta())
, angleDelta(event->angleDelta())
, source(event->source())
+ , inverted(event->inverted())
{
}
Qt::ScrollPhase phase{};
QPoint pixelDelta;
QPoint angleDelta; // eights of a degree, positive is upwards, left
Qt::MouseEventSource source{};
+ bool inverted = false;
};
QList<Event> m_events;
};
@@ -147,13 +144,21 @@ void tst_seat::simpleAxis_data()
QTest::addColumn<uint>("axis");
QTest::addColumn<qreal>("value");
QTest::addColumn<QPoint>("angleDelta");
+ QTest::addColumn<bool>("inverted");
// Directions in regular windows/linux terms (no "natural" scrolling)
- QTest::newRow("down") << uint(Pointer::axis_vertical_scroll) << 1.0 << QPoint{0, -12};
- QTest::newRow("up") << uint(Pointer::axis_vertical_scroll) << -1.0 << QPoint{0, 12};
- QTest::newRow("left") << uint(Pointer::axis_horizontal_scroll) << 1.0 << QPoint{-12, 0};
- QTest::newRow("right") << uint(Pointer::axis_horizontal_scroll) << -1.0 << QPoint{12, 0};
- QTest::newRow("up big") << uint(Pointer::axis_vertical_scroll) << -10.0 << QPoint{0, 120};
+ QTest::newRow("down") << uint(Pointer::axis_vertical_scroll) << 1.0 << QPoint{0, -12} << false;
+ QTest::newRow("up") << uint(Pointer::axis_vertical_scroll) << -1.0 << QPoint{0, 12} << false;
+ QTest::newRow("left") << uint(Pointer::axis_horizontal_scroll) << 1.0 << QPoint{-12, 0} << false;
+ QTest::newRow("right") << uint(Pointer::axis_horizontal_scroll) << -1.0 << QPoint{12, 0} << false;
+ QTest::newRow("up big") << uint(Pointer::axis_vertical_scroll) << -10.0 << QPoint{0, 120} << false;
+
+ // (natural) scrolling
+ QTest::newRow("down inverted") << uint(Pointer::axis_vertical_scroll) << 1.0 << QPoint{0, -12} << true;
+ QTest::newRow("up inverted") << uint(Pointer::axis_vertical_scroll) << -1.0 << QPoint{0, 12} << true;
+ QTest::newRow("left inverted") << uint(Pointer::axis_horizontal_scroll) << 1.0 << QPoint{-12, 0} << true;
+ QTest::newRow("right inverted") << uint(Pointer::axis_horizontal_scroll) << -1.0 << QPoint{12, 0} << true;
+ QTest::newRow("up big inverted") << uint(Pointer::axis_vertical_scroll) << -10.0 << QPoint{0, 120} << true;
}
void tst_seat::simpleAxis()
@@ -161,11 +166,12 @@ void tst_seat::simpleAxis()
QFETCH(uint, axis);
QFETCH(qreal, value);
QFETCH(QPoint, angleDelta);
+ QFETCH(bool, inverted);
WheelWindow window;
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
- exec([=] {
+ exec([&] {
auto *p = pointer();
p->sendEnter(xdgToplevel()->surface(), {32, 32});
p->sendFrame(client());
@@ -174,6 +180,8 @@ void tst_seat::simpleAxis()
Pointer::axis(axis),
value // Length of vector in surface-local space. i.e. positive is downwards
);
+ auto direction = inverted ? Pointer::axis_relative_direction_inverted : Pointer::axis_relative_direction_identical;
+ p->sendAxisRelativeDirection(client(), Pointer::axis(axis), direction);
p->sendFrame(client());
});
@@ -187,6 +195,8 @@ void tst_seat::simpleAxis()
// Documentation says not synthesized is appropriate in such cases
QCOMPARE(e.source, Qt::MouseEventNotSynthesized);
QCOMPARE(e.angleDelta, angleDelta);
+
+ QCOMPARE(e.inverted, inverted);
}
// Sending axis_stop is not mandatory when axis source != finger
@@ -197,7 +207,7 @@ void tst_seat::fingerScroll()
WheelWindow window;
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
- exec([=] {
+ exec([&] {
auto *p = pointer();
auto *c = client();
p->sendEnter(xdgToplevel()->surface(), {32, 32});
@@ -237,7 +247,7 @@ void tst_seat::fingerScroll()
QTRY_VERIFY(window.m_events.empty());
// Scroll horizontally as well
- exec([=] {
+ exec([&] {
pointer()->sendAxisSource(client(), Pointer::axis_source_finger);
pointer()->sendAxis(client(), Pointer::axis_horizontal_scroll, 10);
pointer()->sendFrame(client());
@@ -252,7 +262,7 @@ void tst_seat::fingerScroll()
}
// Scroll diagonally
- exec([=] {
+ exec([&] {
pointer()->sendAxisSource(client(), Pointer::axis_source_finger);
pointer()->sendAxis(client(), Pointer::axis_horizontal_scroll, 10);
pointer()->sendAxis(client(), Pointer::axis_vertical_scroll, 10);
@@ -276,7 +286,7 @@ void tst_seat::fingerScroll()
QVERIFY(window.m_events.empty());
// Sending axis_stop is mandatory when axis source == finger
- exec([=] {
+ exec([&] {
pointer()->sendAxisStop(client(), Pointer::axis_vertical_scroll);
pointer()->sendFrame(client());
});
@@ -294,7 +304,7 @@ void tst_seat::fingerScrollSlow()
WheelWindow window;
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
- exec([=] {
+ exec([&] {
auto *p = pointer();
auto *c = client();
p->sendEnter(xdgToplevel()->surface(), {32, 32});
@@ -319,28 +329,38 @@ void tst_seat::fingerScrollSlow()
QCOMPARE(accumulated.y(), -1);
}
-void tst_seat::wheelDiscreteScroll_data()
-{
- QTest::addColumn<uint>("source");
- QTest::newRow("wheel") << uint(Pointer::axis_source_wheel);
- QTest::newRow("wheel tilt") << uint(Pointer::axis_source_wheel_tilt);
-}
-
-void tst_seat::wheelDiscreteScroll()
+void tst_seat::highResolutionScroll()
{
WheelWindow window;
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
- QFETCH(uint, source);
-
- exec([=] {
+ exec([&] {
auto *p = pointer();
auto *c = client();
p->sendEnter(xdgToplevel()->surface(), {32, 32});
p->sendFrame(c);
- p->sendAxisSource(c, Pointer::axis_source(source));
- p->sendAxisDiscrete(c, Pointer::axis_vertical_scroll, 1); // 1 click downwards
- p->sendAxis(c, Pointer::axis_vertical_scroll, 1.0);
+ p->sendAxisSource(c, Pointer::axis_source_wheel);
+ p->sendAxisValue120(c, Pointer::axis_vertical_scroll, 30); // quarter of a click
+ p->sendAxis(c, Pointer::axis_vertical_scroll, 3.75);
+ p->sendFrame(c);
+ });
+
+ QTRY_VERIFY(!window.m_events.empty());
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.phase, Qt::NoScrollPhase);
+ QVERIFY(qAbs(e.angleDelta.x()) <= qAbs(e.angleDelta.y())); // Vertical scroll
+ QCOMPARE(e.angleDelta, QPoint(0, -30));
+ // Click scrolls are not continuous and should not have a pixel delta
+ QCOMPARE(e.pixelDelta, QPoint(0, 0));
+ }
+
+ exec([&] {
+ auto *p = pointer();
+ auto *c = client();
+ p->sendAxisSource(c, Pointer::axis_source_wheel);
+ p->sendAxisValue120(c, Pointer::axis_vertical_scroll, 90); // complete the click
+ p->sendAxis(c, Pointer::axis_vertical_scroll, 11.25);
p->sendFrame(c);
});
@@ -349,10 +369,7 @@ void tst_seat::wheelDiscreteScroll()
auto e = window.m_events.takeFirst();
QCOMPARE(e.phase, Qt::NoScrollPhase);
QVERIFY(qAbs(e.angleDelta.x()) <= qAbs(e.angleDelta.y())); // Vertical scroll
- // According to the docs the angle delta is in eights of a degree and most mice have
- // 1 click = 15 degrees. The angle delta should therefore be:
- // 15 degrees / (1/8 eights per degrees) = 120 eights of degrees.
- QCOMPARE(e.angleDelta, QPoint(0, -120));
+ QCOMPARE(e.angleDelta, QPoint(0, -90));
// Click scrolls are not continuous and should not have a pixel delta
QCOMPARE(e.pixelDelta, QPoint(0, 0));
}
@@ -363,7 +380,7 @@ void tst_seat::continuousScroll()
WheelWindow window;
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
- exec([=] {
+ exec([&] {
auto *p = pointer();
auto *c = client();
p->sendEnter(xdgToplevel()->surface(), {32, 32});
@@ -380,6 +397,8 @@ void tst_seat::continuousScroll()
QCOMPARE(e.phase, Qt::NoScrollPhase);
QCOMPARE(e.pixelDelta, QPoint(5, -10));
QCOMPARE(e.source, Qt::MouseEventSynthesizedBySystem); // touchpads are not wheels
+ QCOMPARE(e.inverted, false);
+
}
// Sending axis_stop is not mandatory when axis source != finger
}
@@ -387,7 +406,7 @@ void tst_seat::continuousScroll()
void tst_seat::createsTouch()
{
QCOMPOSITOR_TRY_COMPARE(touch()->resourceMap().size(), 1);
- QCOMPOSITOR_TRY_COMPARE(touch()->resourceMap().first()->version(), 7);
+ QCOMPOSITOR_TRY_COMPARE(touch()->resourceMap().first()->version(), 9);
}
class TouchWindow : public QRasterWindow {
@@ -423,7 +442,7 @@ void tst_seat::singleTap()
TouchWindow window;
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
- exec([=] {
+ exec([&] {
auto *t = touch();
auto *c = client();
t->sendDown(xdgToplevel()->surface(), {32, 32}, 1);
@@ -437,14 +456,14 @@ void tst_seat::singleTap()
auto e = window.m_events.takeFirst();
QCOMPARE(e.type, QEvent::TouchBegin);
QCOMPARE(e.touchPointStates, QEventPoint::State::Pressed);
- QCOMPARE(e.touchPoints.length(), 1);
+ QCOMPARE(e.touchPoints.size(), 1);
QCOMPARE(e.touchPoints.first().position(), QPointF(32-window.frameMargins().left(), 32-window.frameMargins().top()));
}
{
auto e = window.m_events.takeFirst();
QCOMPARE(e.type, QEvent::TouchEnd);
QCOMPARE(e.touchPointStates, QEventPoint::State::Released);
- QCOMPARE(e.touchPoints.length(), 1);
+ QCOMPARE(e.touchPoints.size(), 1);
QCOMPARE(e.touchPoints.first().position(), QPointF(32-window.frameMargins().left(), 32-window.frameMargins().top()));
}
}
@@ -454,7 +473,7 @@ void tst_seat::singleTapFloat()
TouchWindow window;
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
- exec([=] {
+ exec([&] {
auto *t = touch();
auto *c = client();
t->sendDown(xdgToplevel()->surface(), {32.75, 32.25}, 1);
@@ -468,14 +487,14 @@ void tst_seat::singleTapFloat()
auto e = window.m_events.takeFirst();
QCOMPARE(e.type, QEvent::TouchBegin);
QCOMPARE(e.touchPointStates, QEventPoint::State::Pressed);
- QCOMPARE(e.touchPoints.length(), 1);
+ QCOMPARE(e.touchPoints.size(), 1);
QCOMPARE(e.touchPoints.first().position(), QPointF(32.75-window.frameMargins().left(), 32.25-window.frameMargins().top()));
}
{
auto e = window.m_events.takeFirst();
QCOMPARE(e.type, QEvent::TouchEnd);
QCOMPARE(e.touchPointStates, QEventPoint::State::Released);
- QCOMPARE(e.touchPoints.length(), 1);
+ QCOMPARE(e.touchPoints.size(), 1);
QCOMPARE(e.touchPoints.first().position(), QPointF(32.75-window.frameMargins().left(), 32.25-window.frameMargins().top()));
}
}
@@ -485,7 +504,7 @@ void tst_seat::multiTouch()
TouchWindow window;
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
- exec([=] {
+ exec([&] {
auto *t = touch();
auto *c = client();
@@ -511,7 +530,7 @@ void tst_seat::multiTouch()
auto e = window.m_events.takeFirst();
QCOMPARE(e.type, QEvent::TouchBegin);
QCOMPARE(e.touchPointStates, QEventPoint::State::Pressed);
- QCOMPARE(e.touchPoints.length(), 2);
+ QCOMPARE(e.touchPoints.size(), 2);
QCOMPARE(e.touchPoints[0].state(), QEventPoint::State::Pressed);
QCOMPARE(e.touchPoints[0].position(), QPointF(32-window.frameMargins().left(), 32-window.frameMargins().top()));
@@ -522,7 +541,7 @@ void tst_seat::multiTouch()
{
auto e = window.m_events.takeFirst();
QCOMPARE(e.type, QEvent::TouchUpdate);
- QCOMPARE(e.touchPoints.length(), 2);
+ QCOMPARE(e.touchPoints.size(), 2);
QCOMPARE(e.touchPoints[0].state(), QEventPoint::State::Updated);
QCOMPARE(e.touchPoints[0].position(), QPointF(33-window.frameMargins().left(), 32-window.frameMargins().top()));
@@ -534,7 +553,7 @@ void tst_seat::multiTouch()
auto e = window.m_events.takeFirst();
QCOMPARE(e.type, QEvent::TouchUpdate);
QCOMPARE(e.touchPointStates, QEventPoint::State::Released | QEventPoint::State::Stationary);
- QCOMPARE(e.touchPoints.length(), 2);
+ QCOMPARE(e.touchPoints.size(), 2);
QCOMPARE(e.touchPoints[0].state(), QEventPoint::State::Released);
QCOMPARE(e.touchPoints[0].position(), QPointF(33-window.frameMargins().left(), 32-window.frameMargins().top()));
@@ -546,7 +565,7 @@ void tst_seat::multiTouch()
auto e = window.m_events.takeFirst();
QCOMPARE(e.type, QEvent::TouchEnd);
QCOMPARE(e.touchPointStates, QEventPoint::State::Released);
- QCOMPARE(e.touchPoints.length(), 1);
+ QCOMPARE(e.touchPoints.size(), 1);
QCOMPARE(e.touchPoints[0].state(), QEventPoint::State::Released);
QCOMPARE(e.touchPoints[0].position(), QPointF(49-window.frameMargins().left(), 48-window.frameMargins().top()));
}
@@ -557,7 +576,7 @@ void tst_seat::multiTouchUpAndMotionFrame()
TouchWindow window;
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
- exec([=] {
+ exec([&] {
auto *t = touch();
auto *c = client();
@@ -588,14 +607,14 @@ void tst_seat::multiTouchUpAndMotionFrame()
{
auto e = window.m_events.takeFirst();
QCOMPARE(e.type, QEvent::TouchUpdate);
- QCOMPARE(e.touchPoints.length(), 2);
+ QCOMPARE(e.touchPoints.size(), 2);
QCOMPARE(e.touchPoints[0].state(), QEventPoint::State::Released);
QCOMPARE(e.touchPoints[1].state(), QEventPoint::State::Updated);
}
{
auto e = window.m_events.takeFirst();
QCOMPARE(e.type, QEvent::TouchEnd);
- QCOMPARE(e.touchPoints.length(), 1);
+ QCOMPARE(e.touchPoints.size(), 1);
QCOMPARE(e.touchPoints[0].state(), QEventPoint::State::Released);
}
QVERIFY(window.m_events.empty());
@@ -606,7 +625,7 @@ void tst_seat::tapAndMoveInSameFrame()
TouchWindow window;
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
- exec([=] {
+ exec([&] {
auto *t = touch();
auto *c = client();
@@ -633,5 +652,34 @@ void tst_seat::tapAndMoveInSameFrame()
QTRY_COMPARE(window.m_events.last().touchPoints.first().state(), QEventPoint::State::Released);
}
+void tst_seat::cancelTouch()
+{
+ TouchWindow window;
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ exec([&] {
+ auto *t = touch();
+ auto *c = client();
+ t->sendDown(xdgToplevel()->surface(), {32, 32}, 1);
+ t->sendFrame(c);
+ t->sendCancel(c);
+ t->sendFrame(c);
+ });
+
+ QTRY_VERIFY(!window.m_events.empty());
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.type, QEvent::TouchBegin);
+ QCOMPARE(e.touchPointStates, QEventPoint::State::Pressed);
+ QCOMPARE(e.touchPoints.size(), 1);
+ QCOMPARE(e.touchPoints.first().position(), QPointF(32-window.frameMargins().left(), 32-window.frameMargins().top()));
+ }
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.type, QEvent::TouchCancel);
+ QCOMPARE(e.touchPoints.size(), 0);
+ }
+}
+
QCOMPOSITOR_TEST_MAIN(tst_seat)
#include "tst_seat.moc"
diff --git a/tests/auto/client/seatv4/BLACKLIST b/tests/auto/client/seatv4/BLACKLIST
deleted file mode 100644
index e33539406..000000000
--- a/tests/auto/client/seatv4/BLACKLIST
+++ /dev/null
@@ -1,3 +0,0 @@
-[animatedCursor]
-b2qt
-sles
diff --git a/tests/auto/client/seatv4/CMakeLists.txt b/tests/auto/client/seatv4/CMakeLists.txt
index 31ea86b7e..c4e3ecba1 100644
--- a/tests/auto/client/seatv4/CMakeLists.txt
+++ b/tests/auto/client/seatv4/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from seatv4.pro.
#####################################################################
@@ -7,7 +10,7 @@
qt_internal_add_test(tst_seatv4
SOURCES
tst_seatv4.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
SharedClientTest
)
@@ -15,7 +18,7 @@ qt_internal_add_test(tst_seatv4
#####################################################################
qt_internal_extend_target(tst_seatv4 CONDITION QT_FEATURE_cursor
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::GuiPrivate
Wayland::Cursor
)
diff --git a/tests/auto/client/seatv4/tst_seatv4.cpp b/tests/auto/client/seatv4/tst_seatv4.cpp
index 3a5a479fb..cc1cf0afd 100644
--- a/tests/auto/client/seatv4/tst_seatv4.cpp
+++ b/tests/auto/client/seatv4/tst_seatv4.cpp
@@ -1,9 +1,8 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockcompositor.h"
-#include <QtOpenGL/QOpenGLWindow>
#include <QtGui/QRasterWindow>
#if QT_CONFIG(cursor)
#include <wayland-cursor.h>
@@ -24,6 +23,7 @@ public:
{
exec([this] {
m_config.autoConfigure = true;
+ m_config.autoFrameCallback = false; // for cursor animation test
removeAll<Seat>();
@@ -38,6 +38,7 @@ class tst_seatv4 : public QObject, private SeatV4Compositor
{
Q_OBJECT
private slots:
+ void init();
void cleanup();
void bindsToSeat();
void keyboardKeyPress();
@@ -60,6 +61,12 @@ private slots:
#endif
};
+void tst_seatv4::init()
+{
+ // Remove the extra outputs to clean up for the next test
+ exec([&] { while (auto *o = output(1)) remove(o); });
+}
+
void tst_seatv4::cleanup()
{
QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage()));
@@ -110,7 +117,7 @@ void tst_seatv4::setsCursorOnEnter()
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
- exec([&] { pointer()->sendEnter(xdgSurface()->m_surface, {32, 32}); });
+ exec([&] { pointer()->sendEnter(xdgSurface()->m_surface, {24, 24}); });
QCOMPOSITOR_TRY_VERIFY(cursorSurface());
}
@@ -127,7 +134,7 @@ void tst_seatv4::usesEnterSerial()
});
QCOMPOSITOR_TRY_VERIFY(cursorSurface());
- QTRY_COMPARE(setCursorSpy.count(), 1);
+ QTRY_COMPARE(setCursorSpy.size(), 1);
QCOMPARE(setCursorSpy.takeFirst().at(0).toUInt(), enterSerial);
}
@@ -139,13 +146,13 @@ void tst_seatv4::focusDestruction()
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
// Setting a cursor now is not allowed since there has been no enter event
- QCOMPARE(setCursorSpy.count(), 0);
+ QCOMPARE(setCursorSpy.size(), 0);
uint enterSerial = exec([&] {
return pointer()->sendEnter(xdgSurface()->m_surface, {32, 32});
});
QCOMPOSITOR_TRY_VERIFY(cursorSurface());
- QTRY_COMPARE(setCursorSpy.count(), 1);
+ QTRY_COMPARE(setCursorSpy.size(), 1);
QCOMPARE(setCursorSpy.takeFirst().at(0).toUInt(), enterSerial);
// Destroy the focus
@@ -159,7 +166,7 @@ void tst_seatv4::focusDestruction()
// Setting a cursor now is not allowed since there has been no enter event
xdgPingAndWaitForPong();
- QCOMPARE(setCursorSpy.count(), 0);
+ QCOMPARE(setCursorSpy.size(), 0);
}
void tst_seatv4::mousePress()
@@ -335,7 +342,7 @@ static bool supportsCursorSizes(const QList<uint> &sizes)
static uint defaultCursorSize() {
const int xCursorSize = qEnvironmentVariableIntValue("XCURSOR_SIZE");
- return xCursorSize > 0 ? uint(xCursorSize) : 32;
+ return xCursorSize > 0 ? uint(xCursorSize) : 24;
}
void tst_seatv4::scaledCursor()
@@ -568,7 +575,7 @@ void tst_seatv4::animatedCursor()
});
// Verify that we get a new cursor buffer
- QTRY_COMPARE(bufferSpy.count(), 1);
+ QTRY_COMPARE(bufferSpy.size(), 1);
}
#endif // QT_CONFIG(cursor)
diff --git a/tests/auto/client/seatv7/CMakeLists.txt b/tests/auto/client/seatv7/CMakeLists.txt
new file mode 100644
index 000000000..cf3ade8c7
--- /dev/null
+++ b/tests/auto/client/seatv7/CMakeLists.txt
@@ -0,0 +1,13 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_seatv7 Test:
+#####################################################################
+
+qt_internal_add_test(tst_seatv7
+ SOURCES
+ tst_seatv7.cpp
+ LIBRARIES
+ SharedClientTest
+)
diff --git a/tests/auto/client/seatv7/tst_seatv7.cpp b/tests/auto/client/seatv7/tst_seatv7.cpp
new file mode 100644
index 000000000..f82b84b58
--- /dev/null
+++ b/tests/auto/client/seatv7/tst_seatv7.cpp
@@ -0,0 +1,129 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "mockcompositor.h"
+#include <QtGui/QRasterWindow>
+#include <QtGui/QEventPoint>
+
+using namespace MockCompositor;
+
+class SeatCompositor : public DefaultCompositor {
+public:
+ explicit SeatCompositor()
+ {
+ exec([this] {
+ m_config.autoConfigure = true;
+
+ removeAll<Seat>();
+
+ uint capabilities = MockCompositor::Seat::capability_pointer | MockCompositor::Seat::capability_touch;
+ int version = 7;
+ add<Seat>(capabilities, version);
+ });
+ }
+};
+
+class tst_seatv7 : public QObject, private SeatCompositor
+{
+ Q_OBJECT
+private slots:
+ void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); }
+ void bindsToSeat();
+
+ // Pointer tests
+ void wheelDiscreteScroll_data();
+ void wheelDiscreteScroll();
+};
+
+void tst_seatv7::bindsToSeat()
+{
+ QCOMPOSITOR_COMPARE(get<Seat>()->resourceMap().size(), 1);
+ QCOMPOSITOR_COMPARE(get<Seat>()->resourceMap().first()->version(), 7);
+}
+
+class WheelWindow : QRasterWindow {
+public:
+ WheelWindow()
+ {
+ resize(64, 64);
+ show();
+ }
+ void wheelEvent(QWheelEvent *event) override
+ {
+ QRasterWindow::wheelEvent(event);
+// qDebug() << event << "angleDelta" << event->angleDelta() << "pixelDelta" << event->pixelDelta();
+
+ if (event->phase() != Qt::ScrollUpdate && event->phase() != Qt::NoScrollPhase) {
+ // Shouldn't have deltas in the these phases
+ QCOMPARE(event->angleDelta(), QPoint(0, 0));
+ QCOMPARE(event->pixelDelta(), QPoint(0, 0));
+ }
+
+ // The axis vector of the event is already in surface space, so there is now way to tell
+ // whether it is inverted or not.
+ QCOMPARE(event->inverted(), false);
+
+ // We didn't press any buttons
+ QCOMPARE(event->buttons(), Qt::NoButton);
+
+ m_events.append(Event{event});
+ }
+ struct Event // Because I didn't find a convenient way to copy it entirely
+ {
+ explicit Event() = default;
+ explicit Event(const QWheelEvent *event)
+ : phase(event->phase())
+ , pixelDelta(event->pixelDelta())
+ , angleDelta(event->angleDelta())
+ , source(event->source())
+ {
+ }
+ Qt::ScrollPhase phase{};
+ QPoint pixelDelta;
+ QPoint angleDelta; // eights of a degree, positive is upwards, left
+ Qt::MouseEventSource source{};
+ };
+ QList<Event> m_events;
+};
+
+void tst_seatv7::wheelDiscreteScroll_data()
+{
+ QTest::addColumn<uint>("source");
+ QTest::newRow("wheel") << uint(Pointer::axis_source_wheel);
+ QTest::newRow("wheel tilt") << uint(Pointer::axis_source_wheel_tilt);
+}
+
+void tst_seatv7::wheelDiscreteScroll()
+{
+ WheelWindow window;
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ QFETCH(uint, source);
+
+ exec([&] {
+ auto *p = pointer();
+ auto *c = client();
+ p->sendEnter(xdgToplevel()->surface(), {32, 32});
+ p->sendFrame(c);
+ p->sendAxisSource(c, Pointer::axis_source(source));
+ p->sendAxisDiscrete(c, Pointer::axis_vertical_scroll, 1); // 1 click downwards
+ p->sendAxis(c, Pointer::axis_vertical_scroll, 1.0);
+ p->sendFrame(c);
+ });
+
+ QTRY_VERIFY(!window.m_events.empty());
+ {
+ auto e = window.m_events.takeFirst();
+ QCOMPARE(e.phase, Qt::NoScrollPhase);
+ QVERIFY(qAbs(e.angleDelta.x()) <= qAbs(e.angleDelta.y())); // Vertical scroll
+ // According to the docs the angle delta is in eights of a degree and most mice have
+ // 1 click = 15 degrees. The angle delta should therefore be:
+ // 15 degrees / (1/8 eights per degrees) = 120 eights of degrees.
+ QCOMPARE(e.angleDelta, QPoint(0, -120));
+ // Click scrolls are not continuous and should not have a pixel delta
+ QCOMPARE(e.pixelDelta, QPoint(0, 0));
+ }
+}
+
+QCOMPOSITOR_TEST_MAIN(tst_seatv7)
+#include "tst_seatv7.moc"
diff --git a/tests/auto/client/shared/CMakeLists.txt b/tests/auto/client/shared/CMakeLists.txt
index b028dff16..1d64f2956 100644
--- a/tests/auto/client/shared/CMakeLists.txt
+++ b/tests/auto/client/shared/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
#####################################################################
##Client test shared components:
#####################################################################
@@ -8,9 +11,12 @@ qt_manual_moc(moc_files
corecompositor.h
datadevice.h
fullscreenshellv1.h
+ fractionalscalev1.h
iviapplication.h
textinput.h
qttextinput.h
+ viewport.h
+ xdgdialog.h
xdgoutputv1.h
xdgshell.h
)
@@ -21,33 +27,44 @@ add_library(SharedClientTest
coreprotocol.cpp coreprotocol.h
datadevice.cpp datadevice.h
fullscreenshellv1.cpp fullscreenshellv1.h
+ fractionalscalev1.cpp fractionalscalev1.h
iviapplication.cpp iviapplication.h
mockcompositor.cpp mockcompositor.h
textinput.cpp textinput.h
qttextinput.cpp qttextinput.h
xdgoutputv1.cpp xdgoutputv1.h
xdgshell.cpp xdgshell.h
+ xdgdialog.cpp xdgdialog.h
+ viewport.cpp viewport.h
${moc_files}
)
qt6_generate_wayland_protocol_server_sources(SharedClientTest
FILES
+ ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/cursor-shape-v1.xml
${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/fullscreen-shell-unstable-v1.xml
${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/ivi-application.xml
${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/wp-primary-selection-unstable-v1.xml
${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/tablet-unstable-v2.xml
${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/text-input-unstable-v2.xml
${PROJECT_SOURCE_DIR}/src/extensions/qt-text-input-method-unstable-v1.xml
+ ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/fractional-scale-v1.xml
+ ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/viewporter.xml
${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/wayland.xml
${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/xdg-decoration-unstable-v1.xml
+ ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/xdg-dialog-v1.xml
${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/xdg-output-unstable-v1.xml
${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/xdg-shell.xml
)
+if(QT_FEATURE_opengl)
+ set(optional_libraries Qt::OpenGL)
+endif()
+
target_link_libraries(SharedClientTest
PUBLIC
Qt::Gui
- Qt::OpenGL
+ ${optional_libraries}
Qt::WaylandClientPrivate
Wayland::Server
Threads::Threads # special case
diff --git a/tests/auto/client/shared/corecompositor.cpp b/tests/auto/client/shared/corecompositor.cpp
index 38930c540..d110768ec 100644
--- a/tests/auto/client/shared/corecompositor.cpp
+++ b/tests/auto/client/shared/corecompositor.cpp
@@ -1,15 +1,14 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "corecompositor.h"
#include <thread>
namespace MockCompositor {
-CoreCompositor::CoreCompositor(CompositorType t)
+CoreCompositor::CoreCompositor(CompositorType t, int socketFd)
: m_type(t)
, m_display(wl_display_create())
- , m_socketName(wl_display_add_socket_auto(m_display))
, m_eventLoop(wl_display_get_event_loop(m_display))
// Start dispatching
@@ -20,7 +19,12 @@ CoreCompositor::CoreCompositor(CompositorType t)
}
})
{
- qputenv("WAYLAND_DISPLAY", m_socketName);
+ if (socketFd == -1) {
+ QByteArray socketName = wl_display_add_socket_auto(m_display);
+ qputenv("WAYLAND_DISPLAY", socketName);
+ } else {
+ wl_display_add_socket_fd(m_display, socketFd);
+ }
m_timer.start();
Q_ASSERT(isClean());
}
@@ -29,13 +33,15 @@ CoreCompositor::~CoreCompositor()
{
m_running = false;
m_dispatchThread.join();
+ wl_display_destroy_clients(m_display);
wl_display_destroy(m_display);
+ qDebug() << "cleanup";
}
bool CoreCompositor::isClean()
{
Lock lock(this);
- for (auto *global : qAsConst(m_globals)) {
+ for (auto *global : std::as_const(m_globals)) {
if (!global->isClean())
return false;
}
@@ -46,7 +52,7 @@ QString CoreCompositor::dirtyMessage()
{
Lock lock(this);
QStringList messages;
- for (auto *global : qAsConst(m_globals)) {
+ for (auto *global : std::as_const(m_globals)) {
if (!global->isClean())
messages << (global->metaObject()->className() % QLatin1String(": ") % global->dirtyMessage());
}
diff --git a/tests/auto/client/shared/corecompositor.h b/tests/auto/client/shared/corecompositor.h
index 2edb7f3fc..2df1b5758 100644
--- a/tests/auto/client/shared/corecompositor.h
+++ b/tests/auto/client/shared/corecompositor.h
@@ -1,5 +1,5 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef MOCKCOMPOSITOR_CORECOMPOSITOR_H
#define MOCKCOMPOSITOR_CORECOMPOSITOR_H
@@ -29,7 +29,8 @@ public:
};
CompositorType m_type = Default;
- explicit CoreCompositor(CompositorType t = Default);
+ explicit CoreCompositor(CompositorType t = Default, int socketFd = -1);
+
~CoreCompositor();
bool isClean();
QString dirtyMessage();
@@ -98,7 +99,7 @@ public:
global_type *get()
{
warnIfNotLockedByThread(Q_FUNC_INFO);
- for (auto *global : qAsConst(m_globals)) {
+ for (auto *global : std::as_const(m_globals)) {
if (auto *casted = qobject_cast<global_type *>(global))
return casted;
}
@@ -112,7 +113,7 @@ public:
global_type *get(int index)
{
warnIfNotLockedByThread(Q_FUNC_INFO);
- for (auto *global : qAsConst(m_globals)) {
+ for (auto *global : std::as_const(m_globals)) {
if (auto *casted = qobject_cast<global_type *>(global)) {
if (index--)
continue;
@@ -130,7 +131,7 @@ public:
{
warnIfNotLockedByThread(Q_FUNC_INFO);
QList<global_type *> matching;
- for (auto *global : qAsConst(m_globals)) {
+ for (auto *global : std::as_const(m_globals)) {
if (auto *casted = qobject_cast<global_type *>(global))
matching.append(casted);
}
@@ -178,7 +179,6 @@ protected:
CoreCompositor *m_compositor = nullptr;
std::thread::id m_threadId;
};
- QByteArray m_socketName;
wl_event_loop *m_eventLoop = nullptr;
bool m_running = true;
QList<Global *> m_globals;
diff --git a/tests/auto/client/shared/coreprotocol.cpp b/tests/auto/client/shared/coreprotocol.cpp
index 5a59938de..833ad4b09 100644
--- a/tests/auto/client/shared/coreprotocol.cpp
+++ b/tests/auto/client/shared/coreprotocol.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "coreprotocol.h"
#include "datadevice.h"
@@ -109,7 +109,7 @@ void Surface::surface_commit(Resource *resource)
}
}
- for (wl_resource *frameCallback : qExchange(m_frameCallbackList, {})) {
+ for (wl_resource *frameCallback : std::exchange(m_frameCallbackList, {})) {
auto time = m_wlCompositor->m_compositor->currentTimeMilliseconds();
wl_callback_send_done(frameCallback, time);
wl_resource_destroy(frameCallback);
@@ -144,7 +144,7 @@ void Surface::surface_frame(Resource *resource, uint32_t callback)
}
bool WlCompositor::isClean() {
- for (auto *surface : qAsConst(m_surfaces)) {
+ for (auto *surface : std::as_const(m_surfaces)) {
if (!CursorRole::fromSurface(surface)) {
if (m_compositor->m_type != CoreCompositor::CompositorType::Legacy)
return false;
@@ -160,7 +160,7 @@ QString WlCompositor::dirtyMessage()
if (isClean())
return "clean";
QStringList messages;
- for (auto *s : qAsConst(m_surfaces)) {
+ for (auto *s : std::as_const(m_surfaces)) {
QString role = s->m_role ? s->m_role->staticMetaObject.className(): "none/unknown";
messages << "Surface with role: " + role;
}
@@ -226,6 +226,8 @@ void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource
if (m_version >= WL_OUTPUT_DONE_SINCE_VERSION)
wl_output::send_done(resource->handle);
+
+ Q_EMIT outputBound(resource);
}
// Seat stuff
@@ -336,7 +338,7 @@ uint Pointer::sendEnter(Surface *surface, const QPointF &position)
uint serial = m_seat->m_compositor->nextSerial();
m_enterSerials << serial;
- m_cursorRole = nullptr; // According to the protocol, the pointer image is undefined after enter
+ m_cursorRole.clear(); // According to the protocol, the pointer image is undefined after enter
wl_client *client = surface->resource()->client();
const auto pointerResources = resourceMap().values(client);
@@ -423,18 +425,36 @@ void Pointer::sendFrame(wl_client *client)
send_frame(r->handle);
}
+void Pointer::sendAxisValue120(wl_client *client, QtWaylandServer::wl_pointer::axis axis, int value120)
+{
+ const auto pointerResources = resourceMap().values(client);
+ for (auto *r : pointerResources)
+ send_axis_value120(r->handle, axis, value120);
+}
+
+void Pointer::sendAxisRelativeDirection(wl_client *client, QtWaylandServer::wl_pointer::axis axis, QtWaylandServer::wl_pointer::axis_relative_direction direction)
+{
+ const auto pointerResources = resourceMap().values(client);
+ for (auto *r : pointerResources)
+ send_axis_relative_direction(r->handle, axis, direction);
+}
+
void Pointer::pointer_set_cursor(Resource *resource, uint32_t serial, wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y)
{
Q_UNUSED(resource);
- auto *s = fromResource<Surface>(surface);
- QVERIFY(s);
- if (s->m_role) {
- m_cursorRole = CursorRole::fromSurface(s);
- QVERIFY(m_cursorRole);
+ if (!surface) {
+ m_cursorRole = nullptr;
} else {
- m_cursorRole = new CursorRole(s); //TODO: make sure we don't leak CursorRole
- s->m_role = m_cursorRole;
+ auto *s = fromResource<Surface>(surface);
+ QVERIFY(s);
+ if (s->m_role) {
+ m_cursorRole = CursorRole::fromSurface(s);
+ QVERIFY(m_cursorRole);
+ } else {
+ m_cursorRole = new CursorRole(s); //TODO: make sure we don't leak CursorRole
+ s->m_role = m_cursorRole;
+ }
}
// Directly checking the last serial would be racy, we may just have sent leaves/enters which
@@ -493,6 +513,13 @@ void Touch::sendFrame(wl_client *client)
send_frame(r->handle);
}
+void Touch::sendCancel(wl_client *client)
+{
+ const auto touchResources = resourceMap().values(client);
+ for (auto *r : touchResources)
+ send_cancel(r->handle);
+}
+
uint Keyboard::sendEnter(Surface *surface)
{
auto serial = m_seat->m_compositor->nextSerial();
@@ -540,7 +567,7 @@ Shm::Shm(CoreCompositor *compositor, QList<format> formats, int version)
bool Shm::isClean()
{
-// for (ShmPool *pool : qAsConst(m_pools)) {
+// for (ShmPool *pool : std::as_const(m_pools)) {
// //TODO: return false if not cursor buffer
// if (pool->m_buffers.isEmpty()) {
// return false;
diff --git a/tests/auto/client/shared/coreprotocol.h b/tests/auto/client/shared/coreprotocol.h
index e43451cea..0f59441a3 100644
--- a/tests/auto/client/shared/coreprotocol.h
+++ b/tests/auto/client/shared/coreprotocol.h
@@ -1,11 +1,13 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef MOCKCOMPOSITOR_COREPROTOCOL_H
#define MOCKCOMPOSITOR_COREPROTOCOL_H
#include "corecompositor.h"
+#include <QtCore/qpointer.h>
+
#include <qwayland-server-wayland.h>
namespace MockCompositor {
@@ -288,6 +290,9 @@ public:
OutputData m_data;
int m_version = 1; // TODO: remove on libwayland upgrade
+Q_SIGNALS:
+ void outputBound(Resource *resource);
+
protected:
void output_bind_resource(Resource *resource) override;
};
@@ -296,7 +301,7 @@ class Seat : public Global, public QtWaylandServer::wl_seat
{
Q_OBJECT
public:
- explicit Seat(CoreCompositor *compositor, uint capabilities = Seat::capability_pointer | Seat::capability_keyboard | Seat::capability_touch, int version = 7);
+ explicit Seat(CoreCompositor *compositor, uint capabilities = Seat::capability_pointer | Seat::capability_keyboard | Seat::capability_touch, int version = 9);
~Seat() override;
void send_capabilities(Resource *resource, uint capabilities) = delete; // Use wrapper instead
void send_capabilities(uint capabilities) = delete; // Use wrapper instead
@@ -334,7 +339,7 @@ class Pointer : public QObject, public QtWaylandServer::wl_pointer
public:
explicit Pointer(Seat *seat) : m_seat(seat) {}
Surface *cursorSurface();
- CursorRole* m_cursorRole = nullptr; //TODO: cleanup
+ QPointer<CursorRole> m_cursorRole;
void send_enter() = delete;
uint sendEnter(Surface *surface, const QPointF &position);
void send_leave() = delete;
@@ -346,6 +351,8 @@ public:
void sendAxisSource(wl_client *client, axis_source source);
void sendAxisStop(wl_client *client, axis axis);
void sendFrame(wl_client *client);
+ void sendAxisValue120(wl_client *client, axis axis, int value120);
+ void sendAxisRelativeDirection(wl_client *client, axis axis, axis_relative_direction direction);
Seat *m_seat = nullptr;
QList<uint> m_enterSerials;
@@ -365,6 +372,7 @@ public:
explicit CursorRole(Surface *surface) // TODO: needs some more args
: m_surface(surface)
{
+ connect(m_surface, &QObject::destroyed, this, &QObject::deleteLater);
}
static CursorRole *fromSurface(Surface *surface) { return qobject_cast<CursorRole *>(surface->m_role); }
Surface *m_surface = nullptr;
@@ -379,6 +387,7 @@ public:
uint sendUp(wl_client *client, int id);
void sendMotion(wl_client *client, const QPointF &position, int id);
void sendFrame(wl_client *client);
+ void sendCancel(wl_client *client);
Seat *m_seat = nullptr;
};
@@ -410,7 +419,7 @@ protected:
void shm_create_pool(Resource *resource, uint32_t id, int32_t fd, int32_t size) override;
void shm_bind_resource(Resource *resource) override
{
- for (auto format : qAsConst(m_formats))
+ for (auto format : std::as_const(m_formats))
send_format(resource->handle, format);
}
};
diff --git a/tests/auto/client/shared/datadevice.cpp b/tests/auto/client/shared/datadevice.cpp
index 100f937d3..efb88d0b1 100644
--- a/tests/auto/client/shared/datadevice.cpp
+++ b/tests/auto/client/shared/datadevice.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "datadevice.h"
@@ -7,7 +7,7 @@ namespace MockCompositor {
bool DataDeviceManager::isClean()
{
- for (auto *device : qAsConst(m_dataDevices)) {
+ for (auto *device : std::as_const(m_dataDevices)) {
// The client should not leak selection offers, i.e. if this fails, there is a missing
// data_offer.destroy request
if (!device->m_sentSelectionOffers.empty())
@@ -51,7 +51,7 @@ DataOffer *DataDevice::sendDataOffer(wl_client *client, const QStringList &mimeT
{
Q_ASSERT(client);
auto *offer = new DataOffer(this, client, m_manager->m_version);
- m_offers << offer;
+ m_offer = offer;
for (auto *resource : resourceMap().values(client))
wl_data_device::send_data_offer(resource->handle, offer->resource()->handle);
for (const auto &mimeType : mimeTypes)
@@ -71,8 +71,8 @@ void DataDevice::sendEnter(Surface *surface, const QPoint &position)
{
uint serial = m_manager->m_compositor->nextSerial();
Resource *resource = resourceMap().value(surface->resource()->client());
- for (DataOffer *offer: m_offers)
- wl_data_device::send_enter(resource->handle, serial, surface->resource()->handle, position.x(), position.y(), offer->resource()->handle);
+ if (m_offer)
+ wl_data_device::send_enter(resource->handle, serial, surface->resource()->handle, position.x(), position.y(), m_offer->resource()->handle);
}
void DataDevice::sendMotion(Surface *surface, const QPoint &position)
@@ -108,10 +108,7 @@ void DataOffer::data_offer_receive(Resource *resource, const QString &mime_type,
void DataOffer::data_offer_destroy(QtWaylandServer::wl_data_offer::Resource *resource)
{
- bool removed = m_dataDevice->m_sentSelectionOffers.removeOne(this);
- if (!removed)
- removed = m_dataDevice->m_offers.removeOne(this);
- QVERIFY(removed);
+ m_dataDevice->m_sentSelectionOffers.removeOne(this);
wl_resource_destroy(resource->handle);
}
diff --git a/tests/auto/client/shared/datadevice.h b/tests/auto/client/shared/datadevice.h
index ee1e57d65..356dfa74a 100644
--- a/tests/auto/client/shared/datadevice.h
+++ b/tests/auto/client/shared/datadevice.h
@@ -1,5 +1,5 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef MOCKCOMPOSITOR_DATADEVICE_H
#define MOCKCOMPOSITOR_DATADEVICE_H
@@ -63,7 +63,7 @@ public:
DataDeviceManager *m_manager = nullptr;
Seat *m_seat = nullptr;
QList<DataOffer *> m_sentSelectionOffers;
- QList<DataOffer *> m_offers;
+ QPointer<DataOffer> m_offer;
signals:
void dragStarted();
diff --git a/tests/auto/client/shared/fractionalscalev1.cpp b/tests/auto/client/shared/fractionalscalev1.cpp
new file mode 100644
index 000000000..28c778025
--- /dev/null
+++ b/tests/auto/client/shared/fractionalscalev1.cpp
@@ -0,0 +1,40 @@
+// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "fractionalscalev1.h"
+
+namespace MockCompositor {
+
+FractionalScaleManager::FractionalScaleManager(CoreCompositor *compositor, int version)
+ : QtWaylandServer::wp_fractional_scale_manager_v1(compositor->m_display, version)
+{
+}
+
+void FractionalScaleManager::wp_fractional_scale_manager_v1_get_fractional_scale(Resource *resource, uint32_t id, wl_resource *surface)
+{
+ auto *s = fromResource<Surface>(surface);
+ auto *scaler = new FractionalScale(s, resource->client(), id, resource->version());
+ connect(scaler, &QObject::destroyed, this, [this, scaler]() {
+ m_fractionalScales.removeOne(scaler);
+ });
+ m_fractionalScales << scaler;
+}
+
+FractionalScale::FractionalScale(Surface *surface, wl_client *client, int id, int version)
+ : QtWaylandServer::wp_fractional_scale_v1(client, id, version)
+ , m_surface(surface)
+{
+}
+
+void FractionalScale::wp_fractional_scale_v1_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource)
+ delete this;
+}
+
+void FractionalScale::wp_fractional_scale_v1_destroy(Resource *resource)
+{
+ wl_resource_destroy(resource->handle);
+}
+
+}
diff --git a/tests/auto/client/shared/fractionalscalev1.h b/tests/auto/client/shared/fractionalscalev1.h
new file mode 100644
index 000000000..1ae2fad1f
--- /dev/null
+++ b/tests/auto/client/shared/fractionalscalev1.h
@@ -0,0 +1,39 @@
+// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef MOCKCOMPOSITOR_FRACTIONALSCALE_H
+#define MOCKCOMPOSITOR_FRACTIONALSCALE_H
+
+#include "coreprotocol.h"
+#include <qwayland-server-fractional-scale-v1.h>
+
+namespace MockCompositor {
+
+class FractionalScale;
+
+class FractionalScaleManager : public Global, public QtWaylandServer::wp_fractional_scale_manager_v1
+{
+ Q_OBJECT
+public:
+ explicit FractionalScaleManager(CoreCompositor *compositor, int version = 1);
+ QList<FractionalScale *> m_fractionalScales;
+
+protected:
+ void wp_fractional_scale_manager_v1_get_fractional_scale(Resource *resource, uint32_t id, wl_resource *surface) override;
+};
+
+class FractionalScale : public QObject, public QtWaylandServer::wp_fractional_scale_v1
+{
+ Q_OBJECT
+public:
+ explicit FractionalScale(Surface *surface, wl_client *client, int id, int version);
+ Surface *m_surface;
+
+protected:
+ void wp_fractional_scale_v1_destroy_resource(Resource *resource) override;
+ void wp_fractional_scale_v1_destroy(Resource *resource) override;
+};
+
+}
+
+#endif
diff --git a/tests/auto/client/shared/fullscreenshellv1.cpp b/tests/auto/client/shared/fullscreenshellv1.cpp
index 105557fb5..24468e14b 100644
--- a/tests/auto/client/shared/fullscreenshellv1.cpp
+++ b/tests/auto/client/shared/fullscreenshellv1.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2021 David Edmundson <davidedmundson@kde.org>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "fullscreenshellv1.h"
diff --git a/tests/auto/client/shared/fullscreenshellv1.h b/tests/auto/client/shared/fullscreenshellv1.h
index fb0b3f8d6..02ebf1e0c 100644
--- a/tests/auto/client/shared/fullscreenshellv1.h
+++ b/tests/auto/client/shared/fullscreenshellv1.h
@@ -1,5 +1,5 @@
// Copyright (C) 2021 David Edmundson <davidedmundson@kde.org>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef MOCKCOMPOSITOR_FULLSCREENSHELLV1_H
#define MOCKCOMPOSITOR_FULLSCREENSHELLV1_H
diff --git a/tests/auto/client/shared/iviapplication.cpp b/tests/auto/client/shared/iviapplication.cpp
index 7d487d284..f4f167600 100644
--- a/tests/auto/client/shared/iviapplication.cpp
+++ b/tests/auto/client/shared/iviapplication.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2021 David Edmundson <davidedmundson@kde.org>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "iviapplication.h"
@@ -15,7 +15,7 @@ void IviApplication::ivi_application_surface_create(Resource *resource, uint32_t
auto *s = fromResource<Surface>(surface);
auto *iviSurface = new IviSurface(this, s, ivi_id, resource->client(), id, resource->version());
m_iviSurfaces << iviSurface;
- qDebug() << "count is " << m_iviSurfaces.count();
+ qDebug() << "count is " << m_iviSurfaces.size();
}
IviSurface::IviSurface(IviApplication *iviApplication, Surface *surface, uint32_t ivi_id, wl_client *client, int id, int version)
diff --git a/tests/auto/client/shared/iviapplication.h b/tests/auto/client/shared/iviapplication.h
index afbb71134..1644d0cfd 100644
--- a/tests/auto/client/shared/iviapplication.h
+++ b/tests/auto/client/shared/iviapplication.h
@@ -1,5 +1,5 @@
// Copyright (C) 2021 David Edmundson <davidedmundson@kde.org>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef MOCKCOMPOSITOR_IVIAPPLICATION_H
#define MOCKCOMPOSITOR_IVIAPPLICATION_H
diff --git a/tests/auto/client/shared/mockcompositor.cpp b/tests/auto/client/shared/mockcompositor.cpp
index 03d0ffb6c..bbf406d64 100644
--- a/tests/auto/client/shared/mockcompositor.cpp
+++ b/tests/auto/client/shared/mockcompositor.cpp
@@ -1,13 +1,13 @@
// Copyright (C) 2021 David Edmundson <davidedmundson@kde.org>
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockcompositor.h"
namespace MockCompositor {
-DefaultCompositor::DefaultCompositor(CompositorType t)
- : CoreCompositor(t)
+DefaultCompositor::DefaultCompositor(CompositorType t, int socketFd)
+ : CoreCompositor(t, socketFd)
{
{
Lock l(this);
@@ -21,6 +21,10 @@ DefaultCompositor::DefaultCompositor(CompositorType t)
add<Seat>(Seat::capability_pointer | Seat::capability_keyboard | Seat::capability_touch);
add<WlShell>();
add<XdgWmBase>();
+ add<FractionalScaleManager>();
+ add<Viewporter>();
+ add<XdgWmDialog>();
+
switch (m_type) {
case CompositorType::Default:
add<Shm>();
@@ -34,19 +38,22 @@ DefaultCompositor::DefaultCompositor(CompositorType t)
// TODO: other shells, viewporter, xdgoutput etc
- QObject::connect(get<WlCompositor>(), &WlCompositor::surfaceCreated, [&] (Surface *surface){
- QObject::connect(surface, &Surface::bufferCommitted, [=] {
+ QObject::connect(get<WlCompositor>(), &WlCompositor::surfaceCreated, [this] (Surface *surface){
+ QObject::connect(surface, &Surface::bufferCommitted, [this, surface] {
if (m_config.autoRelease) {
// Pretend we made a copy of the buffer and just release it immediately
surface->m_committed.buffer->send_release();
}
+ if (m_config.autoFrameCallback) {
+ surface->sendFrameCallbacks();
+ }
if (m_config.autoEnter && get<Output>() && surface->m_outputs.empty())
surface->sendEnter(get<Output>());
wl_display_flush_clients(m_display);
});
});
- QObject::connect(get<XdgWmBase>(), &XdgWmBase::toplevelCreated, get<XdgWmBase>(), [&] (XdgToplevel *toplevel) {
+ QObject::connect(get<XdgWmBase>(), &XdgWmBase::toplevelCreated, get<XdgWmBase>(), [this] (XdgToplevel *toplevel) {
if (m_config.autoConfigure)
toplevel->sendCompleteConfigure();
}, Qt::DirectConnection);
@@ -90,9 +97,9 @@ uint DefaultCompositor::sendXdgShellPing()
void DefaultCompositor::xdgPingAndWaitForPong()
{
- QSignalSpy pongSpy(exec([=] { return get<XdgWmBase>(); }), &XdgWmBase::pong);
- uint serial = exec([=] { return sendXdgShellPing(); });
- QTRY_COMPARE(pongSpy.count(), 1);
+ QSignalSpy pongSpy(exec([&] { return get<XdgWmBase>(); }), &XdgWmBase::pong);
+ uint serial = exec([&] { return sendXdgShellPing(); });
+ QTRY_COMPARE(pongSpy.size(), 1);
QTRY_COMPARE(pongSpy.first().at(0).toUInt(), serial);
}
diff --git a/tests/auto/client/shared/mockcompositor.h b/tests/auto/client/shared/mockcompositor.h
index 3b70a430e..9a2c06a17 100644
--- a/tests/auto/client/shared/mockcompositor.h
+++ b/tests/auto/client/shared/mockcompositor.h
@@ -1,6 +1,6 @@
// Copyright (C) 2021 David Edmundson <davidedmundson@kde.org>
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef MOCKCOMPOSITOR_H
#define MOCKCOMPOSITOR_H
@@ -11,6 +11,9 @@
#include "fullscreenshellv1.h"
#include "iviapplication.h"
#include "xdgshell.h"
+#include "viewport.h"
+#include "fractionalscalev1.h"
+#include "xdgdialog.h"
#include <QtGui/QGuiApplication>
@@ -30,7 +33,7 @@ namespace MockCompositor {
class DefaultCompositor : public CoreCompositor
{
public:
- explicit DefaultCompositor(CompositorType t = CompositorType::Default);
+ explicit DefaultCompositor(CompositorType t = CompositorType::Default, int socketFd = -1);
// Convenience functions
Output *output(int i = 0) { return getAll<Output>().value(i, nullptr); }
Surface *surface(int i = 0);
@@ -46,6 +49,9 @@ public:
Keyboard *keyboard() { auto *seat = get<Seat>(); Q_ASSERT(seat); return seat->m_keyboard; }
FullScreenShellV1 *fullScreenShellV1() {return get<FullScreenShellV1>();};
IviSurface *iviSurface(int i = 0) { return get<IviApplication>()->m_iviSurfaces.value(i, nullptr); }
+ FractionalScale *fractionalScale(int i = 0) {return get<FractionalScaleManager>()->m_fractionalScales.value(i, nullptr); }
+ Viewport *viewport(int i = 0) {return get<Viewporter>()->m_viewports.value(i, nullptr); }
+ XdgDialog *xdgDialog(int i = 0) { return get<XdgWmDialog>()->m_dialogs.value(i, nullptr); }
uint sendXdgShellPing();
void xdgPingAndWaitForPong();
@@ -57,6 +63,7 @@ public:
bool autoEnter = true;
bool autoRelease = true;
bool autoConfigure = false;
+ bool autoFrameCallback = true;
} m_config;
void resetConfig() { exec([&] { m_config = Config{}; }); }
};
diff --git a/tests/auto/client/shared/qttextinput.cpp b/tests/auto/client/shared/qttextinput.cpp
index 30cc2afd4..1fb5ef1c4 100644
--- a/tests/auto/client/shared/qttextinput.cpp
+++ b/tests/auto/client/shared/qttextinput.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qttextinput.h"
diff --git a/tests/auto/client/shared/qttextinput.h b/tests/auto/client/shared/qttextinput.h
index a3eb31270..047cec7d3 100644
--- a/tests/auto/client/shared/qttextinput.h
+++ b/tests/auto/client/shared/qttextinput.h
@@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef MOCKCOMPOSITOR_QTTEXTINPUT_H
#define MOCKCOMPOSITOR_QTTEXTINPUT_H
diff --git a/tests/auto/client/shared/textinput.cpp b/tests/auto/client/shared/textinput.cpp
index 05889687c..fc4865d71 100644
--- a/tests/auto/client/shared/textinput.cpp
+++ b/tests/auto/client/shared/textinput.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "textinput.h"
@@ -12,9 +12,8 @@ TextInputManager::TextInputManager(CoreCompositor *compositor)
void TextInputManager::zwp_text_input_manager_v2_get_text_input(Resource *resource, uint32_t id, wl_resource *seatResource)
{
- Q_UNUSED(resource);
- Q_UNUSED(id);
Q_UNUSED(seatResource);
+ add(resource->client(), id, resource->version());
}
} // namespace MockCompositor
diff --git a/tests/auto/client/shared/textinput.h b/tests/auto/client/shared/textinput.h
index 2aedf550b..ca20ddbad 100644
--- a/tests/auto/client/shared/textinput.h
+++ b/tests/auto/client/shared/textinput.h
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef MOCKCOMPOSITOR_TEXTINPUT_H
#define MOCKCOMPOSITOR_TEXTINPUT_H
diff --git a/tests/auto/client/shared/viewport.cpp b/tests/auto/client/shared/viewport.cpp
new file mode 100644
index 000000000..df6bbb336
--- /dev/null
+++ b/tests/auto/client/shared/viewport.cpp
@@ -0,0 +1,58 @@
+// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "viewport.h"
+
+namespace MockCompositor {
+
+Viewporter::Viewporter(CoreCompositor *compositor, int version)
+ : QtWaylandServer::wp_viewporter(compositor->m_display, version)
+{
+}
+
+void Viewporter::wp_viewporter_get_viewport(Resource *resource, uint32_t id, wl_resource *surface)
+{
+ auto *s = fromResource<Surface>(surface);
+ auto *viewport = new Viewport(s, resource->client(), id, resource->version());
+ connect(viewport, &QObject::destroyed, this, [this, viewport]() {
+ m_viewports.removeOne(viewport);
+ });
+ m_viewports << viewport;
+}
+
+Viewport::Viewport(Surface *surface, wl_client *client, int id, int version)
+ : QtWaylandServer::wp_viewport(client, id, version)
+ , m_surface(surface)
+{
+}
+
+void Viewport::wp_viewport_set_source(Resource *resource, wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height)
+{
+ Q_UNUSED(resource)
+ m_source = QRectF(wl_fixed_to_double(x),
+ wl_fixed_to_double(y),
+ wl_fixed_to_double(width),
+ wl_fixed_to_double(height));
+ Q_EMIT sourceChanged();
+}
+
+void Viewport::wp_viewport_set_destination(Resource *resource, int32_t width, int32_t height)
+{
+ Q_UNUSED(resource)
+
+ m_destination = QSize(width, height);
+ Q_EMIT destinationChanged();
+}
+
+void Viewport::wp_viewport_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource)
+ delete this;
+}
+
+void Viewport::wp_viewport_destroy(Resource *resource)
+{
+ wl_resource_destroy(resource->handle);
+}
+
+}
diff --git a/tests/auto/client/shared/viewport.h b/tests/auto/client/shared/viewport.h
new file mode 100644
index 000000000..ddc4297db
--- /dev/null
+++ b/tests/auto/client/shared/viewport.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2022 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef MOCKCOMPOSITOR_VIEWPORT_H
+#define MOCKCOMPOSITOR_VIEWPORT_H
+
+#include "coreprotocol.h"
+#include <qwayland-server-viewporter.h>
+
+namespace MockCompositor {
+
+class Viewport;
+
+class Viewporter : public Global, public QtWaylandServer::wp_viewporter
+{
+ Q_OBJECT
+public:
+ explicit Viewporter(CoreCompositor *compositor, int version = 1);
+ QList<Viewport *> m_viewports;
+
+protected:
+ void wp_viewporter_get_viewport(Resource *resource, uint32_t id, wl_resource *surface) override;
+};
+
+class Viewport : public QObject, public QtWaylandServer::wp_viewport
+{
+ Q_OBJECT
+public:
+ explicit Viewport(Surface *surface, wl_client *client, int id, int version);
+
+ QRectF m_source;
+ QSize m_destination;
+
+ Surface* m_surface;
+
+Q_SIGNALS:
+ void sourceChanged();
+ void destinationChanged();
+
+protected:
+ void wp_viewport_set_source(Resource *resource, wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height) override;
+ void wp_viewport_set_destination(Resource *resource, int32_t width, int32_t height) override;
+
+ void wp_viewport_destroy_resource(Resource *resource) override;
+ void wp_viewport_destroy(Resource *resource) override;
+};
+
+}
+
+#endif
diff --git a/tests/auto/client/shared/xdgdialog.cpp b/tests/auto/client/shared/xdgdialog.cpp
new file mode 100644
index 000000000..b973415bd
--- /dev/null
+++ b/tests/auto/client/shared/xdgdialog.cpp
@@ -0,0 +1,59 @@
+// Copyright (C) 2024 David Redondo <kde@david-redondo.de>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+#include "xdgdialog.h"
+
+#include "xdgshell.h"
+
+namespace MockCompositor {
+
+XdgDialog::XdgDialog(XdgWmDialog *wm, XdgToplevel *toplevel, wl_client *client, int id, int version)
+ : QtWaylandServer::xdg_dialog_v1(client, id, version),
+ toplevel(toplevel),
+ modal(false),
+ m_wm(wm)
+{
+}
+
+void XdgDialog::xdg_dialog_v1_set_modal(Resource *resource)
+{
+ Q_UNUSED(resource)
+ modal = true;
+}
+
+void XdgDialog::xdg_dialog_v1_unset_modal(Resource *resource)
+{
+ Q_UNUSED(resource)
+ modal = false;
+}
+
+void XdgDialog::xdg_dialog_v1_destroy(Resource *resource)
+{
+ wl_resource_destroy(resource->handle);
+}
+
+void XdgDialog::xdg_dialog_v1_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource)
+ m_wm->m_dialogs.removeOne(this);
+ delete this;
+}
+
+XdgWmDialog::XdgWmDialog(CoreCompositor *compositor, int version)
+ : QtWaylandServer::xdg_wm_dialog_v1(compositor->m_display, version)
+{
+}
+
+void XdgWmDialog::xdg_wm_dialog_v1_destroy(Resource *resource)
+{
+ wl_resource_destroy(resource->handle);
+}
+
+void XdgWmDialog::xdg_wm_dialog_v1_get_xdg_dialog(Resource *resource, uint32_t id,
+ struct ::wl_resource *toplevel)
+{
+ auto *t = fromResource<XdgToplevel>(toplevel);
+ auto *dialog = new XdgDialog(this, t, resource->client(), id, resource->version());
+ m_dialogs.push_back(dialog);
+}
+
+} // namespace MockCompositor
diff --git a/tests/auto/client/shared/xdgdialog.h b/tests/auto/client/shared/xdgdialog.h
new file mode 100644
index 000000000..d9e3de996
--- /dev/null
+++ b/tests/auto/client/shared/xdgdialog.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2024 David Redondo <kde@david-redondo.de>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef MOCKCOMPOSITOR_XDG_DIALOG_H
+#define MOCKCOMPOSITOR_XDG_DIALOG_H
+
+#include "corecompositor.h"
+#include <qwayland-server-xdg-dialog-v1.h>
+
+namespace MockCompositor {
+
+class XdgToplevel;
+class XdgWmDialog;
+
+class XdgDialog : public QtWaylandServer::xdg_dialog_v1
+{
+public:
+ explicit XdgDialog(XdgWmDialog *wm, XdgToplevel *toplevel, wl_client *client, int id,
+ int version);
+ XdgToplevel *toplevel;
+ bool modal;
+
+protected:
+ void xdg_dialog_v1_set_modal(Resource *resource) override;
+ void xdg_dialog_v1_unset_modal(Resource *resource) override;
+ void xdg_dialog_v1_destroy(Resource *resource) override;
+ void xdg_dialog_v1_destroy_resource(Resource *resource) override;
+
+private:
+ XdgWmDialog *m_wm;
+};
+
+class XdgWmDialog : public Global, public QtWaylandServer::xdg_wm_dialog_v1
+{
+ Q_OBJECT
+public:
+ explicit XdgWmDialog(CoreCompositor *compositor, int version = 1);
+ ~XdgWmDialog() = default;
+ QList<XdgDialog *> m_dialogs;
+
+protected:
+ void xdg_wm_dialog_v1_destroy(Resource *resource) override;
+ void xdg_wm_dialog_v1_get_xdg_dialog(Resource *resource, uint32_t id,
+ struct ::wl_resource *toplevel) override;
+};
+
+} // namespace MockCompositor
+
+#endif
diff --git a/tests/auto/client/shared/xdgoutputv1.cpp b/tests/auto/client/shared/xdgoutputv1.cpp
index f40a2b60b..af72ae2eb 100644
--- a/tests/auto/client/shared/xdgoutputv1.cpp
+++ b/tests/auto/client/shared/xdgoutputv1.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2020 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "xdgoutputv1.h"
diff --git a/tests/auto/client/shared/xdgoutputv1.h b/tests/auto/client/shared/xdgoutputv1.h
index 164171d40..8c6276741 100644
--- a/tests/auto/client/shared/xdgoutputv1.h
+++ b/tests/auto/client/shared/xdgoutputv1.h
@@ -1,5 +1,5 @@
// Copyright (C) 2020 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef MOCKCOMPOSITOR_XDGOUTPUTV1_H
#define MOCKCOMPOSITOR_XDGOUTPUTV1_H
diff --git a/tests/auto/client/shared/xdgshell.cpp b/tests/auto/client/shared/xdgshell.cpp
index b50f36e7d..2c1639851 100644
--- a/tests/auto/client/shared/xdgshell.cpp
+++ b/tests/auto/client/shared/xdgshell.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "xdgshell.h"
@@ -14,7 +14,7 @@ XdgWmBase::XdgWmBase(CoreCompositor *compositor, int version)
XdgToplevel *XdgWmBase::toplevel(int i)
{
int j = 0;
- for (auto *xdgSurface : qAsConst(m_xdgSurfaces)) {
+ for (auto *xdgSurface : std::as_const(m_xdgSurfaces)) {
if (auto *toplevel = xdgSurface->m_toplevel) {
if (j == i)
return toplevel;
@@ -27,7 +27,7 @@ XdgToplevel *XdgWmBase::toplevel(int i)
XdgPopup *XdgWmBase::popup(int i)
{
int j = 0;
- for (auto *xdgSurface : qAsConst(m_xdgSurfaces)) {
+ for (auto *xdgSurface : std::as_const(m_xdgSurfaces)) {
if (auto *popup = xdgSurface->m_popup) {
if (j == i)
return popup;
@@ -143,6 +143,11 @@ XdgToplevel::XdgToplevel(XdgSurface *xdgSurface, int id, int version)
connect(surface(), &Surface::commit, this, [this] { m_committed = m_pending; });
}
+void XdgToplevel::sendConfigureBounds(const QSize &size)
+{
+ send_configure_bounds(size.width(), size.height());
+}
+
void XdgToplevel::sendConfigure(const QSize &size, const QList<uint> &states)
{
send_configure(size.width(), size.height(), toByteArray(states));
diff --git a/tests/auto/client/shared/xdgshell.h b/tests/auto/client/shared/xdgshell.h
index 4c1cd6cdb..3959e0668 100644
--- a/tests/auto/client/shared/xdgshell.h
+++ b/tests/auto/client/shared/xdgshell.h
@@ -1,5 +1,5 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef MOCKCOMPOSITOR_XDGSHELL_H
#define MOCKCOMPOSITOR_XDGSHELL_H
@@ -18,7 +18,7 @@ class XdgWmBase : public Global, public QtWaylandServer::xdg_wm_base
{
Q_OBJECT
public:
- explicit XdgWmBase(CoreCompositor *compositor, int version = 1);
+ explicit XdgWmBase(CoreCompositor *compositor, int version = 4);
using QtWaylandServer::xdg_wm_base::send_ping;
void send_ping(uint32_t) = delete; // It's a global, use resource specific instead
bool isClean() override { return m_xdgSurfaces.empty(); }
@@ -90,6 +90,7 @@ class XdgToplevel : public QObject, public QtWaylandServer::xdg_toplevel
Q_OBJECT
public:
explicit XdgToplevel(XdgSurface *xdgSurface, int id, int version = 1);
+ void sendConfigureBounds(const QSize &size);
void sendConfigure(const QSize &size = {0, 0}, const QList<uint> &states = {});
uint sendCompleteConfigure(const QSize &size = {0, 0}, const QList<uint> &states = {});
Surface *surface() { return m_xdgSurface->m_surface; }
diff --git a/tests/auto/client/surface/CMakeLists.txt b/tests/auto/client/surface/CMakeLists.txt
index 93cfb2fb0..b175a5331 100644
--- a/tests/auto/client/surface/CMakeLists.txt
+++ b/tests/auto/client/surface/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from surface.pro.
#####################################################################
@@ -7,6 +10,6 @@
qt_internal_add_test(tst_surface
SOURCES
tst_surface.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
SharedClientTest
)
diff --git a/tests/auto/client/surface/tst_surface.cpp b/tests/auto/client/surface/tst_surface.cpp
index e83450861..06e625155 100644
--- a/tests/auto/client/surface/tst_surface.cpp
+++ b/tests/auto/client/surface/tst_surface.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockcompositor.h"
#include <QtGui/QRasterWindow>
@@ -12,6 +12,8 @@ using namespace MockCompositor;
class tst_surface : public QObject, private DefaultCompositor
{
Q_OBJECT
+public:
+ explicit tst_surface();
private slots:
void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); }
void createDestroySurface();
@@ -26,6 +28,11 @@ private slots:
void createSubsurfaceForHiddenParent();
};
+tst_surface::tst_surface()
+{
+ m_config.autoFrameCallback = false;
+}
+
void tst_surface::createDestroySurface()
{
QWindow window;
@@ -51,11 +58,11 @@ void tst_surface::waitForFrameCallbackRaster()
TestWindow window;
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- QSignalSpy bufferSpy(exec([=] { return xdgSurface()->m_surface; }), &Surface::bufferCommitted);
- exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+ QSignalSpy bufferSpy(exec([&] { return xdgSurface()->m_surface; }), &Surface::bufferCommitted);
+ exec([&] { xdgToplevel()->sendCompleteConfigure(); });
// We should get the first buffer without waiting for a frame callback
- QTRY_COMPARE(bufferSpy.count(), 1);
+ QTRY_COMPARE(bufferSpy.size(), 1);
bufferSpy.removeFirst();
// Make sure we follow frame callbacks for some frames
@@ -66,7 +73,7 @@ void tst_surface::waitForFrameCallbackRaster()
QVERIFY(!xdgToplevel()->surface()->m_waitingFrameCallbacks.empty());
xdgToplevel()->surface()->sendFrameCallbacks();
});
- QTRY_COMPARE(bufferSpy.count(), 1);
+ QTRY_COMPARE(bufferSpy.size(), 1);
bufferSpy.removeFirst();
}
}
@@ -92,18 +99,18 @@ void tst_surface::waitForFrameCallbackGl()
TestWindow window;
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- QSignalSpy bufferSpy(exec([=] { return xdgSurface()->m_surface; }), &Surface::bufferCommitted);
- exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+ QSignalSpy bufferSpy(exec([&] { return xdgSurface()->m_surface; }), &Surface::bufferCommitted);
+ exec([&] { xdgToplevel()->sendCompleteConfigure(); });
// We should get the first buffer without waiting for a frame callback
- QTRY_COMPARE(bufferSpy.count(), 1);
+ QTRY_COMPARE(bufferSpy.size(), 1);
bufferSpy.removeFirst();
// Make sure we follow frame callbacks for some frames
for (int i = 0; i < 5; ++i) {
xdgPingAndWaitForPong(); // Make sure things have happened on the client
if (!qEnvironmentVariableIntValue("QT_WAYLAND_DISABLE_WINDOWDECORATION") && i == 0) {
- QCOMPARE(bufferSpy.count(), 1);
+ QCOMPARE(bufferSpy.size(), 1);
bufferSpy.removeFirst();
}
exec([&] {
@@ -111,7 +118,7 @@ void tst_surface::waitForFrameCallbackGl()
QVERIFY(!xdgToplevel()->surface()->m_waitingFrameCallbacks.empty());
xdgToplevel()->surface()->sendFrameCallbacks();
});
- QTRY_COMPARE(bufferSpy.count(), 1);
+ QTRY_COMPARE(bufferSpy.size(), 1);
bufferSpy.removeFirst();
}
}
@@ -128,8 +135,8 @@ void tst_surface::negotiateShmFormat()
window.resize(64, 48);
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- QSignalSpy bufferSpy(exec([=] { return xdgSurface()->m_surface; }), &Surface::bufferCommitted);
- const uint serial = exec([=] { return xdgToplevel()->sendCompleteConfigure(); });
+ QSignalSpy bufferSpy(exec([&] { return xdgSurface()->m_surface; }), &Surface::bufferCommitted);
+ const uint serial = exec([&] { return xdgToplevel()->sendCompleteConfigure(); });
QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, serial);
exec([&] {
Buffer *buffer = xdgToplevel()->surface()->m_committed.buffer;
@@ -157,26 +164,26 @@ void tst_surface::createSubsurface()
QCOMPOSITOR_TRY_VERIFY(subSurface());
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+ exec([&] { xdgToplevel()->sendCompleteConfigure(); });
QCOMPOSITOR_TRY_VERIFY(xdgSurface()->m_committedConfigureSerial);
- const Surface *mainSurface = exec([=] {return surface(0);});
- const Surface *childSurface = exec([=] {return surface(1);});
+ const Surface *mainSurface = exec([&] {return surface(0);});
+ const Surface *childSurface = exec([&] {return surface(1);});
QSignalSpy mainSurfaceCommitSpy(mainSurface, &Surface::commit);
QSignalSpy childSurfaceCommitSpy(childSurface, &Surface::commit);
// Move subsurface. The parent should redraw and commit
subWindow.setGeometry(100, 100, 64, 64);
// the toplevel should commit to indicate the subsurface moved
- QCOMPOSITOR_TRY_COMPARE(mainSurfaceCommitSpy.count(), 1);
+ QCOMPOSITOR_TRY_COMPARE(mainSurfaceCommitSpy.size(), 1);
mainSurfaceCommitSpy.clear();
childSurfaceCommitSpy.clear();
// Move and resize the subSurface. The parent should redraw and commit
// The child should also redraw
subWindow.setGeometry(50, 50, 80, 80);
- QCOMPOSITOR_TRY_COMPARE(mainSurfaceCommitSpy.count(), 1);
- QCOMPOSITOR_TRY_COMPARE(childSurfaceCommitSpy.count(), 1);
+ QCOMPOSITOR_TRY_COMPARE(mainSurfaceCommitSpy.size(), 1);
+ QCOMPOSITOR_TRY_COMPARE(childSurfaceCommitSpy.size(), 1);
}
@@ -187,7 +194,7 @@ void tst_surface::createSubsurfaceForHiddenParent()
window.resize(64, 64);
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+ exec([&] { xdgToplevel()->sendCompleteConfigure(); });
QCOMPOSITOR_TRY_VERIFY(xdgSurface()->m_committedConfigureSerial);
window.hide();
@@ -199,6 +206,10 @@ void tst_surface::createSubsurfaceForHiddenParent()
// Make sure the client doesn't quit before it has a chance to crash
xdgPingAndWaitForPong();
+
+ // Make sure the subsurface was actually created
+ const Subsurface *subsurface = exec([&] {return subSurface(0);});
+ QVERIFY(subsurface);
}
QCOMPOSITOR_TEST_MAIN(tst_surface)
diff --git a/tests/auto/client/tabletv2/CMakeLists.txt b/tests/auto/client/tabletv2/CMakeLists.txt
index 5334b7a1e..1400a511a 100644
--- a/tests/auto/client/tabletv2/CMakeLists.txt
+++ b/tests/auto/client/tabletv2/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from tabletv2.pro.
#####################################################################
@@ -7,6 +10,6 @@
qt_internal_add_test(tst_tabletv2
SOURCES
tst_tabletv2.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
SharedClientTest
)
diff --git a/tests/auto/client/tabletv2/tst_tabletv2.cpp b/tests/auto/client/tabletv2/tst_tabletv2.cpp
index b4d016289..85df099f9 100644
--- a/tests/auto/client/tabletv2/tst_tabletv2.cpp
+++ b/tests/auto/client/tabletv2/tst_tabletv2.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockcompositor.h"
diff --git a/tests/auto/client/wl_connect/CMakeLists.txt b/tests/auto/client/wl_connect/CMakeLists.txt
index 0c7140ac6..fff3835bb 100644
--- a/tests/auto/client/wl_connect/CMakeLists.txt
+++ b/tests/auto/client/wl_connect/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from wl_connect.pro.
#####################################################################
@@ -7,7 +10,7 @@
qt_internal_add_test(tst_wlconnect
SOURCES
tst_wlconnect.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::GuiPrivate
)
diff --git a/tests/auto/client/wl_connect/tst_wlconnect.cpp b/tests/auto/client/wl_connect/tst_wlconnect.cpp
index cd29eeb99..d66d0ad6a 100644
--- a/tests/auto/client/wl_connect/tst_wlconnect.cpp
+++ b/tests/auto/client/wl_connect/tst_wlconnect.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QGuiApplication>
diff --git a/tests/auto/client/xdgdecorationv1/CMakeLists.txt b/tests/auto/client/xdgdecorationv1/CMakeLists.txt
index 1fe7bc44d..0f727aaca 100644
--- a/tests/auto/client/xdgdecorationv1/CMakeLists.txt
+++ b/tests/auto/client/xdgdecorationv1/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from xdgdecorationv1.pro.
#####################################################################
@@ -7,6 +10,6 @@
qt_internal_add_test(tst_xdgdecorationv1
SOURCES
tst_xdgdecorationv1.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
SharedClientTest
)
diff --git a/tests/auto/client/xdgdecorationv1/tst_xdgdecorationv1.cpp b/tests/auto/client/xdgdecorationv1/tst_xdgdecorationv1.cpp
index 8adc9dd0e..54b15b3bf 100644
--- a/tests/auto/client/xdgdecorationv1/tst_xdgdecorationv1.cpp
+++ b/tests/auto/client/xdgdecorationv1/tst_xdgdecorationv1.cpp
@@ -1,11 +1,10 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockcompositor.h"
#include <qwayland-server-xdg-decoration-unstable-v1.h>
-#include <QtOpenGL/QOpenGLWindow>
#include <QtGui/QRasterWindow>
#include <QtGui/QClipboard>
#include <QtCore/private/qcore_unix_p.h>
@@ -152,7 +151,7 @@ void tst_xdgdecorationv1::clientSidePreferredByCompositor()
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
QCOMPOSITOR_TRY_VERIFY(toplevelDecoration()->m_unsetModeRequested);
QVERIFY(window.frameMargins().isNull()); // We're still waiting for a configure
- exec([=] {
+ exec([&] {
toplevelDecoration()->sendConfigure(XdgToplevelDecorationV1::mode_client_side);
xdgToplevel()->sendCompleteConfigure();
});
@@ -166,7 +165,7 @@ void tst_xdgdecorationv1::initialFramelessWindowHint()
window.show();
QCOMPOSITOR_TRY_COMPARE(get<XdgDecorationManagerV1>()->resourceMap().size(), 1);
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- exec([=]{
+ exec([&]{
xdgToplevel()->sendCompleteConfigure();
});
QCOMPOSITOR_TRY_VERIFY(xdgSurface()->m_committedConfigureSerial);
@@ -182,7 +181,7 @@ void tst_xdgdecorationv1::delayedFramelessWindowHint()
window.show();
QCOMPOSITOR_TRY_COMPARE(get<XdgDecorationManagerV1>()->resourceMap().size(), 1);
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- exec([=]{
+ exec([&]{
xdgToplevel()->sendCompleteConfigure();
});
QCOMPOSITOR_TRY_VERIFY(xdgSurface()->m_committedConfigureSerial);
diff --git a/tests/auto/client/xdgoutput/CMakeLists.txt b/tests/auto/client/xdgoutput/CMakeLists.txt
index baaf226b7..123a78f8e 100644
--- a/tests/auto/client/xdgoutput/CMakeLists.txt
+++ b/tests/auto/client/xdgoutput/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from xdgoutput.pro.
#####################################################################
@@ -7,6 +10,6 @@
qt_internal_add_test(tst_xdgoutput
SOURCES
tst_xdgoutput.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
SharedClientTest
)
diff --git a/tests/auto/client/xdgoutput/tst_xdgoutput.cpp b/tests/auto/client/xdgoutput/tst_xdgoutput.cpp
index b1dcde43e..d021e3883 100644
--- a/tests/auto/client/xdgoutput/tst_xdgoutput.cpp
+++ b/tests/auto/client/xdgoutput/tst_xdgoutput.cpp
@@ -1,10 +1,9 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "xdgoutputv1.h"
#include "mockcompositor.h"
-#include <QtOpenGL/QOpenGLWindow>
#include <QtGui/QRasterWindow>
#include <QtGui/QScreen>
@@ -30,6 +29,7 @@ private slots:
void primaryScreen();
void overrideGeometry();
void changeGeometry();
+ void outputCreateEnterRace();
};
void tst_xdgoutput::cleanup()
@@ -43,7 +43,7 @@ void tst_xdgoutput::primaryScreen()
{
// Verify that the client has bound to the global
QCOMPOSITOR_TRY_COMPARE(get<XdgOutputManagerV1>()->resourceMap().size(), 1);
- exec([=] {
+ exec([&] {
auto *resource = xdgOutput()->resourceMap().value(client());
QCOMPARE(resource->version(), 3);
QCOMPARE(xdgOutput()->m_logicalGeometry.size(), QSize(1920, 1080));
@@ -56,7 +56,7 @@ void tst_xdgoutput::primaryScreen()
void tst_xdgoutput::overrideGeometry()
{
- exec([=] {
+ exec([&] {
auto *output = add<Output>();
auto *xdgOutput = get<XdgOutputManagerV1>()->getXdgOutput(output);
xdgOutput->m_logicalGeometry = QRect(10, 20, 800, 1200);
@@ -68,12 +68,12 @@ void tst_xdgoutput::overrideGeometry()
QTRY_COMPARE(s->size(), QSize(800, 1200));
QTRY_COMPARE(s->geometry().topLeft(), QPoint(10, 20));
- exec([=] { remove(output(1)); });
+ exec([&] { remove(output(1)); });
}
void tst_xdgoutput::changeGeometry()
{
- auto *xdgOutput = exec([=] {
+ auto *xdgOutput = exec([&] {
auto *output = add<Output>();
auto *xdgOutput = get<XdgOutputManagerV1>()->getXdgOutput(output);
xdgOutput->m_logicalGeometry = QRect(10, 20, 800, 1200);
@@ -84,7 +84,7 @@ void tst_xdgoutput::changeGeometry()
auto *screen = QGuiApplication::screens()[1];
QTRY_COMPARE(screen->size(), QSize(800, 1200));
- exec([=] {
+ exec([&] {
xdgOutput->sendLogicalSize(QSize(1024, 768));
});
@@ -92,21 +92,55 @@ void tst_xdgoutput::changeGeometry()
// done event. If we TRY_COMPARE immediately, we risk that the client just hasn't handled the
// logical_size request yet, so we add a screen and verify it on the client side just to give
// the client a chance to mess up.
- exec([=] { add<Output>(); });
+ exec([&] { add<Output>(); });
QTRY_COMPARE(QGuiApplication::screens().size(), 3);
- exec([=] { remove(output(2)); });
+ exec([&] { remove(output(2)); });
// The logical_size event should have been handled by now, but state should not have been applied yet.
QTRY_COMPARE(screen->size(), QSize(800, 1200));
- exec([=] {
+ exec([&] {
xdgOutput->m_output->sendDone();
});
// Finally, the size should change
QTRY_COMPARE(screen->size(), QSize(1024, 768));
- exec([=] { remove(output(1)); });
+ exec([&] { remove(output(1)); });
+}
+
+void tst_xdgoutput::outputCreateEnterRace()
+{
+ m_config.autoConfigure = true;
+ m_config.autoEnter = false;
+ QRasterWindow window;
+ QSignalSpy screenChanged(&window, &QWindow::screenChanged);
+ window.resize(400, 320);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+ exec([&] { xdgToplevel()->surface()->sendEnter(output(0));});
+
+ QTRY_COMPARE(QGuiApplication::screens().size(), 1);
+ QScreen *primaryScreen = QGuiApplication::screens().first();
+ QCOMPARE(window.screen(), primaryScreen);
+
+ auto *out = exec([&] {
+ return add<Output>();
+ });
+
+ // In Compositor Thread
+ connect(out, &Output::outputBound, this, [this](QtWaylandServer::wl_output::Resource *resource){
+ auto surface = xdgToplevel()->surface();
+ surface->sendLeave(output(0));
+ surface->QtWaylandServer::wl_surface::send_enter(surface->resource()->handle, resource->handle);
+ }, Qt::DirectConnection);
+
+ QTRY_COMPARE(QGuiApplication::screens().size(), 2);
+ QTRY_COMPARE(window.screen(), QGuiApplication::screens()[1]);
+
+ exec([&] { remove(out); });
+ m_config.autoConfigure = false;
+ m_config.autoEnter = true;
}
QCOMPOSITOR_TEST_MAIN(tst_xdgoutput)
diff --git a/tests/auto/client/xdgshell/CMakeLists.txt b/tests/auto/client/xdgshell/CMakeLists.txt
index ea34539d3..fa7590249 100644
--- a/tests/auto/client/xdgshell/CMakeLists.txt
+++ b/tests/auto/client/xdgshell/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from xdgshell.pro.
#####################################################################
@@ -7,6 +10,6 @@
qt_internal_add_test(tst_xdgshell
SOURCES
tst_xdgshell.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
SharedClientTest
)
diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp
index 80ac3a23f..1dc57e280 100644
--- a/tests/auto/client/xdgshell/tst_xdgshell.cpp
+++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp
@@ -1,8 +1,8 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// Copyright (C) 2023 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockcompositor.h"
-#include <QtOpenGL/QOpenGLWindow>
#include <QtGui/QRasterWindow>
#include <QtGui/qpa/qplatformnativeinterface.h>
#include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
@@ -14,22 +14,34 @@ class tst_xdgshell : public QObject, private DefaultCompositor
{
Q_OBJECT
private slots:
+ void init();
void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); }
void showMinimized();
void basicConfigure();
void configureSize();
void configureStates();
+ void configureBounds();
void popup();
void tooltipOnPopup();
+ void tooltipAndSiblingPopup();
void switchPopups();
void hidePopupParent();
void pongs();
+ void minMaxSize_data();
void minMaxSize();
void windowGeometry();
void foreignSurface();
void nativeResources();
+ void suspended();
+ void initiallySuspended();
+ void modality();
};
+void tst_xdgshell::init()
+{
+ setenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1", 1);
+}
+
void tst_xdgshell::showMinimized()
{
// On xdg-shell there's really no way for the compositor to tell the window if it's minimized
@@ -53,13 +65,13 @@ void tst_xdgshell::basicConfigure()
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- QSignalSpy configureSpy(exec([=] { return xdgSurface(); }), &XdgSurface::configureCommitted);
+ QSignalSpy configureSpy(exec([&] { return xdgSurface(); }), &XdgSurface::configureCommitted);
QTRY_VERIFY(window.isVisible());
// The window should not be exposed before the first xdg_surface configure event
QTRY_VERIFY(!window.isExposed());
- exec([=] {
+ exec([&] {
xdgToplevel()->sendConfigure({0, 0}, {}); // Let the window decide the size
});
@@ -67,9 +79,9 @@ void tst_xdgshell::basicConfigure()
QTRY_VERIFY(!window.isExposed()); //Window should not be exposed before the first configure event
QVERIFY(configureSpy.isEmpty());
- const uint serial = exec([=] { return nextSerial(); });
+ const uint serial = exec([&] { return nextSerial(); });
- exec([=] {
+ exec([&] {
xdgSurface()->sendConfigure(serial);
});
@@ -77,7 +89,7 @@ void tst_xdgshell::basicConfigure()
QTRY_VERIFY(window.isExposed());
// The client is now going to ack the configure
- QTRY_COMPARE(configureSpy.count(), 1);
+ QTRY_COMPARE(configureSpy.size(), 1);
QCOMPARE(configureSpy.takeFirst().at(0).toUInt(), serial);
// And attach a buffer
@@ -95,17 +107,17 @@ void tst_xdgshell::configureSize()
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- QSignalSpy configureSpy(exec([=] { return xdgSurface(); }), &XdgSurface::configureCommitted);
+ QSignalSpy configureSpy(exec([&] { return xdgSurface(); }), &XdgSurface::configureCommitted);
const QSize configureSize(60, 40);
- exec([=] {
+ exec([&] {
xdgToplevel()->sendCompleteConfigure(configureSize);
});
- QTRY_COMPARE(configureSpy.count(), 1);
+ QTRY_COMPARE(configureSpy.size(), 1);
- exec([=] {
+ exec([&] {
Buffer *buffer = xdgToplevel()->surface()->m_committed.buffer;
QVERIFY(buffer);
QCOMPARE(buffer->size(), configureSize);
@@ -121,7 +133,7 @@ void tst_xdgshell::configureStates()
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
const QSize windowedSize(320, 240);
- const uint windowedSerial = exec([=] {
+ const uint windowedSerial = exec([&] {
return xdgToplevel()->sendCompleteConfigure(windowedSize, { XdgToplevel::state_activated });
});
QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, windowedSerial);
@@ -139,7 +151,7 @@ void tst_xdgshell::configureStates()
Qt::WindowActive)); // Just make sure it eventually get's set correctly
const QSize screenSize(640, 480);
- const uint maximizedSerial = exec([=] {
+ const uint maximizedSerial = exec([&] {
return xdgToplevel()->sendCompleteConfigure(screenSize, { XdgToplevel::state_activated, XdgToplevel::state_maximized });
});
QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, maximizedSerial);
@@ -148,7 +160,7 @@ void tst_xdgshell::configureStates()
QCOMPARE(window.frameGeometry().size(), screenSize);
// QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
- const uint fullscreenSerial = exec([=] {
+ const uint fullscreenSerial = exec([&] {
return xdgToplevel()->sendCompleteConfigure(screenSize, { XdgToplevel::state_activated, XdgToplevel::state_fullscreen });
});
QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, fullscreenSerial);
@@ -158,7 +170,7 @@ void tst_xdgshell::configureStates()
// QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
// The window should remember its original size
- const uint restoreSerial = exec([=] {
+ const uint restoreSerial = exec([&] {
return xdgToplevel()->sendCompleteConfigure({0, 0}, { XdgToplevel::state_activated });
});
QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, restoreSerial);
@@ -169,6 +181,30 @@ void tst_xdgshell::configureStates()
QVERIFY(qunsetenv("QT_WAYLAND_FRAME_CALLBACK_TIMEOUT"));
}
+void tst_xdgshell::configureBounds()
+{
+ QRasterWindow window;
+ window.resize(1280, 1024);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+
+ // Take xdg_toplevel.configure_bounds into account only if the configure event has 0x0 size.
+ const uint serial1 = exec([&] {
+ xdgToplevel()->sendConfigureBounds(QSize(800, 600));
+ return xdgToplevel()->sendCompleteConfigure(QSize(0, 0), { XdgToplevel::state_activated });
+ });
+ QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, serial1);
+ QCOMPARE(window.frameGeometry().size(), QSize(800, 600));
+
+ // Window size in xdg_toplevel configure events takes precedence over the configure bounds.
+ const uint serial2 = exec([&] {
+ xdgToplevel()->sendConfigureBounds(QSize(800, 600));
+ return xdgToplevel()->sendCompleteConfigure(QSize(1600, 900), { XdgToplevel::state_activated });
+ });
+ QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, serial2);
+ QCOMPARE(window.frameGeometry().size(), QSize(1600, 900));
+}
+
void tst_xdgshell::popup()
{
class Window : public QRasterWindow {
@@ -189,11 +225,11 @@ void tst_xdgshell::popup()
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- QSignalSpy toplevelConfigureSpy(exec([=] { return xdgSurface(); }), &XdgSurface::configureCommitted);
- exec([=] { xdgToplevel()->sendCompleteConfigure(); });
- QTRY_COMPARE(toplevelConfigureSpy.count(), 1);
+ QSignalSpy toplevelConfigureSpy(exec([&] { return xdgSurface(); }), &XdgSurface::configureCommitted);
+ exec([&] { xdgToplevel()->sendCompleteConfigure(); });
+ QTRY_COMPARE(toplevelConfigureSpy.size(), 1);
- uint clickSerial = exec([=] {
+ uint clickSerial = exec([&] {
auto *surface = xdgToplevel()->surface();
auto *p = pointer();
auto *c = client();
@@ -207,21 +243,21 @@ void tst_xdgshell::popup()
QTRY_VERIFY(window.m_popup);
QCOMPOSITOR_TRY_VERIFY(xdgPopup());
- QSignalSpy popupConfigureSpy(exec([=] { return xdgPopup()->m_xdgSurface; }), &XdgSurface::configureCommitted);
+ QSignalSpy popupConfigureSpy(exec([&] { return xdgPopup()->m_xdgSurface; }), &XdgSurface::configureCommitted);
QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_grabbed);
QCOMPOSITOR_TRY_COMPARE(xdgPopup()->m_grabSerial, clickSerial);
QRasterWindow *popup = window.m_popup.get();
QVERIFY(!popup->isExposed()); // wait for configure
- //TODO: Verify it works with a different configure window geometry
- exec([=] { xdgPopup()->sendConfigure(QRect(100, 100, 100, 100)); });
+ QRect rect1 = QRect(100, 100, 100, 100);
+ exec([&] { xdgPopup()->sendConfigure(rect1); });
// Nothing should happen before the *xdg_surface* configure
QTRY_VERIFY(!popup->isExposed()); // Popup shouldn't be exposed before the first configure event
QVERIFY(popupConfigureSpy.isEmpty());
- const uint configureSerial = exec([=] {
+ const uint configureSerial = exec([&] {
return xdgPopup()->m_xdgSurface->sendConfigure();
});
@@ -229,8 +265,20 @@ void tst_xdgshell::popup()
QTRY_VERIFY(popup->isExposed());
// The client is now going to ack the configure
- QTRY_COMPARE(popupConfigureSpy.count(), 1);
+ QTRY_COMPARE(popupConfigureSpy.size(), 1);
QCOMPARE(popupConfigureSpy.takeFirst().at(0).toUInt(), configureSerial);
+ QCOMPARE(popup->geometry(), rect1);
+
+ QRect rect2 = QRect(50, 50, 150, 150);
+ exec([&] { xdgPopup()->sendConfigure(rect2); });
+
+ const uint configureSerial2 = exec([&] {
+ return xdgPopup()->m_xdgSurface->sendConfigure();
+ });
+
+ QTRY_COMPARE(popupConfigureSpy.size(), 1);
+ QCOMPARE(popupConfigureSpy.takeFirst().at(0).toUInt(), configureSerial2);
+ QCOMPARE(popup->geometry(), rect2);
// And attach a buffer
exec([&] {
@@ -275,10 +323,10 @@ void tst_xdgshell::tooltipOnPopup()
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+ exec([&] { xdgToplevel()->sendCompleteConfigure(); });
QCOMPOSITOR_TRY_VERIFY(xdgToplevel()->m_xdgSurface->m_committedConfigureSerial);
- exec([=] {
+ exec([&] {
auto *surface = xdgToplevel()->surface();
auto *p = pointer();
auto *c = client();
@@ -292,11 +340,11 @@ void tst_xdgshell::tooltipOnPopup()
});
QCOMPOSITOR_TRY_VERIFY(xdgPopup());
- exec([=] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
+ exec([&] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_xdgSurface->m_committedConfigureSerial);
QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_grabbed);
- exec([=] {
+ exec([&] {
auto *surface = xdgPopup()->surface();
auto *p = pointer();
auto *c = client();
@@ -308,7 +356,7 @@ void tst_xdgshell::tooltipOnPopup()
});
QCOMPOSITOR_TRY_VERIFY(xdgPopup(1));
- exec([=] { xdgPopup(1)->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
+ exec([&] { xdgPopup(1)->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
QCOMPOSITOR_TRY_VERIFY(xdgPopup(1)->m_xdgSurface->m_committedConfigureSerial);
QCOMPOSITOR_TRY_VERIFY(!xdgPopup(1)->m_grabbed);
@@ -321,6 +369,92 @@ void tst_xdgshell::tooltipOnPopup()
QCOMPOSITOR_TRY_COMPARE(xdgPopup(0), nullptr);
}
+void tst_xdgshell::tooltipAndSiblingPopup()
+{
+ class ToolTip : public QRasterWindow {
+ public:
+ explicit ToolTip(QWindow *parent) {
+ setTransientParent(parent);
+ setFlags(Qt::ToolTip);
+ resize(100, 100);
+ show();
+ }
+ void mousePressEvent(QMouseEvent *event) override {
+ QRasterWindow::mousePressEvent(event);
+ m_popup = new QRasterWindow;
+ m_popup->setTransientParent(transientParent());
+ m_popup->setFlags(Qt::Popup);
+ m_popup->resize(100, 100);
+ m_popup->show();
+ }
+
+ QRasterWindow *m_popup = nullptr;
+ };
+
+ class Window : public QRasterWindow {
+ public:
+ void mousePressEvent(QMouseEvent *event) override {
+ QRasterWindow::mousePressEvent(event);
+ m_tooltip = new ToolTip(this);
+ }
+ ToolTip *m_tooltip = nullptr;
+ };
+
+ Window window;
+ window.resize(200, 200);
+ window.show();
+
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+ exec([&] { xdgToplevel()->sendCompleteConfigure(); });
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel()->m_xdgSurface->m_committedConfigureSerial);
+
+ exec([&] {
+ auto *surface = xdgToplevel()->surface();
+ auto *p = pointer();
+ auto *c = client();
+ p->sendEnter(surface, {100, 100});
+ p->sendFrame(c);
+ p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
+ p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
+ p->sendFrame(c);
+ p->sendLeave(surface);
+ p->sendFrame(c);
+ });
+
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup());
+ exec([&] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_xdgSurface->m_committedConfigureSerial);
+ QCOMPOSITOR_TRY_VERIFY(!xdgPopup()->m_grabbed);
+
+ exec([&] {
+ auto *surface = xdgPopup()->surface();
+ auto *p = pointer();
+ auto *c = client();
+ p->sendEnter(surface, {100, 100});
+ p->sendFrame(c);
+ p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
+ p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
+ p->sendFrame(c);
+ });
+
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup(1));
+ exec([&] { xdgPopup(1)->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup(1)->m_xdgSurface->m_committedConfigureSerial);
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup(1)->m_grabbed);
+
+ // Close the middle tooltip (it should not close the sibling popup)
+ window.m_tooltip->close();
+
+ QCOMPOSITOR_TRY_COMPARE(xdgPopup(1), nullptr);
+ // Verify the remaining xdg surface is a grab popup..
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup(0));
+ QCOMPOSITOR_TRY_VERIFY(xdgPopup(0)->m_grabbed);
+
+ window.m_tooltip->m_popup->close();
+ QCOMPOSITOR_TRY_COMPARE(xdgPopup(1), nullptr);
+ QCOMPOSITOR_TRY_COMPARE(xdgPopup(0), nullptr);
+}
+
// QTBUG-65680
void tst_xdgshell::switchPopups()
{
@@ -359,10 +493,10 @@ void tst_xdgshell::switchPopups()
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+ exec([&] { xdgToplevel()->sendCompleteConfigure(); });
QCOMPOSITOR_TRY_VERIFY(xdgToplevel()->m_xdgSurface->m_committedConfigureSerial);
- exec([=] {
+ exec([&] {
auto *surface = xdgToplevel()->surface();
auto *p = pointer();
auto *c = client();
@@ -376,13 +510,13 @@ void tst_xdgshell::switchPopups()
});
QCOMPOSITOR_TRY_VERIFY(xdgPopup());
- exec([=] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
+ exec([&] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_xdgSurface->m_committedConfigureSerial);
QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_grabbed);
- QSignalSpy firstDestroyed(exec([=] { return xdgPopup(); }), &XdgPopup::destroyRequested);
+ QSignalSpy firstDestroyed(exec([&] { return xdgPopup(); }), &XdgPopup::destroyRequested);
- exec([=] {
+ exec([&] {
auto *surface = xdgToplevel()->surface();
auto *p = pointer();
auto *c = client();
@@ -407,7 +541,7 @@ void tst_xdgshell::switchPopups()
QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_parentXdgSurface == xdgToplevel()->m_xdgSurface);
// For good measure just check that configuring works as usual
- exec([=] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
+ exec([&] { xdgPopup()->sendCompleteConfigure(QRect(100, 100, 100, 100)); });
QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_xdgSurface->m_committedConfigureSerial);
}
@@ -431,10 +565,10 @@ void tst_xdgshell::hidePopupParent()
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+ exec([&] { xdgToplevel()->sendCompleteConfigure(); });
QCOMPOSITOR_TRY_VERIFY(xdgToplevel()->m_xdgSurface->m_committedConfigureSerial);
- exec([=] {
+ exec([&] {
auto *surface = xdgToplevel()->surface();
auto *p = pointer();
auto *c = client();
@@ -445,7 +579,7 @@ void tst_xdgshell::hidePopupParent()
p->sendFrame(c);
});
QCOMPOSITOR_TRY_VERIFY(xdgPopup());
- exec([=] {
+ exec([&] {
xdgPopup()->sendConfigure(QRect(100, 100, 100, 100));
xdgPopup()->m_xdgSurface->sendConfigure();
});
@@ -466,36 +600,80 @@ void tst_xdgshell::pongs()
// Verify that the client has bound to the global
QCOMPOSITOR_TRY_COMPARE(get<XdgWmBase>()->resourceMap().size(), 1);
- QSignalSpy pongSpy(exec([=] { return get<XdgWmBase>(); }), &XdgWmBase::pong);
- const uint serial = exec([=] { return nextSerial(); });
- exec([=] {
+ QSignalSpy pongSpy(exec([&] { return get<XdgWmBase>(); }), &XdgWmBase::pong);
+ const uint serial = exec([&] { return nextSerial(); });
+ exec([&] {
auto *base = get<XdgWmBase>();
wl_resource *resource = base->resourceMap().first()->handle;
base->send_ping(resource, serial);
});
- QTRY_COMPARE(pongSpy.count(), 1);
+ QTRY_COMPARE(pongSpy.size(), 1);
QCOMPARE(pongSpy.first().at(0).toUInt(), serial);
}
+void tst_xdgshell::minMaxSize_data()
+{
+ QTest::addColumn<QSize>("initialMinSize");
+ QTest::addColumn<QSize>("initialMaxSize");
+ QTest::addColumn<QSize>("nextMinSize");
+ QTest::addColumn<QSize>("nextMaxSize");
+ QTest::addColumn<QSize>("expectedInitialMinSize");
+ QTest::addColumn<QSize>("expectedInitialMaxSize");
+ QTest::addColumn<QSize>("expectedNextMinSize");
+ QTest::addColumn<QSize>("expectedNextMaxSize");
+
+ QTest::newRow("onlyMinSize") << QSize(50, 60) << QSize() << QSize(500, 600) << QSize()
+ << QSize(50, 60) << QSize(0, 0) << QSize(500, 600) << QSize(0, 0);
+
+ QTest::newRow("onlyMaxSize") << QSize() << QSize(70, 80) << QSize() << QSize(700, 800)
+ << QSize(0,0 ) << QSize(70, 80) << QSize(0, 0) << QSize(700, 800);
+
+ QTest::newRow("maxIsSentAsZero") << QSize() << QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX) << QSize() << QSize()
+ << QSize(0,0 ) << QSize(0, 0) << QSize(0, 0) << QSize(0, 0);
+
+
+ QTest::newRow("fullHints") << QSize(50, 60) << QSize(700, 800) << QSize(500, 600) << QSize(710, 810)
+ << QSize(50, 60) << QSize(700, 800) << QSize(500, 600) << QSize(710, 810);
+
+ // setting a minimum above the maximum is not allowed, we should no-op
+ QTest::newRow("invalidResize") << QSize(50, 60) << QSize(100, 100) << QSize(500, 600) << QSize(100, 100)
+ << QSize(50, 60) << QSize(100, 100) << QSize(50, 60) << QSize(100, 100);}
+
void tst_xdgshell::minMaxSize()
{
+ QFETCH(QSize, initialMinSize);
+ QFETCH(QSize, initialMaxSize);
+
+ QFETCH(QSize, expectedInitialMinSize);
+ QFETCH(QSize, expectedInitialMaxSize);
+
QRasterWindow window;
- window.setMinimumSize(QSize(100, 100));
- window.setMaximumSize(QSize(1000, 1000));
- window.resize(400, 320);
+ if (initialMinSize.isValid())
+ window.setMinimumSize(initialMinSize);
+ if (initialMaxSize.isValid())
+ window.setMaximumSize(initialMaxSize);
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+ exec([&] { xdgToplevel()->sendCompleteConfigure(); });
+
// we don't roundtrip with our configuration the initial commit should be correct
- QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.minSize, QSize(100, 100));
- QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.maxSize, QSize(1000, 1000));
+ QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.minSize, expectedInitialMinSize);
+ QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.maxSize, expectedInitialMaxSize);
+
+ QFETCH(QSize, nextMinSize);
+ QFETCH(QSize, expectedNextMinSize);
+ window.setMinimumSize(nextMinSize);
+ window.update();
+ QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.minSize, expectedNextMinSize);
- window.setMaximumSize(QSize(500, 400));
- QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.maxSize, QSize(500, 400));
+ QFETCH(QSize, nextMaxSize);
+ QFETCH(QSize, expectedNextMaxSize);
- window.setMinimumSize(QSize(50, 40));
- QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.minSize, QSize(50, 40));
+ window.setMaximumSize(nextMaxSize);
+ window.update();
+ QCOMPOSITOR_TRY_COMPARE(xdgToplevel()->m_committed.maxSize, expectedNextMaxSize);
}
void tst_xdgshell::windowGeometry()
@@ -505,7 +683,7 @@ void tst_xdgshell::windowGeometry()
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
- exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+ exec([&] { xdgToplevel()->sendCompleteConfigure(); });
QSize marginsSize;
marginsSize.setWidth(window.frameMargins().left() + window.frameMargins().right());
@@ -537,9 +715,9 @@ void tst_xdgshell::foreignSurface()
// Just do something to make sure we don't destroy the surface before
// the pointer events above are handled.
- QSignalSpy spy(exec([=] { return surface(newSurfaceIndex); }), &Surface::commit);
+ QSignalSpy spy(exec([&] { return surface(newSurfaceIndex); }), &Surface::commit);
wl_surface_commit(foreignSurface);
- QTRY_COMPARE(spy.count(), 1);
+ QTRY_COMPARE(spy.size(), 1);
wl_surface_destroy(foreignSurface);
}
@@ -562,5 +740,70 @@ void tst_xdgshell::nativeResources()
QCOMPARE(xdg_popup_proxy, nullptr);
}
+void tst_xdgshell::suspended()
+{
+ QRasterWindow window;
+ window.resize(400, 320);
+ window.show();
+ QVERIFY(!window.isExposed()); // not exposed until we're configured
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+
+ exec([=] { xdgToplevel()->sendCompleteConfigure(); });
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel()->m_xdgSurface->m_committedConfigureSerial);
+ QTRY_VERIFY(window.isExposed());
+
+ exec([=] { xdgToplevel()->sendCompleteConfigure(QSize(), {XdgToplevel::state_suspended}); });
+ QTRY_VERIFY(!window.isExposed());
+
+ exec([=] { xdgToplevel()->sendCompleteConfigure(QSize(), {}); });
+ QTRY_VERIFY(window.isExposed());
+}
+
+void tst_xdgshell::initiallySuspended()
+{
+ QRasterWindow window;
+ window.resize(400, 320);
+ window.show();
+ QVERIFY(!window.isExposed());
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
+ exec([=] { xdgToplevel()->sendCompleteConfigure(QSize(), {XdgToplevel::state_suspended}); });
+ QVERIFY(!window.isExposed());
+}
+
+void tst_xdgshell::modality()
+{
+ QRasterWindow parent;
+ parent.resize(400, 320);
+ parent.show();
+
+ QRasterWindow child;
+ child.resize(400, 320);
+ child.setTransientParent(&parent);
+ child.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgToplevel(1));
+ QCOMPOSITOR_VERIFY(!xdgDialog());
+
+ child.hide();
+ child.setModality(Qt::WindowModal);
+ child.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgDialog());
+ QCOMPOSITOR_VERIFY(xdgDialog()->modal);
+
+ child.hide();
+ QCOMPOSITOR_TRY_VERIFY(!xdgDialog());
+
+ child.setModality(Qt::ApplicationModal);
+ child.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgDialog());
+ QCOMPOSITOR_VERIFY(xdgDialog()->modal);
+
+ child.hide();
+ QCOMPOSITOR_TRY_VERIFY(!xdgDialog());
+
+ child.show();
+ child.setModality(Qt::NonModal);
+ QCOMPOSITOR_TRY_VERIFY(!xdgDialog());
+}
+
QCOMPOSITOR_TEST_MAIN(tst_xdgshell)
#include "tst_xdgshell.moc"
diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt
index 53fc6b2a3..ec8a54567 100644
--- a/tests/auto/cmake/CMakeLists.txt
+++ b/tests/auto/cmake/CMakeLists.txt
@@ -1,18 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
-
-project(qmake_cmake_files)
+project(qtwayland_cmake_tests)
enable_testing()
-find_package(Qt5Core REQUIRED)
-set(Qt5_MODULE_TEST_DEPENDS Quick)
+find_package(Qt6Core REQUIRED)
+set(Qt6_MODULE_TEST_DEPENDS Quick)
-include("${_Qt5CTestMacros}")
+include("${_Qt6CTestMacros}")
-test_module_includes(
+_qt_internal_test_module_includes(
WaylandCompositor QWaylandBufferRef
)
-# Can't test in `test_module_includes`, WaylandClient has no public headers
-expect_pass(test_waylandclient)
+# Can't test in `_qt_internal_test_module_includes`, WaylandClient has no public headers
+_qt_internal_test_expect_pass(test_waylandclient)
diff --git a/tests/auto/cmake/test_waylandclient/CMakeLists.txt b/tests/auto/cmake/test_waylandclient/CMakeLists.txt
index d3dacc0f5..cad8d45d3 100644
--- a/tests/auto/cmake/test_waylandclient/CMakeLists.txt
+++ b/tests/auto/cmake/test_waylandclient/CMakeLists.txt
@@ -1,12 +1,11 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
project(test_plugins)
cmake_minimum_required(VERSION 3.16)
cmake_policy(SET CMP0056 NEW)
-find_package(Qt5WaylandClient REQUIRED)
-
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}")
-
-include_directories(${Qt5WaylandClient_PRIVATE_INCLUDE_DIRS})
+find_package(Qt6WaylandClient REQUIRED)
add_executable(test_waylandclient_exe main.cpp)
-target_link_libraries(test_waylandclient_exe Qt5::WaylandClient)
+target_link_libraries(test_waylandclient_exe Qt6::WaylandClientPrivate)
diff --git a/tests/auto/compositor/CMakeLists.txt b/tests/auto/compositor/CMakeLists.txt
index a55266517..3a6dfedb3 100644
--- a/tests/auto/compositor/CMakeLists.txt
+++ b/tests/auto/compositor/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from compositor.pro.
add_subdirectory(compositor)
diff --git a/tests/auto/compositor/compositor/CMakeLists.txt b/tests/auto/compositor/compositor/CMakeLists.txt
index 4dce9b0f9..5cb18b2aa 100644
--- a/tests/auto/compositor/compositor/CMakeLists.txt
+++ b/tests/auto/compositor/compositor/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from compositor.pro.
#####################################################################
@@ -15,7 +18,7 @@ qt_internal_add_test(tst_compositor
testkeyboardgrabber.cpp testkeyboardgrabber.h
testseat.cpp testseat.h
tst_compositor.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
@@ -39,6 +42,6 @@ qt6_generate_wayland_protocol_client_sources(tst_compositor
#####################################################################
qt_internal_extend_target(tst_compositor CONDITION QT_FEATURE_xkbcommon
- PUBLIC_LIBRARIES
+ LIBRARIES
XKB::XKB
)
diff --git a/tests/auto/compositor/compositor/mockclient.cpp b/tests/auto/compositor/compositor/mockclient.cpp
index af40ee58b..6465f9931 100644
--- a/tests/auto/compositor/compositor/mockclient.cpp
+++ b/tests/auto/compositor/compositor/mockclient.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockclient.h"
#include "mockseat.h"
@@ -51,7 +51,9 @@ const wl_output_listener MockClient::outputListener = {
MockClient::outputGeometryEvent,
MockClient::outputModeEvent,
MockClient::outputDone,
- MockClient::outputScale
+ MockClient::outputScale,
+ MockClient::outputName,
+ MockClient::outputDesc
};
MockClient::~MockClient()
@@ -98,6 +100,16 @@ void MockClient::outputScale(void *, wl_output *, int)
}
+void MockClient::outputName(void *, wl_output *, const char *)
+{
+
+}
+
+void MockClient::outputDesc(void *, wl_output *, const char *)
+{
+
+}
+
void MockClient::readEvents()
{
if (error)
diff --git a/tests/auto/compositor/compositor/mockclient.h b/tests/auto/compositor/compositor/mockclient.h
index 53d2b700a..2f6d9046e 100644
--- a/tests/auto/compositor/compositor/mockclient.h
+++ b/tests/auto/compositor/compositor/mockclient.h
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "wayland-wayland-client-protocol.h"
#include <qwayland-xdg-shell.h>
@@ -103,6 +103,8 @@ private:
int refreshRate);
static void outputDone(void *data, wl_output *output);
static void outputScale(void *data, wl_output *output, int factor);
+ static void outputName(void *data, wl_output *output, const char *name);
+ static void outputDesc(void *data, wl_output *output, const char *desc);
void handleGlobal(uint32_t id, const QByteArray &interface);
void handleGlobalRemove(uint32_t id);
diff --git a/tests/auto/compositor/compositor/mockkeyboard.cpp b/tests/auto/compositor/compositor/mockkeyboard.cpp
index f8481799f..b3055ffa9 100644
--- a/tests/auto/compositor/compositor/mockkeyboard.cpp
+++ b/tests/auto/compositor/compositor/mockkeyboard.cpp
@@ -1,8 +1,11 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockkeyboard.h"
+QT_WARNING_DISABLE_GCC("-Wmissing-field-initializers")
+QT_WARNING_DISABLE_CLANG("-Wmissing-field-initializers")
+
void keyboardKeymap(void *keyboard, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size)
{
Q_UNUSED(keyboard);
diff --git a/tests/auto/compositor/compositor/mockkeyboard.h b/tests/auto/compositor/compositor/mockkeyboard.h
index 0b7935604..093586bb3 100644
--- a/tests/auto/compositor/compositor/mockkeyboard.h
+++ b/tests/auto/compositor/compositor/mockkeyboard.h
@@ -1,5 +1,5 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef MOCKKEYBOARD_H
#define MOCKKEYBOARD_H
diff --git a/tests/auto/compositor/compositor/mockpointer.cpp b/tests/auto/compositor/compositor/mockpointer.cpp
index 1929564ba..65a8b9ce7 100644
--- a/tests/auto/compositor/compositor/mockpointer.cpp
+++ b/tests/auto/compositor/compositor/mockpointer.cpp
@@ -1,8 +1,11 @@
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockpointer.h"
+QT_WARNING_DISABLE_GCC("-Wmissing-field-initializers")
+QT_WARNING_DISABLE_CLANG("-Wmissing-field-initializers")
+
static void pointerEnter(void *pointer, struct wl_pointer *wlPointer, uint serial, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y)
{
Q_UNUSED(wlPointer);
diff --git a/tests/auto/compositor/compositor/mockpointer.h b/tests/auto/compositor/compositor/mockpointer.h
index a35434613..db5c6a0af 100644
--- a/tests/auto/compositor/compositor/mockpointer.h
+++ b/tests/auto/compositor/compositor/mockpointer.h
@@ -1,5 +1,5 @@
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef MOCKPOINTER_H
#define MOCKPOINTER_H
diff --git a/tests/auto/compositor/compositor/mockseat.cpp b/tests/auto/compositor/compositor/mockseat.cpp
index 4a4b08444..88b1c94e4 100644
--- a/tests/auto/compositor/compositor/mockseat.cpp
+++ b/tests/auto/compositor/compositor/mockseat.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 LG Electronics Ltd., author: <mikko.levonmaa@lge.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockseat.h"
diff --git a/tests/auto/compositor/compositor/mockseat.h b/tests/auto/compositor/compositor/mockseat.h
index 744ae0850..12a14c727 100644
--- a/tests/auto/compositor/compositor/mockseat.h
+++ b/tests/auto/compositor/compositor/mockseat.h
@@ -1,5 +1,5 @@
// Copyright (C) 2016 LG Electronics Ltd., author: <mikko.levonmaa@lge.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef MOCKSEAT
#define MOCKSEAT
diff --git a/tests/auto/compositor/compositor/mockxdgoutputv1.cpp b/tests/auto/compositor/compositor/mockxdgoutputv1.cpp
index ae31279da..9349e62d6 100644
--- a/tests/auto/compositor/compositor/mockxdgoutputv1.cpp
+++ b/tests/auto/compositor/compositor/mockxdgoutputv1.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockxdgoutputv1.h"
diff --git a/tests/auto/compositor/compositor/mockxdgoutputv1.h b/tests/auto/compositor/compositor/mockxdgoutputv1.h
index 43baf67eb..4e3a05c91 100644
--- a/tests/auto/compositor/compositor/mockxdgoutputv1.h
+++ b/tests/auto/compositor/compositor/mockxdgoutputv1.h
@@ -1,5 +1,5 @@
// Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef MOCKXDGOUTPUTV1_H
#define MOCKXDGOUTPUTV1_H
diff --git a/tests/auto/compositor/compositor/testcompositor.cpp b/tests/auto/compositor/compositor/testcompositor.cpp
index bd4cce504..d2f454a93 100644
--- a/tests/auto/compositor/compositor/testcompositor.cpp
+++ b/tests/auto/compositor/compositor/testcompositor.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "testcompositor.h"
#include "testseat.h"
diff --git a/tests/auto/compositor/compositor/testcompositor.h b/tests/auto/compositor/compositor/testcompositor.h
index 3c1154001..0e11def13 100644
--- a/tests/auto/compositor/compositor/testcompositor.h
+++ b/tests/auto/compositor/compositor/testcompositor.h
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwaylandcompositor.h"
#include "qwaylandsurface.h"
diff --git a/tests/auto/compositor/compositor/testkeyboardgrabber.cpp b/tests/auto/compositor/compositor/testkeyboardgrabber.cpp
index cc27dae90..73592dd4f 100644
--- a/tests/auto/compositor/compositor/testkeyboardgrabber.cpp
+++ b/tests/auto/compositor/compositor/testkeyboardgrabber.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 LG Electronics, Inc., author: <mikko.levonmaa@lge.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "testkeyboardgrabber.h"
diff --git a/tests/auto/compositor/compositor/testkeyboardgrabber.h b/tests/auto/compositor/compositor/testkeyboardgrabber.h
index 749bf0ed9..2e2f44df4 100644
--- a/tests/auto/compositor/compositor/testkeyboardgrabber.h
+++ b/tests/auto/compositor/compositor/testkeyboardgrabber.h
@@ -1,5 +1,5 @@
// Copyright (C) 2016 LG Electronics, Inc., author: <mikko.levonmaa@lge.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwaylandkeyboard.h"
diff --git a/tests/auto/compositor/compositor/testseat.cpp b/tests/auto/compositor/compositor/testseat.cpp
index fb408bebc..21e2bffe5 100644
--- a/tests/auto/compositor/compositor/testseat.cpp
+++ b/tests/auto/compositor/compositor/testseat.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 LG Electronics, Inc., author: <mikko.levonmaa@lge.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "testseat.h"
#include <QMouseEvent>
diff --git a/tests/auto/compositor/compositor/testseat.h b/tests/auto/compositor/compositor/testseat.h
index 25c1166be..a71abc122 100644
--- a/tests/auto/compositor/compositor/testseat.h
+++ b/tests/auto/compositor/compositor/testseat.h
@@ -1,5 +1,5 @@
// Copyright (C) 2016 LG Electronics, Inc., author: <mikko.levonmaa@lge.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QWaylandSeat>
#include <QList>
diff --git a/tests/auto/compositor/compositor/tst_compositor.cpp b/tests/auto/compositor/compositor/tst_compositor.cpp
index 9c70ef84e..c3c0c35fb 100644
--- a/tests/auto/compositor/compositor/tst_compositor.cpp
+++ b/tests/auto/compositor/compositor/tst_compositor.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "mockclient.h"
#include "mockseat.h"
@@ -312,14 +312,14 @@ void tst_WaylandCompositor::keyboardGrab()
//QSignalSpy grabModifierSpy(grab, SIGNAL(modifiersCalled()));
seat->setKeyboardFocus(waylandSurface);
- QTRY_COMPARE(grabFocusSpy.count(), 1);
+ QTRY_COMPARE(grabFocusSpy.size(), 1);
QKeyEvent ke(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier, 30, 0, 0);
QKeyEvent ke1(QEvent::KeyRelease, Qt::Key_A, Qt::NoModifier, 30, 0, 0);
seat->sendFullKeyEvent(&ke);
seat->sendFullKeyEvent(&ke1);
- QTRY_COMPARE(grabKeyPressSpy.count(), 1);
- QTRY_COMPARE(grabKeyReleaseSpy.count(), 1);
+ QTRY_COMPARE(grabKeyPressSpy.size(), 1);
+ QTRY_COMPARE(grabKeyReleaseSpy.size(), 1);
QKeyEvent ke2(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier, 50, 0, 0);
QKeyEvent ke3(QEvent::KeyRelease, Qt::Key_Shift, Qt::NoModifier, 50, 0, 0);
@@ -327,14 +327,14 @@ void tst_WaylandCompositor::keyboardGrab()
seat->sendFullKeyEvent(&ke3);
//QTRY_COMPARE(grabModifierSpy.count(), 2);
// Modifiers are also keys
- QTRY_COMPARE(grabKeyPressSpy.count(), 2);
- QTRY_COMPARE(grabKeyReleaseSpy.count(), 2);
+ QTRY_COMPARE(grabKeyPressSpy.size(), 2);
+ QTRY_COMPARE(grabKeyReleaseSpy.size(), 2);
// Stop grabbing
seat->setKeyboardFocus(nullptr);
seat->sendFullKeyEvent(&ke);
seat->sendFullKeyEvent(&ke1);
- QTRY_COMPARE(grabKeyPressSpy.count(), 2);
+ QTRY_COMPARE(grabKeyPressSpy.size(), 2);
}
void tst_WaylandCompositor::geometry()
@@ -466,7 +466,7 @@ void tst_WaylandCompositor::mapSurface()
wl_surface_damage(surface, 0, 0, size.width(), size.height());
wl_surface_commit(surface);
- QTRY_COMPARE(hasContentSpy.count(), 1);
+ QTRY_COMPARE(hasContentSpy.size(), 1);
QCOMPARE(waylandSurface->hasContent(), true);
QCOMPARE(waylandSurface->bufferSize(), size);
QCOMPARE(waylandSurface->destinationSize(), size);
@@ -505,25 +505,30 @@ void tst_WaylandCompositor::mapSurfaceHiDpi()
QCOMPARE(waylandSurface->hasContent(), true);
};
- QObject::connect(waylandSurface, &QWaylandSurface::damaged, [=] (const QRegion &damage) {
+ QObject::connect(waylandSurface, &QWaylandSurface::damaged, this, [=] (const QRegion &damage) {
QCOMPARE(damage, QRect(QPoint(), surfaceSize));
verifyComittedState();
});
QSignalSpy damagedSpy(waylandSurface, SIGNAL(damaged(const QRegion &)));
- QObject::connect(waylandSurface, &QWaylandSurface::hasContentChanged, verifyComittedState);
+ QObject::connect(waylandSurface, &QWaylandSurface::hasContentChanged,
+ this, verifyComittedState);
QSignalSpy hasContentSpy(waylandSurface, SIGNAL(hasContentChanged()));
- QObject::connect(waylandSurface, &QWaylandSurface::bufferSizeChanged, verifyComittedState);
+ QObject::connect(waylandSurface, &QWaylandSurface::bufferSizeChanged,
+ this, verifyComittedState);
QSignalSpy bufferSizeSpy(waylandSurface, SIGNAL(bufferSizeChanged()));
- QObject::connect(waylandSurface, &QWaylandSurface::destinationSizeChanged, verifyComittedState);
+ QObject::connect(waylandSurface, &QWaylandSurface::destinationSizeChanged,
+ this, verifyComittedState);
QSignalSpy destinationSizeSpy(waylandSurface, SIGNAL(destinationSizeChanged()));
- QObject::connect(waylandSurface, &QWaylandSurface::bufferScaleChanged, verifyComittedState);
+ QObject::connect(waylandSurface, &QWaylandSurface::bufferScaleChanged,
+ this, verifyComittedState);
QSignalSpy bufferScaleSpy(waylandSurface, SIGNAL(bufferScaleChanged()));
- QObject::connect(waylandSurface, &QWaylandSurface::offsetForNextFrame, [=](const QPoint &offset) {
+ QObject::connect(waylandSurface, &QWaylandSurface::offsetForNextFrame,
+ this, [=](const QPoint &offset) {
QCOMPARE(offset, attachOffset);
verifyComittedState();
});
@@ -534,21 +539,21 @@ void tst_WaylandCompositor::mapSurfaceHiDpi()
QCOMPARE(waylandSurface->destinationSize(), QSize());
QCOMPARE(waylandSurface->hasContent(), false);
QCOMPARE(waylandSurface->bufferScale(), 1);
- QCOMPARE(offsetSpy.count(), 0);
+ QCOMPARE(offsetSpy.size(), 0);
wl_surface_commit(surface);
- QTRY_COMPARE(hasContentSpy.count(), 1);
- QTRY_COMPARE(bufferSizeSpy.count(), 1);
- QTRY_COMPARE(destinationSizeSpy.count(), 1);
- QTRY_COMPARE(bufferScaleSpy.count(), 1);
- QTRY_COMPARE(offsetSpy.count(), 1);
- QTRY_COMPARE(damagedSpy.count(), 1);
+ QTRY_COMPARE(hasContentSpy.size(), 1);
+ QTRY_COMPARE(bufferSizeSpy.size(), 1);
+ QTRY_COMPARE(destinationSizeSpy.size(), 1);
+ QTRY_COMPARE(bufferScaleSpy.size(), 1);
+ QTRY_COMPARE(offsetSpy.size(), 1);
+ QTRY_COMPARE(damagedSpy.size(), 1);
// Now verify that wl_surface_damage_buffer gets mapped properly
wl_surface_damage_buffer(surface, 0, 0, bufferSize.width(), bufferSize.height());
wl_surface_commit(surface);
- QTRY_COMPARE(damagedSpy.count(), 2);
+ QTRY_COMPARE(damagedSpy.size(), 2);
wl_surface_destroy(surface);
}
@@ -617,7 +622,7 @@ void tst_WaylandCompositor::frameCallback()
wl_surface_commit(surface);
QTRY_COMPARE(waylandSurface->hasContent(), true);
- QTRY_COMPARE(damagedSpy.count(), i + 1);
+ QTRY_COMPARE(damagedSpy.size(), i + 1);
QCOMPARE(static_cast<BufferView*>(waylandSurface->views().first())->image(), buffer.image);
compositor.defaultOutput()->frameStarted();
@@ -673,18 +678,18 @@ void tst_WaylandCompositor::outputs()
window.resize(800, 600);
auto output = new QWaylandOutput(&compositor, &window);
- QTRY_COMPARE(outputAddedSpy.count(), 1);
+ QTRY_COMPARE(outputAddedSpy.size(), 1);
compositor.setDefaultOutput(output);
- QTRY_COMPARE(defaultOutputSpy.count(), 2);
+ QTRY_COMPARE(defaultOutputSpy.size(), 2);
MockClient client;
QTRY_COMPARE(client.m_outputs.size(), 2);
delete output;
- QTRY_COMPARE(outputRemovedSpy.count(), 1);
+ QTRY_COMPARE(outputRemovedSpy.size(), 1);
QEXPECT_FAIL("", "FIXME: defaultOutputChanged() is not emitted when the default output is removed", Continue);
- QTRY_COMPARE(defaultOutputSpy.count(), 3);
+ QTRY_COMPARE(defaultOutputSpy.size(), 3);
compositor.flushClients();
QTRY_COMPARE(client.m_outputs.size(), 1);
}
@@ -960,13 +965,12 @@ void tst_WaylandCompositor::createsXdgSurfaces()
QSignalSpy xdgSurfaceCreatedSpy(&compositor.xdgShell, &QWaylandXdgShell::xdgSurfaceCreated);
QWaylandXdgSurface *xdgSurface = nullptr;
- QObject::connect(&compositor.xdgShell, &QWaylandXdgShell::xdgSurfaceCreated, [&](QWaylandXdgSurface *s) {
- xdgSurface = s;
- });
+ QObject::connect(&compositor.xdgShell, &QWaylandXdgShell::xdgSurfaceCreated,
+ this, [&](QWaylandXdgSurface *s) { xdgSurface = s; });
wl_surface *surface = client.createSurface();
xdg_surface *clientXdgSurface = client.createXdgSurface(surface);
- QTRY_COMPARE(xdgSurfaceCreatedSpy.count(), 1);
+ QTRY_COMPARE(xdgSurfaceCreatedSpy.size(), 1);
QTRY_VERIFY(xdgSurface);
QTRY_VERIFY(xdgSurface->surface());
@@ -980,9 +984,8 @@ void tst_WaylandCompositor::reportsXdgSurfaceWindowGeometry()
compositor.create();
QWaylandXdgSurface *xdgSurface = nullptr;
- QObject::connect(&compositor.xdgShell, &QWaylandXdgShell::xdgSurfaceCreated, [&](QWaylandXdgSurface *s) {
- xdgSurface = s;
- });
+ QObject::connect(&compositor.xdgShell, &QWaylandXdgShell::xdgSurfaceCreated,
+ this, [&](QWaylandXdgSurface *s) { xdgSurface = s; });
MockClient client;
wl_surface *surface = client.createSurface();
@@ -1017,9 +1020,8 @@ void tst_WaylandCompositor::setsXdgAppId()
compositor.create();
QWaylandXdgToplevel *toplevel = nullptr;
- QObject::connect(&compositor.xdgShell, &QWaylandXdgShell::toplevelCreated, [&](QWaylandXdgToplevel *t) {
- toplevel = t;
- });
+ QObject::connect(&compositor.xdgShell, &QWaylandXdgShell::toplevelCreated,
+ this, [&](QWaylandXdgToplevel *t) { toplevel = t; });
MockClient client;
wl_surface *surface = client.createSurface();
@@ -1063,9 +1065,8 @@ void tst_WaylandCompositor::sendsXdgConfigure()
compositor.create();
QWaylandXdgToplevel *toplevel = nullptr;
- QObject::connect(&compositor.xdgShell, &QWaylandXdgShell::toplevelCreated, [&](QWaylandXdgToplevel *t) {
- toplevel = t;
- });
+ QObject::connect(&compositor.xdgShell, &QWaylandXdgShell::toplevelCreated,
+ this, [&](QWaylandXdgToplevel *t) { toplevel = t; });
MockClient client;
wl_surface *surface = client.createSurface();
@@ -1177,13 +1178,12 @@ void tst_WaylandCompositor::createsIviSurfaces()
QSignalSpy iviSurfaceCreatedSpy(&compositor.iviApplication, &QWaylandIviApplication::iviSurfaceRequested);
QWaylandIviSurface *iviSurface = nullptr;
- QObject::connect(&compositor.iviApplication, &QWaylandIviApplication::iviSurfaceCreated, [&](QWaylandIviSurface *s) {
- iviSurface = s;
- });
+ QObject::connect(&compositor.iviApplication, &QWaylandIviApplication::iviSurfaceCreated,
+ this, [&](QWaylandIviSurface *s) { iviSurface = s; });
wl_surface *surface = client.createSurface();
client.createIviSurface(surface, 123);
- QTRY_COMPARE(iviSurfaceCreatedSpy.count(), 1);
+ QTRY_COMPARE(iviSurfaceCreatedSpy.size(), 1);
QTRY_VERIFY(iviSurface);
QTRY_VERIFY(iviSurface->surface());
QTRY_COMPARE(iviSurface->iviId(), 123u);
@@ -1199,9 +1199,10 @@ void tst_WaylandCompositor::emitsErrorOnSameIviId()
QTRY_VERIFY(&firstClient.iviApplication);
QWaylandIviSurface *firstIviSurface = nullptr;
- QObject::connect(&compositor.iviApplication, &QWaylandIviApplication::iviSurfaceCreated, [&](QWaylandIviSurface *s) {
- firstIviSurface = s;
- });
+ auto connection = QObject::connect(&compositor.iviApplication,
+ &QWaylandIviApplication::iviSurfaceCreated,
+ this,
+ [&](QWaylandIviSurface *s) { firstIviSurface = s; });
firstClient.createIviSurface(firstClient.createSurface(), 123);
QTRY_VERIFY(firstIviSurface);
@@ -1210,7 +1211,7 @@ void tst_WaylandCompositor::emitsErrorOnSameIviId()
{
MockClient secondClient;
QTRY_VERIFY(&secondClient.iviApplication);
- QTRY_COMPARE(compositor.clients().count(), 2);
+ QTRY_COMPARE(compositor.clients().size(), 2);
secondClient.createIviSurface(secondClient.createSurface(), 123);
compositor.flushClients();
@@ -1218,8 +1219,9 @@ void tst_WaylandCompositor::emitsErrorOnSameIviId()
QTRY_COMPARE(secondClient.error, EPROTO);
QTRY_COMPARE(secondClient.protocolError.interface, &ivi_application_interface);
QTRY_COMPARE(static_cast<ivi_application_error>(secondClient.protocolError.code), IVI_APPLICATION_ERROR_IVI_ID);
- QTRY_COMPARE(compositor.clients().count(), 1);
+ QTRY_COMPARE(compositor.clients().size(), 1);
}
+ QObject::disconnect(connection);
}
// The other clients have passed out of scope and have been destroyed,
@@ -1228,9 +1230,8 @@ void tst_WaylandCompositor::emitsErrorOnSameIviId()
QTRY_VERIFY(&thirdClient.iviApplication);
QWaylandIviSurface *thirdIviSurface = nullptr;
- QObject::connect(&compositor.iviApplication, &QWaylandIviApplication::iviSurfaceCreated, [&](QWaylandIviSurface *s) {
- thirdIviSurface = s;
- });
+ QObject::connect(&compositor.iviApplication, &QWaylandIviApplication::iviSurfaceCreated,
+ this, [&](QWaylandIviSurface *s) { thirdIviSurface = s; });
thirdClient.createIviSurface(thirdClient.createSurface(), 123);
compositor.flushClients();
@@ -1259,9 +1260,8 @@ void tst_WaylandCompositor::sendsIviConfigure()
QTRY_VERIFY(client.iviApplication);
QWaylandIviSurface *iviSurface = nullptr;
- QObject::connect(&compositor.iviApplication, &QWaylandIviApplication::iviSurfaceCreated, [&](QWaylandIviSurface *s) {
- iviSurface = s;
- });
+ QObject::connect(&compositor.iviApplication, &QWaylandIviApplication::iviSurfaceCreated,
+ this, [&](QWaylandIviSurface *s) { iviSurface = s; });
wl_surface *surface = client.createSurface();
ivi_surface *clientIviSurface = client.createIviSurface(surface, 123);
@@ -1283,16 +1283,15 @@ void tst_WaylandCompositor::destroysIviSurfaces()
QTRY_VERIFY(client.iviApplication);
QWaylandIviSurface *iviSurface = nullptr;
- QObject::connect(&compositor.iviApplication, &QWaylandIviApplication::iviSurfaceCreated, [&](QWaylandIviSurface *s) {
- iviSurface = s;
- });
+ QObject::connect(&compositor.iviApplication, &QWaylandIviApplication::iviSurfaceCreated,
+ this, [&](QWaylandIviSurface *s) { iviSurface = s; });
QtWayland::ivi_surface mockIviSurface(client.createIviSurface(client.createSurface(), 123));
QTRY_VERIFY(iviSurface);
QSignalSpy destroySpy(iviSurface, SIGNAL(destroyed()));
mockIviSurface.destroy();
- QTRY_VERIFY(destroySpy.count() == 1);
+ QTRY_VERIFY(destroySpy.size() == 1);
}
class ViewporterTestCompositor: public TestCompositor {
@@ -1728,7 +1727,7 @@ void tst_WaylandCompositor::idleInhibit()
QVERIFY(idleInhibitor);
QTRY_COMPARE(waylandSurfacePrivate->idleInhibitors.size(), 1);
QCOMPARE(waylandSurface->inhibitsIdle(), true);
- QTRY_COMPARE(changedSpy.count(), 1);
+ QTRY_COMPARE(changedSpy.size(), 1);
}
class XdgOutputCompositor : public TestCompositor
diff --git a/tests/manual/CMakeLists.txt b/tests/manual/CMakeLists.txt
index 9399a10ab..87ae459fd 100644
--- a/tests/manual/CMakeLists.txt
+++ b/tests/manual/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
if(TARGET Qt::WaylandClient)
add_subdirectory(qmlclient)
add_subdirectory(subsurface)
@@ -8,4 +11,9 @@ endif()
if(TARGET Qt::WaylandCompositor)
#add_subdirectory(wip-cpp-compositor)
add_subdirectory(scaling-compositor)
+ add_subdirectory(hwlayer-compositor)
+endif()
+
+if(QT_FEATURE_opengl AND TARGET Qt::Quick AND TARGET Qt::WaylandClient)
+ add_subdirectory(server-buffer)
endif()
diff --git a/examples/wayland/hwlayer-compositor/.gitignore b/tests/manual/hwlayer-compositor/.gitignore
index 83a421caf..83a421caf 100644
--- a/examples/wayland/hwlayer-compositor/.gitignore
+++ b/tests/manual/hwlayer-compositor/.gitignore
diff --git a/examples/wayland/hwlayer-compositor/CMakeLists.txt b/tests/manual/hwlayer-compositor/CMakeLists.txt
index 049d4ad2f..729bae99b 100644
--- a/examples/wayland/hwlayer-compositor/CMakeLists.txt
+++ b/tests/manual/hwlayer-compositor/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(hwlayer-compositor LANGUAGES CXX)
diff --git a/examples/wayland/hwlayer-compositor/hwlayer-compositor.pro b/tests/manual/hwlayer-compositor/hwlayer-compositor.pro
index a6eed9079..a6eed9079 100644
--- a/examples/wayland/hwlayer-compositor/hwlayer-compositor.pro
+++ b/tests/manual/hwlayer-compositor/hwlayer-compositor.pro
diff --git a/examples/wayland/hwlayer-compositor/hwlayer-compositor.qrc b/tests/manual/hwlayer-compositor/hwlayer-compositor.qrc
index 5f6483ac3..5f6483ac3 100644
--- a/examples/wayland/hwlayer-compositor/hwlayer-compositor.qrc
+++ b/tests/manual/hwlayer-compositor/hwlayer-compositor.qrc
diff --git a/examples/wayland/hwlayer-compositor/main.cpp b/tests/manual/hwlayer-compositor/main.cpp
index acecb9225..85cab3cec 100644
--- a/examples/wayland/hwlayer-compositor/main.cpp
+++ b/tests/manual/hwlayer-compositor/main.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtCore/QUrl>
#include <QtCore/QDebug>
diff --git a/examples/wayland/hwlayer-compositor/main.qml b/tests/manual/hwlayer-compositor/main.qml
index 9d6648fe9..32a197ac1 100644
--- a/examples/wayland/hwlayer-compositor/main.qml
+++ b/tests/manual/hwlayer-compositor/main.qml
@@ -1,9 +1,9 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtQuick.Window
-import QtQuick.Controls 2.2
+import QtQuick.Controls
import QtWayland.Compositor
import QtWayland.Compositor.XdgShell
import QtWayland.Compositor.WlShell
@@ -32,37 +32,37 @@ WaylandCompositor {
duration: 1000
}
}
- Repeater {
- model: shellSurfaces
- ShellSurfaceItem {
- id: waylandItem
- onSurfaceDestroyed: shellSurfaces.remove(index)
- shellSurface: shSurface
- WaylandHardwareLayer {
- stackingLevel: level
- Component.onCompleted: console.log("Added hardware layer with stacking level", stackingLevel);
- }
- Component.onCompleted: console.log("Added wayland quick item");
- Behavior on x {
- PropertyAnimation {
- easing.type: Easing.OutBounce
- duration: 1000
- }
- }
- Timer {
- interval: 2000; running: animatePosition; repeat: true
- onTriggered: waylandItem.x = waylandItem.x === 0 ? win.width - waylandItem.width : 0
- }
- Behavior on opacity {
- PropertyAnimation {
- duration: 1000
- }
+ Repeater {
+ model: shellSurfaces
+ ShellSurfaceItem {
+ id: waylandItem
+ onSurfaceDestroyed: shellSurfaces.remove(index)
+ shellSurface: shSurface
+ WaylandHardwareLayer {
+ stackingLevel: level
+ Component.onCompleted: console.log("Added hardware layer with stacking level", stackingLevel);
+ }
+ Component.onCompleted: console.log("Added wayland quick item");
+ Behavior on x {
+ PropertyAnimation {
+ easing.type: Easing.OutBounce
+ duration: 1000
}
- Timer {
- interval: 2000; running: animateOpacity; repeat: true
- onTriggered: waylandItem.opacity = waylandItem.opacity === 1 ? 0 : 1
+ }
+ Timer {
+ interval: 2000; running: animatePosition; repeat: true
+ onTriggered: waylandItem.x = waylandItem.x === 0 ? win.width - waylandItem.width : 0
+ }
+ Behavior on opacity {
+ PropertyAnimation {
+ duration: 1000
}
}
+ Timer {
+ interval: 2000; running: animateOpacity; repeat: true
+ onTriggered: waylandItem.opacity = waylandItem.opacity === 1 ? 0 : 1
+ }
+ }
}
Column {
anchors.bottom: parent.bottom
@@ -94,7 +94,7 @@ WaylandCompositor {
}
Button {
text: "Kill"
- onClicked: shSurface.surface.client.close()
+ onClicked: shSurface.surface.client.kill()
}
}
}
@@ -111,7 +111,7 @@ WaylandCompositor {
function addShellSurface(shellSurface) {
shellSurfaces.append({shSurface: shellSurface, animatePosition: false, animateOpacity: false, level: 0});
}
- XdgShell { onToplevelCreated: addShellSurface(xdgSurface) }
- IviApplication { onIviSurfaceCreated: addShellSurface(iviSurface) }
- WlShell { onWlShellSurfaceCreated: addShellSurface(shellSurface) }
+ XdgShell { onToplevelCreated: (toplevel, xdgSurface) => addShellSurface(xdgSurface) }
+ IviApplication { onIviSurfaceCreated: (iviSurface) => addShellSurface(iviSurface) }
+ WlShell { onWlShellSurfaceCreated: (shellSurface) => addShellSurface(shellSurface) }
}
diff --git a/tests/manual/keymap/keymapcompositor.qml b/tests/manual/keymap/keymapcompositor.qml
index bdc6f4f90..7d8bcda7c 100644
--- a/tests/manual/keymap/keymapcompositor.qml
+++ b/tests/manual/keymap/keymapcompositor.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
import QtWayland.Compositor 1.0
diff --git a/tests/manual/qmlclient/CMakeLists.txt b/tests/manual/qmlclient/CMakeLists.txt
index b91ee4a2c..7dedc67bf 100644
--- a/tests/manual/qmlclient/CMakeLists.txt
+++ b/tests/manual/qmlclient/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qmlclient.pro.
#####################################################################
@@ -8,7 +11,7 @@ qt_internal_add_manual_test(qmlclient
GUI
SOURCES
main.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
diff --git a/tests/manual/qmlclient/main.cpp b/tests/manual/qmlclient/main.cpp
index 3ab34e8e8..673359b52 100644
--- a/tests/manual/qmlclient/main.cpp
+++ b/tests/manual/qmlclient/main.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtGui/QGuiApplication>
#include <QtQml/QQmlApplicationEngine>
diff --git a/tests/manual/qmlclient/main.qml b/tests/manual/qmlclient/main.qml
index c7cb81498..b5061c182 100644
--- a/tests/manual/qmlclient/main.qml
+++ b/tests/manual/qmlclient/main.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2016 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
import QtQuick.Window 2.2
diff --git a/tests/manual/qt-shell/CMakeLists.txt b/tests/manual/qt-shell/CMakeLists.txt
index 5a38aae4c..daf8fb25d 100644
--- a/tests/manual/qt-shell/CMakeLists.txt
+++ b/tests/manual/qt-shell/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
cmake_minimum_required(VERSION 3.14)
project(qt-shell LANGUAGES CXX)
diff --git a/tests/manual/qt-shell/main.cpp b/tests/manual/qt-shell/main.cpp
index 2a7ba661e..31bd58fae 100644
--- a/tests/manual/qt-shell/main.cpp
+++ b/tests/manual/qt-shell/main.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtCore/QUrl>
#include <QtCore/QDebug>
diff --git a/tests/manual/qt-shell/qml/Chrome.qml b/tests/manual/qt-shell/qml/Chrome.qml
index 2cde0789d..9eb2f1965 100644
--- a/tests/manual/qt-shell/qml/Chrome.qml
+++ b/tests/manual/qt-shell/qml/Chrome.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtQuick.Controls
diff --git a/tests/manual/qt-shell/qml/CompositorScreen.qml b/tests/manual/qt-shell/qml/CompositorScreen.qml
index 62886b726..92b75b348 100644
--- a/tests/manual/qt-shell/qml/CompositorScreen.qml
+++ b/tests/manual/qt-shell/qml/CompositorScreen.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtQuick.Window
diff --git a/tests/manual/qt-shell/qml/HandleHandler.qml b/tests/manual/qt-shell/qml/HandleHandler.qml
index 100dec695..7b31ad4d5 100644
--- a/tests/manual/qt-shell/qml/HandleHandler.qml
+++ b/tests/manual/qt-shell/qml/HandleHandler.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
diff --git a/tests/manual/qt-shell/qml/Keyboard.qml b/tests/manual/qt-shell/qml/Keyboard.qml
index d565351c8..a6e1bec30 100644
--- a/tests/manual/qt-shell/qml/Keyboard.qml
+++ b/tests/manual/qt-shell/qml/Keyboard.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtQuick.VirtualKeyboard
diff --git a/tests/manual/qt-shell/qml/main.qml b/tests/manual/qt-shell/qml/main.qml
index 31d0c3108..986e0a490 100644
--- a/tests/manual/qt-shell/qml/main.qml
+++ b/tests/manual/qt-shell/qml/main.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtWayland.Compositor
diff --git a/tests/manual/scaling-compositor/CMakeLists.txt b/tests/manual/scaling-compositor/CMakeLists.txt
index c64b507fc..2ee7d96bc 100644
--- a/tests/manual/scaling-compositor/CMakeLists.txt
+++ b/tests/manual/scaling-compositor/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from scaling-compositor.pro.
#####################################################################
@@ -8,7 +11,7 @@ qt_internal_add_manual_test(scaling-compositor
GUI
SOURCES
main.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::Qml
)
diff --git a/tests/manual/scaling-compositor/main.cpp b/tests/manual/scaling-compositor/main.cpp
index 6bed8cd81..e972b9ca6 100644
--- a/tests/manual/scaling-compositor/main.cpp
+++ b/tests/manual/scaling-compositor/main.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtGui/QGuiApplication>
#include <QtQml/QQmlApplicationEngine>
diff --git a/tests/manual/scaling-compositor/main.qml b/tests/manual/scaling-compositor/main.qml
index 75a9d1c59..f173de3a0 100644
--- a/tests/manual/scaling-compositor/main.qml
+++ b/tests/manual/scaling-compositor/main.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.15
import QtQuick.Window 2.2
diff --git a/tests/manual/server-buffer/CMakeLists.txt b/tests/manual/server-buffer/CMakeLists.txt
new file mode 100644
index 000000000..973063c71
--- /dev/null
+++ b/tests/manual/server-buffer/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.16)
+project(server-buffer)
+
+add_subdirectory(cpp-client)
+add_subdirectory(compositor)
diff --git a/examples/wayland/server-buffer/README b/tests/manual/server-buffer/README
index da20b0f50..ae76ca755 100644
--- a/examples/wayland/server-buffer/README
+++ b/tests/manual/server-buffer/README
@@ -18,7 +18,7 @@ The compositor broadcasts the name of the server buffer integration to
all clients through the hardware integration extension. Therefore,
all you need to do is to start the client with
-$ ./cpp-client -platform wayland
+$ ./server-buffer-cpp-client -platform wayland
The client will show all the buffers shared by the compositor.
diff --git a/examples/wayland/server-buffer/compositor/CMakeLists.txt b/tests/manual/server-buffer/compositor/CMakeLists.txt
index d270106dc..5f4fb0c51 100644
--- a/examples/wayland/server-buffer/compositor/CMakeLists.txt
+++ b/tests/manual/server-buffer/compositor/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(compositor)
diff --git a/examples/wayland/server-buffer/compositor/compositor.pro b/tests/manual/server-buffer/compositor/compositor.pro
index 26334c63c..26334c63c 100644
--- a/examples/wayland/server-buffer/compositor/compositor.pro
+++ b/tests/manual/server-buffer/compositor/compositor.pro
diff --git a/examples/wayland/server-buffer/compositor/compositor.qrc b/tests/manual/server-buffer/compositor/compositor.qrc
index b50594b55..b50594b55 100644
--- a/examples/wayland/server-buffer/compositor/compositor.qrc
+++ b/tests/manual/server-buffer/compositor/compositor.qrc
diff --git a/examples/wayland/server-buffer/compositor/images/Siberischer_tiger_de_edit02.jpg b/tests/manual/server-buffer/compositor/images/Siberischer_tiger_de_edit02.jpg
index eb1b73f84..eb1b73f84 100644
--- a/examples/wayland/server-buffer/compositor/images/Siberischer_tiger_de_edit02.jpg
+++ b/tests/manual/server-buffer/compositor/images/Siberischer_tiger_de_edit02.jpg
Binary files differ
diff --git a/examples/wayland/server-buffer/compositor/images/Siberischer_tiger_de_edit02.txt b/tests/manual/server-buffer/compositor/images/Siberischer_tiger_de_edit02.txt
index 3a26c00d3..3a26c00d3 100644
--- a/examples/wayland/server-buffer/compositor/images/Siberischer_tiger_de_edit02.txt
+++ b/tests/manual/server-buffer/compositor/images/Siberischer_tiger_de_edit02.txt
diff --git a/examples/wayland/server-buffer/compositor/images/background.png b/tests/manual/server-buffer/compositor/images/background.png
index 292160cd8..292160cd8 100644
--- a/examples/wayland/server-buffer/compositor/images/background.png
+++ b/tests/manual/server-buffer/compositor/images/background.png
Binary files differ
diff --git a/examples/wayland/server-buffer/compositor/main.cpp b/tests/manual/server-buffer/compositor/main.cpp
index 3c33620c5..36e607e34 100644
--- a/examples/wayland/server-buffer/compositor/main.cpp
+++ b/tests/manual/server-buffer/compositor/main.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtCore/QUrl>
#include <QtCore/QDebug>
diff --git a/examples/wayland/server-buffer/compositor/qml/main.qml b/tests/manual/server-buffer/compositor/qml/main.qml
index dc2a2fb8c..4227584af 100644
--- a/examples/wayland/server-buffer/compositor/qml/main.qml
+++ b/tests/manual/server-buffer/compositor/qml/main.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtWayland.Compositor
@@ -24,6 +24,7 @@ WaylandCompositor {
}
}
}
+
Component {
id: chromeComponent
ShellSurfaceItem {
@@ -32,11 +33,11 @@ WaylandCompositor {
}
WlShell {
- onWlShellSurfaceCreated:
+ onWlShellSurfaceCreated: (shellSurface) => {
chromeComponent.createObject(surfaceArea, { "shellSurface": shellSurface } );
+ }
}
ShareBufferExtension {
}
-
}
diff --git a/examples/wayland/server-buffer/compositor/sharebufferextension.cpp b/tests/manual/server-buffer/compositor/sharebufferextension.cpp
index 9e658767e..bc8b01af3 100644
--- a/examples/wayland/server-buffer/compositor/sharebufferextension.cpp
+++ b/tests/manual/server-buffer/compositor/sharebufferextension.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "sharebufferextension.h"
@@ -77,7 +77,7 @@ void ShareBufferExtension::share_buffer_bind_resource(Resource *resource)
if (!m_server_buffers_created)
createServerBuffers();
- for (auto *buffer : qAsConst(m_server_buffers)) {
+ for (auto *buffer : std::as_const(m_server_buffers)) {
qDebug() << "sending" << buffer << "to client";
struct ::wl_client *client = wl_resource_get_client(resource->handle);
struct ::wl_resource *buffer_resource = buffer->resourceForClient(client);
diff --git a/examples/wayland/server-buffer/compositor/sharebufferextension.h b/tests/manual/server-buffer/compositor/sharebufferextension.h
index 98dcc7d83..58809e3d4 100644
--- a/examples/wayland/server-buffer/compositor/sharebufferextension.h
+++ b/tests/manual/server-buffer/compositor/sharebufferextension.h
@@ -1,5 +1,5 @@
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef SHAREBUFFEREXTENSION_H
#define SHAREBUFFEREXTENSION_H
diff --git a/examples/wayland/server-buffer/cpp-client/CMakeLists.txt b/tests/manual/server-buffer/cpp-client/CMakeLists.txt
index 5ecec45ed..01c0df44f 100644
--- a/examples/wayland/server-buffer/cpp-client/CMakeLists.txt
+++ b/tests/manual/server-buffer/cpp-client/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(server-buffer-cpp-client)
diff --git a/examples/wayland/server-buffer/cpp-client/cpp-client.pro b/tests/manual/server-buffer/cpp-client/cpp-client.pro
index 6ac551323..6ac551323 100644
--- a/examples/wayland/server-buffer/cpp-client/cpp-client.pro
+++ b/tests/manual/server-buffer/cpp-client/cpp-client.pro
diff --git a/examples/wayland/server-buffer/cpp-client/main.cpp b/tests/manual/server-buffer/cpp-client/main.cpp
index 8adac2520..b11921f67 100644
--- a/examples/wayland/server-buffer/cpp-client/main.cpp
+++ b/tests/manual/server-buffer/cpp-client/main.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QGuiApplication>
#include <QtGui/private/qguiapplication_p.h>
diff --git a/examples/wayland/server-buffer/cpp-client/sharebufferextension.cpp b/tests/manual/server-buffer/cpp-client/sharebufferextension.cpp
index 3641ec636..299684a89 100644
--- a/examples/wayland/server-buffer/cpp-client/sharebufferextension.cpp
+++ b/tests/manual/server-buffer/cpp-client/sharebufferextension.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "sharebufferextension.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
diff --git a/examples/wayland/server-buffer/cpp-client/sharebufferextension.h b/tests/manual/server-buffer/cpp-client/sharebufferextension.h
index 78e3ca7f1..6fc429194 100644
--- a/examples/wayland/server-buffer/cpp-client/sharebufferextension.h
+++ b/tests/manual/server-buffer/cpp-client/sharebufferextension.h
@@ -1,5 +1,5 @@
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef SHAREBUFFEREXTENSION_H
#define SHAREBUFFEREXTENSION_H
diff --git a/examples/wayland/server-buffer/server-buffer.pro b/tests/manual/server-buffer/server-buffer.pro
index 0c737ea8c..0c737ea8c 100644
--- a/examples/wayland/server-buffer/server-buffer.pro
+++ b/tests/manual/server-buffer/server-buffer.pro
diff --git a/examples/wayland/server-buffer/share-buffer.xml b/tests/manual/server-buffer/share-buffer.xml
index 53020c4e9..2a4ae6748 100644
--- a/examples/wayland/server-buffer/share-buffer.xml
+++ b/tests/manual/server-buffer/share-buffer.xml
@@ -2,7 +2,7 @@
<copyright>
Copyright (C) 2015 The Qt Company Ltd.
- SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+ SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
</copyright>
<interface name="qt_share_buffer" version="1">
diff --git a/tests/manual/subsurface/CMakeLists.txt b/tests/manual/subsurface/CMakeLists.txt
index 9d8eda99d..0c1b50e0c 100644
--- a/tests/manual/subsurface/CMakeLists.txt
+++ b/tests/manual/subsurface/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from subsurface.pro.
#####################################################################
@@ -9,7 +12,7 @@ qt_internal_add_manual_test(subsurface
SOURCES
main.cpp
shmwindow.cpp shmwindow.h
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
diff --git a/tests/manual/subsurface/child.qml b/tests/manual/subsurface/child.qml
index 588cb924b..82d2e0757 100644
--- a/tests/manual/subsurface/child.qml
+++ b/tests/manual/subsurface/child.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2015 LG Electronics Inc, author: <mikko.levonmaa@lge.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.4
import QtQuick.Window 2.2
diff --git a/tests/manual/subsurface/main.cpp b/tests/manual/subsurface/main.cpp
index 7936f5b9f..c353496c0 100644
--- a/tests/manual/subsurface/main.cpp
+++ b/tests/manual/subsurface/main.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2015 LG Electronics Inc, author: <mikko.levonmaa@lge.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QGuiApplication>
#include <QQmlEngine>
diff --git a/tests/manual/subsurface/main.qml b/tests/manual/subsurface/main.qml
index 504290ec9..e6f7eeb79 100644
--- a/tests/manual/subsurface/main.qml
+++ b/tests/manual/subsurface/main.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2015 LG Electronics Inc, author: <mikko.levonmaa@lge.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.4
import QtQuick.Window 2.2
diff --git a/tests/manual/subsurface/shmwindow.cpp b/tests/manual/subsurface/shmwindow.cpp
index 33798f9b8..c6b59d132 100644
--- a/tests/manual/subsurface/shmwindow.cpp
+++ b/tests/manual/subsurface/shmwindow.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2015 LG Electronics Ltd, author: <mikko.levonmaa@lge.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "shmwindow.h"
diff --git a/tests/manual/subsurface/shmwindow.h b/tests/manual/subsurface/shmwindow.h
index 9d3c5ec4e..55a0336e6 100644
--- a/tests/manual/subsurface/shmwindow.h
+++ b/tests/manual/subsurface/shmwindow.h
@@ -1,5 +1,5 @@
// Copyright (C) 2015 LG Electronics Ltd, author: <mikko.levonmaa@lge.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef SHMWINDOW_H
#define SHMWINDOW_H
diff --git a/tests/manual/texture-sharing-2/CMakeLists.txt b/tests/manual/texture-sharing-2/CMakeLists.txt
index bf6a7cbf9..9a212ea3e 100644
--- a/tests/manual/texture-sharing-2/CMakeLists.txt
+++ b/tests/manual/texture-sharing-2/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from texture-sharing.pro.
add_subdirectory(qml-client)
diff --git a/tests/manual/texture-sharing-2/custom-compositor/CMakeLists.txt b/tests/manual/texture-sharing-2/custom-compositor/CMakeLists.txt
index c8d9839c7..1a6c1494a 100644
--- a/tests/manual/texture-sharing-2/custom-compositor/CMakeLists.txt
+++ b/tests/manual/texture-sharing-2/custom-compositor/CMakeLists.txt
@@ -1,37 +1,13 @@
-# Generated from custom-compositor.pro.
-
-cmake_minimum_required(VERSION 3.16)
-project(texture-sharing-custom-compositor LANGUAGES CXX)
-
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
-
-set(CMAKE_AUTOMOC ON)
-set(CMAKE_AUTORCC ON)
-set(CMAKE_AUTOUIC ON)
-
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/wayland/texture-sharing/custom-compositor")
-
-find_package(Qt6 COMPONENTS Core)
-find_package(Qt6 COMPONENTS Gui)
-find_package(Qt6 COMPONENTS Qml)
-find_package(Qt6 COMPONENTS WaylandCompositor)
-
-qt_add_executable(texture-sharing-custom-compositor
- main.cpp
-)
-set_target_properties(texture-sharing-custom-compositor PROPERTIES
- WIN32_EXECUTABLE TRUE
- MACOSX_BUNDLE TRUE
-)
-target_link_libraries(texture-sharing-custom-compositor PUBLIC
- Qt::Core
- Qt::Gui
- Qt::Qml
- Qt::WaylandCompositorPrivate
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_manual_test(texture-sharing-custom-compositor
+ GUI
+ SOURCES
+ main.cpp
+ LIBRARIES
+ Qt::Qml
+ Qt::WaylandCompositorPrivate
)
@@ -44,15 +20,9 @@ set(compositor_resource_files
"qml/main.qml"
)
-qt6_add_resources(texture-sharing-custom-compositor "compositor"
+qt_internal_add_resource(texture-sharing-custom-compositor "compositor"
PREFIX
"/"
FILES
${compositor_resource_files}
)
-
-install(TARGETS texture-sharing-custom-compositor
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
-)
diff --git a/tests/manual/texture-sharing-2/custom-compositor/main.cpp b/tests/manual/texture-sharing-2/custom-compositor/main.cpp
index 323a34ba9..0c229413b 100644
--- a/tests/manual/texture-sharing-2/custom-compositor/main.cpp
+++ b/tests/manual/texture-sharing-2/custom-compositor/main.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtCore/QUrl>
#include <QtCore/QDebug>
diff --git a/tests/manual/texture-sharing-2/custom-compositor/qml/main.qml b/tests/manual/texture-sharing-2/custom-compositor/qml/main.qml
index 61237a0a6..dd1f60f4e 100644
--- a/tests/manual/texture-sharing-2/custom-compositor/qml/main.qml
+++ b/tests/manual/texture-sharing-2/custom-compositor/qml/main.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtQuick.Window
diff --git a/tests/manual/texture-sharing-2/minimal-compositor.qml b/tests/manual/texture-sharing-2/minimal-compositor.qml
index 2e457d147..d12216156 100644
--- a/tests/manual/texture-sharing-2/minimal-compositor.qml
+++ b/tests/manual/texture-sharing-2/minimal-compositor.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtQuick.Window
diff --git a/tests/manual/texture-sharing-2/qml-client/CMakeLists.txt b/tests/manual/texture-sharing-2/qml-client/CMakeLists.txt
index dc88cb30f..ce6bc118d 100644
--- a/tests/manual/texture-sharing-2/qml-client/CMakeLists.txt
+++ b/tests/manual/texture-sharing-2/qml-client/CMakeLists.txt
@@ -1,52 +1,22 @@
-# Generated from qml-client.pro.
-
-cmake_minimum_required(VERSION 3.16)
-project(qml-client LANGUAGES CXX)
-
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
-
-set(CMAKE_AUTOMOC ON)
-set(CMAKE_AUTORCC ON)
-set(CMAKE_AUTOUIC ON)
-
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/wayland/texture-sharing/qml-client")
-
-find_package(Qt6 COMPONENTS Core)
-find_package(Qt6 COMPONENTS Gui)
-find_package(Qt6 COMPONENTS Quick)
-
-qt_add_executable(qml-client
- main.cpp
-)
-set_target_properties(qml-client PROPERTIES
- WIN32_EXECUTABLE TRUE
- MACOSX_BUNDLE TRUE
-)
-target_link_libraries(qml-client PUBLIC
- Qt::Core
- Qt::Gui
- Qt::Quick
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_manual_test(qml-client
+ GUI
+ SOURCES
+ main.cpp
+ LIBRARIES
+ Qt::Quick
)
-
# Resources:
set(qml-client_resource_files
"main.qml"
)
-qt6_add_resources(qml-client "qml-client"
+qt_internal_add_resource(qml-client "qml-client"
PREFIX
"/"
FILES
${qml-client_resource_files}
)
-
-install(TARGETS qml-client
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
-)
diff --git a/tests/manual/texture-sharing-2/qml-client/main.cpp b/tests/manual/texture-sharing-2/qml-client/main.cpp
index d9058f10b..8af386939 100644
--- a/tests/manual/texture-sharing-2/qml-client/main.cpp
+++ b/tests/manual/texture-sharing-2/qml-client/main.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QGuiApplication>
#include <QtQuick/QQuickView>
diff --git a/tests/manual/texture-sharing-2/qml-client/main.qml b/tests/manual/texture-sharing-2/qml-client/main.qml
index 86b85551f..819a93bcf 100644
--- a/tests/manual/texture-sharing-2/qml-client/main.qml
+++ b/tests/manual/texture-sharing-2/qml-client/main.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtQuick.Window
diff --git a/tests/manual/texture-sharing/cpp-client/CMakeLists.txt b/tests/manual/texture-sharing/cpp-client/CMakeLists.txt
index f6495a5bf..1059e6e5e 100644
--- a/tests/manual/texture-sharing/cpp-client/CMakeLists.txt
+++ b/tests/manual/texture-sharing/cpp-client/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from cpp-client.pro.
#####################################################################
@@ -7,11 +10,12 @@
qt_internal_add_manual_test(cpp-client
GUI
SOURCES
- ../../../../src/imports/texture-sharing/texturesharingextension.cpp ../../../../src/imports/texture-sharing/texturesharingextension.h
+ ../../../../src/imports/texture-sharing/texturesharingextension.cpp
+ ../../../../src/imports/texture-sharing/texturesharingextension_p.h
main.cpp
INCLUDE_DIRECTORIES
../../../../src/imports/texture-sharing
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::GuiPrivate
Qt::OpenGL
diff --git a/tests/manual/texture-sharing/cpp-client/main.cpp b/tests/manual/texture-sharing/cpp-client/main.cpp
index 3c0a826f4..f992ea1b6 100644
--- a/tests/manual/texture-sharing/cpp-client/main.cpp
+++ b/tests/manual/texture-sharing/cpp-client/main.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QGuiApplication>
#include <QtGui/private/qguiapplication_p.h>
@@ -87,7 +87,7 @@ protected:
int x = 0;
qDebug() << "*** paintGL ***";
showBuffers();
- for (auto buffer: qAsConst(m_buffers)) {
+ for (auto buffer: std::as_const(m_buffers)) {
m_blitter->bind();
QSize s(buffer->size());
qDebug() << "painting" << buffer << s;
diff --git a/tests/manual/wip-cpp-compositor/CMakeLists.txt b/tests/manual/wip-cpp-compositor/CMakeLists.txt
index 4bae44d2d..4d8a166ed 100644
--- a/tests/manual/wip-cpp-compositor/CMakeLists.txt
+++ b/tests/manual/wip-cpp-compositor/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from wip-cpp-compositor.pro.
#####################################################################
@@ -10,7 +13,7 @@ qt_internal_add_manual_test(wip-cpp-compositor
compositor.cpp compositor.h
main.cpp
window.cpp window.h
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::WaylandCompositor
)
diff --git a/tests/manual/wip-cpp-compositor/compositor.cpp b/tests/manual/wip-cpp-compositor/compositor.cpp
index 6cf72cf9e..2f7025115 100644
--- a/tests/manual/wip-cpp-compositor/compositor.cpp
+++ b/tests/manual/wip-cpp-compositor/compositor.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "compositor.h"
#include "window.h"
diff --git a/tests/manual/wip-cpp-compositor/compositor.h b/tests/manual/wip-cpp-compositor/compositor.h
index 713d1e88c..b2810d0da 100644
--- a/tests/manual/wip-cpp-compositor/compositor.h
+++ b/tests/manual/wip-cpp-compositor/compositor.h
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef COMPOSITOR_H
#define COMPOSITOR_H
diff --git a/tests/manual/wip-cpp-compositor/main.cpp b/tests/manual/wip-cpp-compositor/main.cpp
index 36475b1e4..e8a34a14f 100644
--- a/tests/manual/wip-cpp-compositor/main.cpp
+++ b/tests/manual/wip-cpp-compositor/main.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QGuiApplication>
#include "window.h"
diff --git a/tests/manual/wip-cpp-compositor/window.cpp b/tests/manual/wip-cpp-compositor/window.cpp
index 0a61272f8..413e56572 100644
--- a/tests/manual/wip-cpp-compositor/window.cpp
+++ b/tests/manual/wip-cpp-compositor/window.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "window.h"
#include "compositor.h"
diff --git a/tests/manual/wip-cpp-compositor/window.h b/tests/manual/wip-cpp-compositor/window.h
index 5d49aa1ba..58ed1d5a0 100644
--- a/tests/manual/wip-cpp-compositor/window.h
+++ b/tests/manual/wip-cpp-compositor/window.h
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef WINDOW_H
#define WINDOW_H