Merge remote-tracking branch 'origin/dev' into wip/cmake
Change-Id: Ia76896a4d06240ccc3d95ba478b6ce273c7a0be2
This commit is contained in:
commit
b27b0ac173
@ -28,6 +28,7 @@
|
||||
<description summary="factory for creating dmabuf-based wl_buffers">
|
||||
Following the interfaces from:
|
||||
https://www.khronos.org/registry/egl/extensions/EXT/EGL_EXT_image_dma_buf_import.txt
|
||||
https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import_modifiers.txt
|
||||
and the Linux DRM sub-system's AddFb2 ioctl.
|
||||
|
||||
This interface offers ways to create generic dmabuf-based
|
||||
@ -129,8 +130,16 @@
|
||||
binds to this interface. A roundtrip after binding guarantees that
|
||||
the client has received all supported format-modifier pairs.
|
||||
|
||||
For legacy support, DRM_FORMAT_MOD_INVALID (that is, modifier_hi ==
|
||||
0x00ffffff and modifier_lo == 0xffffffff) is allowed in this event.
|
||||
It indicates that the server can support the format with an implicit
|
||||
modifier. When a plane has DRM_FORMAT_MOD_INVALID as its modifier, it
|
||||
is as if no explicit modifier is specified. The effective modifier
|
||||
will be derived from the dmabuf.
|
||||
|
||||
For the definition of the format and modifier codes, see the
|
||||
zwp_linux_buffer_params_v1::create request.
|
||||
zwp_linux_buffer_params_v1::create and zwp_linux_buffer_params_v1::add
|
||||
requests.
|
||||
</description>
|
||||
<arg name="format" type="uint" summary="DRM_FORMAT code"/>
|
||||
<arg name="modifier_hi" type="uint"
|
||||
@ -197,6 +206,11 @@
|
||||
compression, etc. driver-specific modifications to the base format
|
||||
defined by the DRM fourcc code.
|
||||
|
||||
Warning: It should be an error if the format/modifier pair was not
|
||||
advertised with the modifier event. This is not enforced yet because
|
||||
some implementations always accept DRM_FORMAT_MOD_INVALID. Also
|
||||
version 2 of this protocol does not have the modifier event.
|
||||
|
||||
This request raises the PLANE_IDX error if plane_idx is too large.
|
||||
The error PLANE_SET is raised if attempting to set a plane that
|
||||
was already set.
|
||||
|
@ -9,7 +9,7 @@
|
||||
"Description": "A Wayland shell for displaying a single surface per output",
|
||||
"Homepage": "https://wayland.freedesktop.org",
|
||||
"Version": "unstable v1",
|
||||
"DownloadLocation": "https://cgit.freedesktop.org/wayland/wayland-protocols",
|
||||
"DownloadLocation": "https://gitlab.freedesktop.org/wayland/wayland-protocols/raw/1.18/unstable/fullscreen-shell/fullscreen-shell-unstable-v1.xml",
|
||||
"LicenseId": "MIT",
|
||||
"License": "MIT License",
|
||||
"LicenseFile": "MIT_LICENSE.txt",
|
||||
@ -65,11 +65,11 @@ Copyright (c) 2013 BMW Car IT GmbH"
|
||||
"Description": "The primary selection extension allows copying text by selecting it and pasting it with the middle mouse button.",
|
||||
"Homepage": "https://wayland.freedesktop.org",
|
||||
"Version": "1",
|
||||
"DownloadLocation": "https://cgit.freedesktop.org/wayland/wayland-protocols/plain/unstable/primary-selection/primary-selection-unstable-v1.xml",
|
||||
"DownloadLocation": "https://gitlab.freedesktop.org/wayland/wayland-protocols/raw/1.18/unstable/primary-selection/primary-selection-unstable-v1.xml",
|
||||
"LicenseId": "MIT",
|
||||
"License": "MIT License",
|
||||
"LicenseFile": "MIT_LICENSE.txt",
|
||||
"Copyright": "Copyright © 2015 2016 Red Hat"
|
||||
"Copyright": "Copyright © 2015, 2016 Red Hat"
|
||||
},
|
||||
|
||||
{
|
||||
@ -82,13 +82,31 @@ Copyright (c) 2013 BMW Car IT GmbH"
|
||||
"Description": "The Wayland scaler extension allows a client to scale or crop a surface without modifying the buffer",
|
||||
"Homepage": "https://wayland.freedesktop.org",
|
||||
"Version": "2",
|
||||
"DownloadLocation": "https://cgit.freedesktop.org/wayland/weston/plain/protocol/scaler.xml?h=1.11.1",
|
||||
"DownloadLocation": "https://gitlab.freedesktop.org/wayland/weston/raw/1.11/protocol/scaler.xml",
|
||||
"LicenseId": "MIT",
|
||||
"License": "MIT License",
|
||||
"LicenseFile": "MIT_LICENSE.txt",
|
||||
"Copyright": "Copyright © 2013-2014 Collabora, Ltd."
|
||||
},
|
||||
|
||||
{
|
||||
"Id": "wayland-tablet-protocol",
|
||||
"Name": "Wayland Tablet Protocol",
|
||||
"QDocModule": "qtwaylandcompositor",
|
||||
"QtUsage": "Used in the Qt Wayland platform plugin",
|
||||
"Files": "tablet-unstable-v2.xml",
|
||||
|
||||
"Description": "",
|
||||
"Homepage": "https://wayland.freedesktop.org",
|
||||
"Version": "unstable v2, version 1",
|
||||
"DownloadLocation": "https://cgit.freedesktop.org/wayland/wayland-protocols/plain/unstable/tablet/tablet-unstable-v2.xml",
|
||||
"LicenseId": "MIT",
|
||||
"License": "MIT License",
|
||||
"LicenseFile": "MIT_LICENSE.txt",
|
||||
"Copyright": "Copyright 2014 © Stephen "Lyude" Chandler Paul
|
||||
Copyright 2015-2016 © Red Hat, Inc."
|
||||
},
|
||||
|
||||
{
|
||||
"Id": "wayland-viewporter-protocol",
|
||||
"Name": "Wayland Viewporter Protocol",
|
||||
@ -99,7 +117,7 @@ Copyright (c) 2013 BMW Car IT GmbH"
|
||||
"Description": "The Wayland viewporter extension allows a client to scale or crop a surface without modifying the buffer",
|
||||
"Homepage": "https://wayland.freedesktop.org",
|
||||
"Version": "1",
|
||||
"DownloadLocation": "https://cgit.freedesktop.org/wayland/wayland-protocols/plain/stable/viewporter/viewporter.xml",
|
||||
"DownloadLocation": "https://gitlab.freedesktop.org/wayland/wayland-protocols/raw/1.18/stable/viewporter/viewporter.xml",
|
||||
"LicenseId": "MIT",
|
||||
"License": "MIT License",
|
||||
"LicenseFile": "MIT_LICENSE.txt",
|
||||
@ -116,7 +134,7 @@ Copyright (c) 2013 BMW Car IT GmbH"
|
||||
"Description": "The xdg-decoration protocol allows a compositor to announce support for server-side decorations.",
|
||||
"Homepage": "https://wayland.freedesktop.org",
|
||||
"Version": "unstable v1, version 1",
|
||||
"DownloadLocation": "https://cgit.freedesktop.org/wayland/wayland-protocols/plain/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml?h=1.16",
|
||||
"DownloadLocation": "https://gitlab.freedesktop.org/wayland/wayland-protocols/raw/1.18/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml",
|
||||
"LicenseId": "MIT",
|
||||
"License": "MIT License",
|
||||
"LicenseFile": "MIT_LICENSE.txt",
|
||||
@ -132,8 +150,8 @@ Copyright (c) 2013 BMW Car IT GmbH"
|
||||
|
||||
"Description": "The XDG Output protocol is an extended way to describe output regions under Wayland",
|
||||
"Homepage": "https://wayland.freedesktop.org",
|
||||
"Version": "unstable v1, version 2",
|
||||
"DownloadLocation": "https://cgit.freedesktop.org/wayland/wayland-protocols/plain/unstable/xdg-output/xdg-output-unstable-v1.xml?h=1.16",
|
||||
"Version": "unstable v1, version 3",
|
||||
"DownloadLocation": "https://gitlab.freedesktop.org/wayland/wayland-protocols/raw/1.18/unstable/xdg-output/xdg-output-unstable-v1.xml",
|
||||
"LicenseId": "MIT",
|
||||
"License": "MIT License",
|
||||
"LicenseFile": "MIT_LICENSE.txt",
|
||||
@ -148,20 +166,23 @@ Copyright (c) 2013 BMW Car IT GmbH"
|
||||
"Files": " xdg-shell-unstable-v5.xml xdg-shell-unstable-v6.xml xdg-shell.xml ../../compositor/extensions/pregenerated/3rdparty/qwayland-server-xdg-shell-unstable-v5.cpp ../../compositor/extensions/pregenerated/3rdparty/qwayland-server-xdg-shell-unstable-v5_p.h ../../compositor/extensions/pregenerated/3rdparty/wayland-xdg-shell-unstable-v5-protocol.c ../../compositor/extensions/pregenerated/3rdparty/wayland-xdg-shell-unstable-v5-server-protocol_p.h ../../plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/qwayland-xdg-shell-unstable-v5.cpp ../../plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/qwayland-xdg-shell-unstable-v5_p.h ../../plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/wayland-xdg-shell-unstable-v5-client-protocol_p.h ../../plugins/shellintegration/xdg-shell-v5/pregenerated/3rdparty/wayland-xdg-shell-unstable-v5-protocol.c",
|
||||
|
||||
"Description": "The XDG-Shell protocol is an extended way to manage surfaces under Wayland compositors.",
|
||||
"Homepage": "https://wayland.freedesktop.org",
|
||||
"Version": "1.9.0",
|
||||
"DownloadLocation": "https://cgit.freedesktop.org/wayland/weston/tag/?id=1.9.0",
|
||||
"Homepage": "https://gitlab.freedesktop.org/wayland/wayland-protocols/",
|
||||
"Version": "1.18",
|
||||
"DownloadLocation": "https://gitlab.freedesktop.org/wayland/wayland-protocols/tree/1.18/",
|
||||
"LicenseId": "MIT",
|
||||
"License": "MIT License",
|
||||
"LicenseFile": "MIT_LICENSE.txt",
|
||||
"Copyright": "Copyright © 2008-2013 Kristian Høgsberg
|
||||
Copyright © 2013 Rafael Antognolli
|
||||
Copyright © 2013 Jasper St. Pierre
|
||||
Copyright © 2010-2013 Intel Corporation"
|
||||
Copyright © 2010-2013 Intel Corporation
|
||||
Copyright © 2015-2017 Samsung Electronics Co., Ltd
|
||||
Copyright © 2015-2017 Red Hat Inc.
|
||||
"
|
||||
},
|
||||
|
||||
{
|
||||
"Id": "wayland-txt-input-unstable",
|
||||
"Id": "wayland-text-input-unstable",
|
||||
"Name": "Wayland Text Input Protocol",
|
||||
"QDocModule": "qtwaylandcompositor",
|
||||
"QtUsage": "Used in the Qt Wayland Compositor, and the Qt Wayland platform plugin.",
|
||||
@ -169,6 +190,7 @@ Copyright © 2010-2013 Intel Corporation"
|
||||
|
||||
"Description": "Adds support for text input and input methods to applications.",
|
||||
"Homepage": "https://wayland.freedesktop.org",
|
||||
"Version": "unstable v2",
|
||||
"LicenseId": "HPND",
|
||||
"License": "HPND License",
|
||||
"LicenseFile": "HPND_LICENSE.txt",
|
||||
@ -185,6 +207,8 @@ Copyright © 2015, 2016 Jan Arne Petersen"
|
||||
|
||||
"Description": "The linux dmabuf protocol is a way to create dmabuf-based wl_buffers",
|
||||
"Homepage": "https://wayland.freedesktop.org",
|
||||
"Version": "unstable v1, version 3",
|
||||
"DownloadLocation": "https://gitlab.freedesktop.org/wayland/wayland-protocols/raw/1.18/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml",
|
||||
"LicenseId": "MIT",
|
||||
"License": "MIT License",
|
||||
"LicenseFile": "MIT_LICENSE.txt",
|
||||
@ -200,6 +224,8 @@ Copyright © 2015, 2016 Jan Arne Petersen"
|
||||
|
||||
"Description": "Allows clients to request that the compositor creates its EGLStream.",
|
||||
"Homepage": "https://github.com/NVIDIA/egl-wayland",
|
||||
"Version": "1.1.1",
|
||||
"DownloadLocation": "https://raw.githubusercontent.com/NVIDIA/egl-wayland/1.1.1/wayland-eglstream/wayland-eglstream-controller.xml",
|
||||
"LicenseId": "MIT",
|
||||
"License": "MIT License",
|
||||
"LicenseFile": "MIT_LICENSE.txt",
|
||||
|
1178
src/3rdparty/wayland/protocols/tablet-unstable-v2.xml
vendored
Normal file
1178
src/3rdparty/wayland/protocols/tablet-unstable-v2.xml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -54,7 +54,7 @@
|
||||
reset.
|
||||
</description>
|
||||
|
||||
<interface name="zxdg_output_manager_v1" version="2">
|
||||
<interface name="zxdg_output_manager_v1" version="3">
|
||||
<description summary="manage xdg_output objects">
|
||||
A global factory interface for xdg_output objects.
|
||||
</description>
|
||||
@ -77,12 +77,17 @@
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="zxdg_output_v1" version="2">
|
||||
<interface name="zxdg_output_v1" version="3">
|
||||
<description summary="compositor logical output region">
|
||||
An xdg_output describes part of the compositor geometry.
|
||||
|
||||
This typically corresponds to a monitor that displays part of the
|
||||
compositor space.
|
||||
|
||||
For objects version 3 onwards, after all xdg_output properties have been
|
||||
sent (when the object is created and when properties are updated), a
|
||||
wl_output.done event is sent. This allows changes to the output
|
||||
properties to be seen as atomic, even if they happen via multiple events.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
@ -157,6 +162,10 @@
|
||||
|
||||
This allows changes to the xdg_output properties to be seen as
|
||||
atomic, even if they happen via multiple events.
|
||||
|
||||
For objects version 3 onwards, this event is deprecated. Compositors
|
||||
are not required to send it anymore and must send wl_output.done
|
||||
instead.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
@ -197,10 +206,12 @@
|
||||
output via :1'.
|
||||
|
||||
The description event is sent after creating an xdg_output (see
|
||||
xdg_output_manager.get_xdg_output). This event is only sent once per
|
||||
xdg_output_manager.get_xdg_output) and whenever the description
|
||||
changes. The description is optional, and may not be sent at all.
|
||||
|
||||
For objects of version 2 and lower, this event is only sent once per
|
||||
xdg_output, and the description does not change over the lifetime of
|
||||
the wl_output global. The description is optional, and may not be sent
|
||||
at all.
|
||||
the wl_output global.
|
||||
</description>
|
||||
<arg name="description" type="string" summary="output description"/>
|
||||
</event>
|
||||
|
@ -118,7 +118,9 @@
|
||||
child surface relative to a parent surface. Rules can be defined to ensure
|
||||
the child surface remains within the visible area's borders, and to
|
||||
specify how the child surface changes its position, such as sliding along
|
||||
an axis, or flipping around a rectangle.
|
||||
an axis, or flipping around a rectangle. These positioner-created rules are
|
||||
constrained by the requirement that a child surface must intersect with or
|
||||
be at least partially adjacent to its parent surface.
|
||||
|
||||
See the various requests for details about possible rules.
|
||||
|
||||
@ -941,7 +943,8 @@
|
||||
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.
|
||||
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.
|
||||
|
91
src/3rdparty/wayland/protocols/xdg-shell.xml
vendored
91
src/3rdparty/wayland/protocols/xdg-shell.xml
vendored
@ -29,7 +29,7 @@
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<interface name="xdg_wm_base" version="1">
|
||||
<interface name="xdg_wm_base" version="2">
|
||||
<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
|
||||
@ -101,7 +101,7 @@
|
||||
<description summary="check if the client is alive">
|
||||
The ping event asks the client if it's still alive. Pass the
|
||||
serial specified in the event back to the compositor by sending
|
||||
a "pong" request back with the specified serial. See xdg_wm_base.ping.
|
||||
a "pong" request back with the specified serial. See xdg_wm_base.pong.
|
||||
|
||||
Compositors can use this to determine if the client is still
|
||||
alive. It's unspecified what will happen if the client doesn't
|
||||
@ -115,7 +115,7 @@
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="xdg_positioner" version="1">
|
||||
<interface name="xdg_positioner" version="2">
|
||||
<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
|
||||
@ -359,7 +359,7 @@
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="xdg_surface" version="1">
|
||||
<interface name="xdg_surface" version="2">
|
||||
<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.
|
||||
@ -528,7 +528,7 @@
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="xdg_toplevel" version="1">
|
||||
<interface name="xdg_toplevel" version="2">
|
||||
<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,
|
||||
@ -604,6 +604,9 @@
|
||||
For example, "org.freedesktop.FooViewer" where the .desktop file is
|
||||
"org.freedesktop.FooViewer.desktop".
|
||||
|
||||
Like other properties, a set_app_id request can be sent after the
|
||||
xdg_toplevel has been mapped to update the property.
|
||||
|
||||
See the desktop-entry specification [0] for more details on
|
||||
application identifiers and how they relate to well-known D-Bus
|
||||
names and .desktop files.
|
||||
@ -724,6 +727,9 @@
|
||||
<description summary="the surface is maximized">
|
||||
The surface is maximized. The window geometry specified in the configure
|
||||
event must be obeyed by the client.
|
||||
|
||||
The client should draw without shadow or other
|
||||
decoration outside of the window geometry.
|
||||
</description>
|
||||
</entry>
|
||||
<entry name="fullscreen" value="2" summary="the surface is fullscreen">
|
||||
@ -750,6 +756,30 @@
|
||||
keyboard or pointer focus.
|
||||
</description>
|
||||
</entry>
|
||||
<entry name="tiled_left" value="5" since="2">
|
||||
<description summary="the surface 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">
|
||||
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">
|
||||
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">
|
||||
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>
|
||||
</enum>
|
||||
|
||||
<request name="set_max_size">
|
||||
@ -839,12 +869,11 @@
|
||||
Maximize the surface.
|
||||
|
||||
After requesting that the surface should be maximized, the compositor
|
||||
will respond by emitting a configure event with the "maximized" state
|
||||
and the required window geometry. The client should then update its
|
||||
content, drawing it in a maximized state, i.e. without shadow or other
|
||||
decoration outside of the window geometry. The client must also
|
||||
acknowledge the configure when committing the new content (see
|
||||
ack_configure).
|
||||
will respond by emitting a configure event. Whether this configure
|
||||
actually sets the window maximized is subject to compositor policies.
|
||||
The client must then update its content, drawing in the configured
|
||||
state. The client must also acknowledge the configure when committing
|
||||
the new content (see ack_configure).
|
||||
|
||||
It is up to the compositor to decide how and where to maximize the
|
||||
surface, for example which output and what region of the screen should
|
||||
@ -854,8 +883,8 @@
|
||||
a configure event with the "maximized" state.
|
||||
|
||||
If the surface is in a fullscreen state, this request has no direct
|
||||
effect. It will alter the state the surface is returned to when
|
||||
unmaximized if not overridden by the compositor.
|
||||
effect. It may alter the state the surface is returned to when
|
||||
unmaximized unless overridden by the compositor.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
@ -864,13 +893,13 @@
|
||||
Unmaximize the surface.
|
||||
|
||||
After requesting that the surface should be unmaximized, the compositor
|
||||
will respond by emitting a configure event without the "maximized"
|
||||
state. If available, the compositor will include the window geometry
|
||||
dimensions the window had prior to being maximized in the configure
|
||||
event. The client must then update its content, drawing it in a
|
||||
regular state, i.e. potentially with shadow, etc. The client must also
|
||||
acknowledge the configure when committing the new content (see
|
||||
ack_configure).
|
||||
will respond by emitting a configure event. Whether this actually
|
||||
un-maximizes the window is subject to compositor policies.
|
||||
If available and applicable, the compositor will include the window
|
||||
geometry dimensions the window had prior to being maximized in the
|
||||
configure event. The client must then update its content, drawing it in
|
||||
the configured state. The client must also acknowledge the configure
|
||||
when committing the new content (see ack_configure).
|
||||
|
||||
It is up to the compositor to position the surface after it was
|
||||
unmaximized; usually the position the surface had before maximizing, if
|
||||
@ -880,8 +909,8 @@
|
||||
emit a configure event without the "maximized" state.
|
||||
|
||||
If the surface is in a fullscreen state, this request has no direct
|
||||
effect. It will alter the state the surface is returned to when
|
||||
unmaximized if not overridden by the compositor.
|
||||
effect. It may alter the state the surface is returned to when
|
||||
unmaximized unless overridden by the compositor.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
@ -890,10 +919,10 @@
|
||||
Make the surface fullscreen.
|
||||
|
||||
After requesting that the surface should be fullscreened, the
|
||||
compositor will respond by emitting a configure event with the
|
||||
"fullscreen" state and the fullscreen window geometry. The client must
|
||||
also acknowledge the configure when committing the new content (see
|
||||
ack_configure).
|
||||
compositor will respond by emitting a configure event. Whether the
|
||||
client is actually put into a fullscreen state is subject to compositor
|
||||
policies. The client must also acknowledge the configure when
|
||||
committing the new content (see ack_configure).
|
||||
|
||||
The output passed by the request indicates the client's preference as
|
||||
to which display it should be set fullscreen on. If this value is NULL,
|
||||
@ -919,8 +948,9 @@
|
||||
Make the surface no longer fullscreen.
|
||||
|
||||
After requesting that the surface should be unfullscreened, the
|
||||
compositor will respond by emitting a configure event without the
|
||||
"fullscreen" state.
|
||||
compositor will respond by emitting a configure event.
|
||||
Whether this actually removes the fullscreen state of the client is
|
||||
subject to compositor policies.
|
||||
|
||||
Making a surface unfullscreen sets states for the surface based on the following:
|
||||
* the state(s) it may have had before becoming fullscreen
|
||||
@ -989,7 +1019,7 @@
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="xdg_popup" version="1">
|
||||
<interface name="xdg_popup" version="2">
|
||||
<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
|
||||
@ -1007,9 +1037,6 @@
|
||||
surface of their own is clicked should dismiss the popup using the destroy
|
||||
request.
|
||||
|
||||
The parent surface must have either the xdg_toplevel or xdg_popup surface
|
||||
role.
|
||||
|
||||
A newly created xdg_popup will be stacked on top of all previously created
|
||||
xdg_popup surfaces associated with the same xdg_toplevel.
|
||||
|
||||
|
@ -23,8 +23,11 @@ qtConfig(xkbcommon) {
|
||||
QT_FOR_PRIVATE += xkbcommon_support-private
|
||||
}
|
||||
|
||||
qtHaveModule(linuxaccessibility_support_private): \
|
||||
QT_PRIVATE += linuxaccessibility_support_private
|
||||
qtHaveModule(platformcompositor_support-private): \
|
||||
QT_PRIVATE += platformcompositor_support-private
|
||||
|
||||
qtHaveModule(linuxaccessibility_support-private): \
|
||||
QT_PRIVATE += linuxaccessibility_support-private
|
||||
|
||||
QMAKE_USE += wayland-client
|
||||
|
||||
@ -36,6 +39,7 @@ WAYLANDCLIENTSOURCES += \
|
||||
../extensions/qt-key-unstable-v1.xml \
|
||||
../extensions/qt-windowmanager.xml \
|
||||
../3rdparty/protocol/wp-primary-selection-unstable-v1.xml \
|
||||
../3rdparty/protocol/tablet-unstable-v2.xml \
|
||||
../3rdparty/protocol/text-input-unstable-v2.xml \
|
||||
../3rdparty/protocol/xdg-output-unstable-v1.xml \
|
||||
../3rdparty/protocol/wayland.xml
|
||||
@ -52,6 +56,7 @@ SOURCES += qwaylandintegration.cpp \
|
||||
qwaylandextendedsurface.cpp \
|
||||
qwaylandsubsurface.cpp \
|
||||
qwaylandsurface.cpp \
|
||||
qwaylandtabletv2.cpp \
|
||||
qwaylandtouch.cpp \
|
||||
qwaylandqtkey.cpp \
|
||||
../shared/qwaylandmimehelper.cpp \
|
||||
@ -77,6 +82,7 @@ HEADERS += qwaylandintegration_p.h \
|
||||
qwaylandextendedsurface_p.h \
|
||||
qwaylandsubsurface_p.h \
|
||||
qwaylandsurface_p.h \
|
||||
qwaylandtabletv2_p.h \
|
||||
qwaylandtouch_p.h \
|
||||
qwaylandqtkey_p.h \
|
||||
qwaylandabstractdecoration_p.h \
|
||||
|
@ -134,12 +134,15 @@
|
||||
"#endif"
|
||||
]
|
||||
},
|
||||
"use": "egl"
|
||||
"use": "egl drm"
|
||||
},
|
||||
"vulkan-server-buffer": {
|
||||
"label": "Vulkan Buffer Sharing",
|
||||
"type": "compile",
|
||||
"test": {
|
||||
"head": [
|
||||
"#define VK_USE_PLATFORM_WAYLAND_KHR 1"
|
||||
],
|
||||
"include": [
|
||||
"vulkan/vulkan.h"
|
||||
],
|
||||
@ -150,6 +153,21 @@
|
||||
"return 0;"
|
||||
]
|
||||
}
|
||||
},
|
||||
"egl_1_5-wayland": {
|
||||
"label": "EGL 1.5 with Wayland Platform",
|
||||
"type": "compile",
|
||||
"test": {
|
||||
"include": [
|
||||
"EGL/egl.h",
|
||||
"EGL/eglext.h",
|
||||
"wayland-client.h"
|
||||
],
|
||||
"main": [
|
||||
"eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_EXT, (struct wl_display *)(nullptr), nullptr);"
|
||||
]
|
||||
},
|
||||
"use": "egl"
|
||||
}
|
||||
},
|
||||
|
||||
@ -200,7 +218,7 @@
|
||||
},
|
||||
"wayland-egl": {
|
||||
"label": "EGL",
|
||||
"condition": "features.wayland-client && features.opengl && features.egl && libs.wayland-egl",
|
||||
"condition": "features.wayland-client && features.opengl && features.egl && libs.wayland-egl && (!config.qnx || tests.egl_1_5-wayland)",
|
||||
"output": [ "privateFeature" ]
|
||||
},
|
||||
"wayland-brcm": {
|
||||
@ -220,7 +238,7 @@
|
||||
},
|
||||
"wayland-drm-egl-server-buffer": {
|
||||
"label": "DRM EGL",
|
||||
"condition": "features.wayland-client && features.opengl && features.egl && tests.drm-egl-server",
|
||||
"condition": "features.wayland-client && features.opengl && features.egl && tests.drm-egl-server && (!config.qnx || tests.egl_1_5-wayland)",
|
||||
"output": [ "privateFeature" ]
|
||||
},
|
||||
"wayland-libhybris-egl-server-buffer": {
|
||||
@ -235,7 +253,7 @@
|
||||
},
|
||||
"wayland-vulkan-server-buffer": {
|
||||
"label": "Vulkan-based server buffer integration",
|
||||
"condition": "features.wayland-client && features.opengl && features.egl && tests.vulkan-server-buffer",
|
||||
"condition": "features.wayland-client && features.vulkan && features.opengl && features.egl && tests.vulkan-server-buffer",
|
||||
"output": [ "privateFeature" ]
|
||||
},
|
||||
"wayland-shm-emulation-server-buffer": {
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QPalette>
|
||||
#include <QtGui/QLinearGradient>
|
||||
#include <QtGui/QPainterPath>
|
||||
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# We have a bunch of C code with casts, so we can't have this option
|
||||
QMAKE_CXXFLAGS_WARN_ON -= -Wcast-qual
|
||||
|
||||
QT += waylandclient-private
|
||||
QT += waylandclient-private opengl
|
||||
|
||||
include(../../../../hardwareintegration/client/dmabuf-server/dmabuf-server.pri)
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# We have a bunch of C code with casts, so we can't have this option
|
||||
QMAKE_CXXFLAGS_WARN_ON -= -Wcast-qual
|
||||
|
||||
QT += waylandclient-private
|
||||
QT += waylandclient-private opengl
|
||||
|
||||
include(../../../../hardwareintegration/client/drm-egl-server/drm-egl-server.pri)
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# We have a bunch of C code with casts, so we can't have this option
|
||||
QMAKE_CXXFLAGS_WARN_ON -= -Wcast-qual
|
||||
|
||||
QT += waylandclient-private
|
||||
QT += waylandclient-private opengl
|
||||
|
||||
include(../../../../hardwareintegration/client/shm-emulation-server/shm-emulation-server.pri)
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# We have a bunch of C code with casts, so we can't have this option
|
||||
QMAKE_CXXFLAGS_WARN_ON -= -Wcast-qual
|
||||
|
||||
QT += waylandclient-private
|
||||
QT += waylandclient-private opengl
|
||||
|
||||
include(../../../../hardwareintegration/client/vulkan-server/vulkan-server.pri)
|
||||
|
||||
|
@ -50,10 +50,11 @@ QWaylandFullScreenShellV1Surface::QWaylandFullScreenShellV1Surface(QtWayland::zw
|
||||
, m_shell(shell)
|
||||
, m_window(window)
|
||||
{
|
||||
auto screen = static_cast<QWaylandScreen *>(m_window->screen());
|
||||
auto *screen = m_window->waylandScreen();
|
||||
auto *output = screen ? screen->output() : nullptr;
|
||||
m_shell->present_surface(m_window->wlSurface(),
|
||||
QtWayland::zwp_fullscreen_shell_v1::present_method_default,
|
||||
screen->output());
|
||||
output);
|
||||
}
|
||||
|
||||
} // namespace QtWaylandClient
|
||||
|
@ -74,7 +74,7 @@ QWaylandCursorTheme::~QWaylandCursorTheme()
|
||||
|
||||
wl_cursor *QWaylandCursorTheme::requestCursor(WaylandCursor shape)
|
||||
{
|
||||
if (struct wl_cursor *cursor = m_cursors.value(shape, nullptr))
|
||||
if (struct wl_cursor *cursor = m_cursors[shape])
|
||||
return cursor;
|
||||
|
||||
static Q_CONSTEXPR struct ShapeAndName {
|
||||
@ -206,7 +206,7 @@ wl_cursor *QWaylandCursorTheme::requestCursor(WaylandCursor shape)
|
||||
ShapeAndName{shape, ""}, byShape);
|
||||
for (auto it = p.first; it != p.second; ++it) {
|
||||
if (wl_cursor *cursor = wl_cursor_theme_get_cursor(m_theme, it->name)) {
|
||||
m_cursors.insert(shape, cursor);
|
||||
m_cursors[shape] = cursor;
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
@ -219,7 +219,7 @@ wl_cursor *QWaylandCursorTheme::requestCursor(WaylandCursor shape)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
::wl_cursor_image *QWaylandCursorTheme::cursorImage(Qt::CursorShape shape, uint millisecondsIntoAnimation)
|
||||
::wl_cursor *QWaylandCursorTheme::cursor(Qt::CursorShape shape)
|
||||
{
|
||||
struct wl_cursor *waylandCursor = nullptr;
|
||||
|
||||
@ -237,15 +237,7 @@ wl_cursor *QWaylandCursorTheme::requestCursor(WaylandCursor shape)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int frame = wl_cursor_frame(waylandCursor, millisecondsIntoAnimation);
|
||||
::wl_cursor_image *image = waylandCursor->images[frame];
|
||||
::wl_buffer *buffer = wl_cursor_image_get_buffer(image);
|
||||
if (!buffer) {
|
||||
qCWarning(lcQpaWayland) << "Could not find buffer for cursor";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return image;
|
||||
return waylandCursor;
|
||||
}
|
||||
|
||||
QWaylandCursor::QWaylandCursor(QWaylandDisplay *display)
|
||||
|
@ -75,7 +75,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandCursorTheme
|
||||
public:
|
||||
static QWaylandCursorTheme *create(QWaylandShm *shm, int size, const QString &themeName);
|
||||
~QWaylandCursorTheme();
|
||||
::wl_cursor_image *cursorImage(Qt::CursorShape shape, uint millisecondsIntoAnimation = 0);
|
||||
::wl_cursor *cursor(Qt::CursorShape shape);
|
||||
|
||||
private:
|
||||
enum WaylandCursor {
|
||||
@ -109,13 +109,15 @@ private:
|
||||
ResizeNorthWestCursor,
|
||||
ResizeSouthEastCursor,
|
||||
ResizeNorthEastCursor,
|
||||
ResizeSouthWestCursor
|
||||
ResizeSouthWestCursor,
|
||||
|
||||
NumWaylandCursors
|
||||
};
|
||||
|
||||
explicit QWaylandCursorTheme(struct ::wl_cursor_theme *theme) : m_theme(theme) {}
|
||||
struct ::wl_cursor *requestCursor(WaylandCursor shape);
|
||||
struct ::wl_cursor_theme *m_theme = nullptr;
|
||||
QMap<WaylandCursor, wl_cursor *> m_cursors;
|
||||
wl_cursor *m_cursors[NumWaylandCursors] = {};
|
||||
};
|
||||
|
||||
class Q_WAYLAND_CLIENT_EXPORT QWaylandCursor : public QPlatformCursor
|
||||
@ -129,7 +131,6 @@ public:
|
||||
void setPos(const QPoint &pos) override;
|
||||
|
||||
static QSharedPointer<QWaylandBuffer> cursorBitmapBuffer(QWaylandDisplay *display, const QCursor *cursor);
|
||||
struct wl_cursor_image *cursorImage(Qt::CursorShape shape);
|
||||
|
||||
private:
|
||||
QWaylandDisplay *mDisplay = nullptr;
|
||||
|
@ -157,7 +157,9 @@ void QWaylandDataDevice::data_device_drop()
|
||||
return;
|
||||
}
|
||||
|
||||
QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(m_dragWindow, dragData, m_dragPoint, supportedActions);
|
||||
QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(m_dragWindow, dragData, m_dragPoint, supportedActions,
|
||||
QGuiApplication::mouseButtons(),
|
||||
QGuiApplication::keyboardModifiers());
|
||||
|
||||
if (drag) {
|
||||
static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag(response);
|
||||
@ -187,7 +189,9 @@ void QWaylandDataDevice::data_device_enter(uint32_t serial, wl_surface *surface,
|
||||
supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
|
||||
}
|
||||
|
||||
const QPlatformDragQtResponse &response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions);
|
||||
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);
|
||||
@ -203,7 +207,9 @@ void QWaylandDataDevice::data_device_enter(uint32_t serial, wl_surface *surface,
|
||||
void QWaylandDataDevice::data_device_leave()
|
||||
{
|
||||
if (m_dragWindow)
|
||||
QWindowSystemInterface::handleDrag(m_dragWindow, nullptr, QPoint(), Qt::IgnoreAction);
|
||||
QWindowSystemInterface::handleDrag(m_dragWindow, nullptr, QPoint(), Qt::IgnoreAction,
|
||||
QGuiApplication::mouseButtons(),
|
||||
QGuiApplication::keyboardModifiers());
|
||||
|
||||
QDrag *drag = static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->currentDrag();
|
||||
if (!drag) {
|
||||
@ -232,7 +238,9 @@ void QWaylandDataDevice::data_device_motion(uint32_t time, wl_fixed_t x, wl_fixe
|
||||
supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
|
||||
}
|
||||
|
||||
QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions);
|
||||
QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions,
|
||||
QGuiApplication::mouseButtons(),
|
||||
QGuiApplication::keyboardModifiers());
|
||||
|
||||
if (drag) {
|
||||
static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setResponse(response);
|
||||
|
@ -170,24 +170,27 @@ int QWaylandMimeData::readData(int fd, QByteArray &data) const
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
int ready = select(FD_SETSIZE, &readset, nullptr, nullptr, &timeout);
|
||||
if (ready < 0) {
|
||||
qWarning() << "QWaylandDataOffer: select() failed";
|
||||
return -1;
|
||||
} else if (ready == 0) {
|
||||
qWarning("QWaylandDataOffer: timeout reading from pipe");
|
||||
return -1;
|
||||
} else {
|
||||
char buf[4096];
|
||||
int n = QT_READ(fd, buf, sizeof buf);
|
||||
Q_FOREVER {
|
||||
int ready = select(FD_SETSIZE, &readset, nullptr, nullptr, &timeout);
|
||||
if (ready < 0) {
|
||||
qWarning() << "QWaylandDataOffer: select() failed";
|
||||
return -1;
|
||||
} else if (ready == 0) {
|
||||
qWarning("QWaylandDataOffer: timeout reading from pipe");
|
||||
return -1;
|
||||
} else {
|
||||
char buf[4096];
|
||||
int n = QT_READ(fd, buf, sizeof buf);
|
||||
|
||||
if (n > 0) {
|
||||
data.append(buf, n);
|
||||
n = readData(fd, data);
|
||||
} else if (n < 0) {
|
||||
qWarning("QWaylandDataOffer: read() failed");
|
||||
if (n < 0) {
|
||||
qWarning("QWaylandDataOffer: read() failed");
|
||||
return -1;
|
||||
} else if (n == 0) {
|
||||
return 0;
|
||||
} else if (n > 0) {
|
||||
data.append(buf, n);
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,7 @@
|
||||
#include "qwaylandextendedsurface_p.h"
|
||||
#include "qwaylandsubsurface_p.h"
|
||||
#include "qwaylandtouch_p.h"
|
||||
#include "qwaylandtabletv2_p.h"
|
||||
#include "qwaylandqtkey_p.h"
|
||||
|
||||
#include <QtWaylandClient/private/qwayland-text-input-unstable-v2.h>
|
||||
@ -114,6 +115,10 @@ struct ::wl_region *QWaylandDisplay::createRegion(const QRegion &qregion)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Make sure we don't pass NULL surfaces to libwayland (crashes)
|
||||
Q_ASSERT(parent->wlSurface());
|
||||
Q_ASSERT(window->wlSurface());
|
||||
|
||||
return mSubCompositor->get_subsurface(window->wlSurface(), parent->wlSurface());
|
||||
}
|
||||
|
||||
@ -184,6 +189,18 @@ QWaylandDisplay::~QWaylandDisplay(void)
|
||||
wl_display_disconnect(mDisplay);
|
||||
}
|
||||
|
||||
void QWaylandDisplay::ensureScreen()
|
||||
{
|
||||
if (!mScreens.empty() || mPlaceholderScreen)
|
||||
return; // There are real screens or we already have a fake one
|
||||
|
||||
qCInfo(lcQpaWayland) << "Creating a fake screen in order for Qt not to crash";
|
||||
|
||||
mPlaceholderScreen = new QPlatformPlaceholderScreen();
|
||||
QWindowSystemInterface::handleScreenAdded(mPlaceholderScreen);
|
||||
Q_ASSERT(!QGuiApplication::screens().empty());
|
||||
}
|
||||
|
||||
void QWaylandDisplay::checkError() const
|
||||
{
|
||||
int ecode = wl_display_get_error(mDisplay);
|
||||
@ -249,8 +266,7 @@ void QWaylandDisplay::dispatchQueueWhile(wl_event_queue *queue, std::function<bo
|
||||
|
||||
QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const
|
||||
{
|
||||
for (int i = 0; i < mScreens.size(); ++i) {
|
||||
QWaylandScreen *screen = static_cast<QWaylandScreen *>(mScreens.at(i));
|
||||
for (auto screen : qAsConst(mScreens)) {
|
||||
if (screen->output() == output)
|
||||
return screen;
|
||||
}
|
||||
@ -263,6 +279,11 @@ void QWaylandDisplay::handleScreenInitialized(QWaylandScreen *screen)
|
||||
return;
|
||||
mScreens.append(screen);
|
||||
QWindowSystemInterface::handleScreenAdded(screen);
|
||||
if (mPlaceholderScreen) {
|
||||
QWindowSystemInterface::handleScreenRemoved(mPlaceholderScreen);
|
||||
// handleScreenRemoved deletes the platform screen
|
||||
mPlaceholderScreen = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void QWaylandDisplay::waitForScreens()
|
||||
@ -310,6 +331,8 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
|
||||
mTouchExtension.reset(new QWaylandTouchExtension(this, id));
|
||||
} else if (interface == QStringLiteral("zqt_key_v1")) {
|
||||
mQtKeyExtension.reset(new QWaylandQtKeyExtension(this, id));
|
||||
} else if (interface == QStringLiteral("zwp_tablet_manager_v2")) {
|
||||
mTabletManager.reset(new QWaylandTabletManagerV2(this, id, qMin(1, int(version))));
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
} else if (interface == QStringLiteral("zwp_primary_selection_device_manager_v1")) {
|
||||
mPrimarySelectionManager.reset(new QWaylandPrimarySelectionDeviceManagerV1(this, id, 1));
|
||||
@ -328,7 +351,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
|
||||
forceRoundTrip();
|
||||
}
|
||||
} else if (interface == QLatin1String("zxdg_output_manager_v1")) {
|
||||
mXdgOutputManager.reset(new QtWayland::zxdg_output_manager_v1(registry, id, qMin(2, int(version))));
|
||||
mXdgOutputManager.reset(new QWaylandXdgOutputManagerV1(this, id, version));
|
||||
for (auto *screen : qAsConst(mWaitingScreens))
|
||||
screen->initXdgOutput(xdgOutputManager());
|
||||
forceRoundTrip();
|
||||
@ -358,6 +381,8 @@ void QWaylandDisplay::registry_global_remove(uint32_t id)
|
||||
for (QWaylandScreen *screen : qAsConst(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.
|
||||
ensureScreen();
|
||||
QWindowSystemInterface::handleScreenRemoved(screen);
|
||||
break;
|
||||
}
|
||||
|
@ -76,11 +76,11 @@ QT_BEGIN_NAMESPACE
|
||||
class QAbstractEventDispatcher;
|
||||
class QSocketNotifier;
|
||||
class QPlatformScreen;
|
||||
class QPlatformPlaceholderScreen;
|
||||
|
||||
namespace QtWayland {
|
||||
class qt_surface_extension;
|
||||
class zwp_text_input_manager_v2;
|
||||
class zxdg_output_manager_v1;
|
||||
}
|
||||
|
||||
namespace QtWaylandClient {
|
||||
@ -90,12 +90,14 @@ Q_WAYLAND_CLIENT_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcQpaWayland);
|
||||
class QWaylandInputDevice;
|
||||
class QWaylandBuffer;
|
||||
class QWaylandScreen;
|
||||
class QWaylandXdgOutputManagerV1;
|
||||
class QWaylandClientBufferIntegration;
|
||||
class QWaylandWindowManagerIntegration;
|
||||
class QWaylandDataDeviceManager;
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
class QWaylandPrimarySelectionDeviceManagerV1;
|
||||
#endif
|
||||
class QWaylandTabletManagerV2;
|
||||
class QWaylandTouchExtension;
|
||||
class QWaylandQtKeyExtension;
|
||||
class QWaylandWindow;
|
||||
@ -124,6 +126,8 @@ public:
|
||||
#endif
|
||||
|
||||
QList<QWaylandScreen *> screens() const { return mScreens; }
|
||||
QPlatformPlaceholderScreen *placeholderScreen() const { return mPlaceholderScreen; }
|
||||
void ensureScreen();
|
||||
|
||||
QWaylandScreen *screenForOutput(struct wl_output *output) const;
|
||||
void handleScreenInitialized(QWaylandScreen *screen);
|
||||
@ -157,10 +161,11 @@ public:
|
||||
QWaylandPrimarySelectionDeviceManagerV1 *primarySelectionManager() const { return mPrimarySelectionManager.data(); }
|
||||
#endif
|
||||
QtWayland::qt_surface_extension *windowExtension() const { return mWindowExtension.data(); }
|
||||
QWaylandTabletManagerV2 *tabletManager() const { return mTabletManager.data(); }
|
||||
QWaylandTouchExtension *touchExtension() const { return mTouchExtension.data(); }
|
||||
QtWayland::zwp_text_input_manager_v2 *textInputManager() const { return mTextInputManager.data(); }
|
||||
QWaylandHardwareIntegration *hardwareIntegration() const { return mHardwareIntegration.data(); }
|
||||
QtWayland::zxdg_output_manager_v1 *xdgOutputManager() const { return mXdgOutputManager.data(); }
|
||||
QWaylandXdgOutputManagerV1 *xdgOutputManager() const { return mXdgOutputManager.data(); }
|
||||
|
||||
bool usingInputContextFromCompositor() const { return mUsingInputContextFromCompositor; }
|
||||
|
||||
@ -228,6 +233,7 @@ private:
|
||||
QScopedPointer<QWaylandShm> mShm;
|
||||
QList<QWaylandScreen *> mWaitingScreens;
|
||||
QList<QWaylandScreen *> mScreens;
|
||||
QPlatformPlaceholderScreen *mPlaceholderScreen = nullptr;
|
||||
QList<QWaylandInputDevice *> mInputDevices;
|
||||
QList<Listener> mRegistryListeners;
|
||||
QWaylandIntegration *mWaylandIntegration = nullptr;
|
||||
@ -243,12 +249,13 @@ private:
|
||||
QScopedPointer<QWaylandTouchExtension> mTouchExtension;
|
||||
QScopedPointer<QWaylandQtKeyExtension> mQtKeyExtension;
|
||||
QScopedPointer<QWaylandWindowManagerIntegration> mWindowManagerIntegration;
|
||||
QScopedPointer<QWaylandTabletManagerV2> mTabletManager;
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
QScopedPointer<QWaylandPrimarySelectionDeviceManagerV1> mPrimarySelectionManager;
|
||||
#endif
|
||||
QScopedPointer<QtWayland::zwp_text_input_manager_v2> mTextInputManager;
|
||||
QScopedPointer<QWaylandHardwareIntegration> mHardwareIntegration;
|
||||
QScopedPointer<QtWayland::zxdg_output_manager_v1> mXdgOutputManager;
|
||||
QScopedPointer<QWaylandXdgOutputManagerV1> mXdgOutputManager;
|
||||
QSocketNotifier *mReadNotifier = nullptr;
|
||||
int mFd = -1;
|
||||
int mWritableNotificationFd = -1;
|
||||
|
@ -50,6 +50,7 @@
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
#include "qwaylandprimaryselectionv1_p.h"
|
||||
#endif
|
||||
#include "qwaylandtabletv2_p.h"
|
||||
#include "qwaylandtouch_p.h"
|
||||
#include "qwaylandscreen_p.h"
|
||||
#include "qwaylandcursor_p.h"
|
||||
@ -72,6 +73,7 @@
|
||||
#endif
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QTouchDevice>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -88,7 +90,7 @@ QWaylandInputDevice::Keyboard::Keyboard(QWaylandInputDevice *p)
|
||||
// or the server didn't send an enter event first.
|
||||
return;
|
||||
}
|
||||
mRepeatTimer.setInterval(mRepeatRate);
|
||||
mRepeatTimer.setInterval(1000 / mRepeatRate);
|
||||
handleKey(mRepeatKey.time, QEvent::KeyRelease, mRepeatKey.key, mRepeatKey.modifiers,
|
||||
mRepeatKey.code, mRepeatKey.nativeVirtualKey, mRepeatKey.nativeModifiers,
|
||||
mRepeatKey.text, true);
|
||||
@ -143,6 +145,12 @@ QWaylandWindow *QWaylandInputDevice::Keyboard::focusWindow() const
|
||||
QWaylandInputDevice::Pointer::Pointer(QWaylandInputDevice *seat)
|
||||
: mParent(seat)
|
||||
{
|
||||
#if QT_CONFIG(cursor)
|
||||
mCursor.frameTimer.setSingleShot(true);
|
||||
mCursor.frameTimer.callOnTimeout([&]() {
|
||||
cursorTimerCallback();
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
QWaylandInputDevice::Pointer::~Pointer()
|
||||
@ -224,7 +232,7 @@ public:
|
||||
if (animated) {
|
||||
m_frameCallback.reset(new WlCallback(frame(), [this](uint32_t time){
|
||||
Q_UNUSED(time);
|
||||
m_pointer->updateCursor();
|
||||
m_pointer->cursorFrameCallback();
|
||||
}));
|
||||
}
|
||||
commit();
|
||||
@ -283,8 +291,8 @@ void QWaylandInputDevice::Pointer::updateCursorTheme()
|
||||
if (!mCursor.theme)
|
||||
return; // A warning has already been printed in loadCursorTheme
|
||||
|
||||
if (auto *arrow = mCursor.theme->cursorImage(Qt::ArrowCursor)) {
|
||||
int arrowPixelSize = qMax(arrow->width, arrow->height); // Not all cursor themes are square
|
||||
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())
|
||||
--scale;
|
||||
} else {
|
||||
@ -326,12 +334,26 @@ void QWaylandInputDevice::Pointer::updateCursor()
|
||||
|
||||
// Set from shape using theme
|
||||
uint time = seat()->mCursor.animationTimer.elapsed();
|
||||
if (struct ::wl_cursor_image *image = mCursor.theme->cursorImage(shape, time)) {
|
||||
|
||||
if (struct ::wl_cursor *waylandCursor = mCursor.theme->cursor(shape)) {
|
||||
uint duration = 0;
|
||||
int frame = wl_cursor_frame_and_duration(waylandCursor, time, &duration);
|
||||
::wl_cursor_image *image = waylandCursor->images[frame];
|
||||
|
||||
struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
|
||||
if (!buffer) {
|
||||
qCWarning(lcQpaWayland) << "Could not find buffer for cursor" << shape;
|
||||
return;
|
||||
}
|
||||
int bufferScale = mCursor.themeBufferScale;
|
||||
QPoint hotspot = QPoint(image->hotspot_x, image->hotspot_y) / bufferScale;
|
||||
QSize size = QSize(image->width, image->height) / bufferScale;
|
||||
bool animated = image->delay > 0;
|
||||
bool animated = duration > 0;
|
||||
if (animated) {
|
||||
mCursor.gotFrameCallback = false;
|
||||
mCursor.gotTimerCallback = false;
|
||||
mCursor.frameTimer.start(duration);
|
||||
}
|
||||
getOrCreateCursorSurface()->update(buffer, hotspot, size, bufferScale, animated);
|
||||
return;
|
||||
}
|
||||
@ -346,6 +368,22 @@ CursorSurface *QWaylandInputDevice::Pointer::getOrCreateCursorSurface()
|
||||
return mCursor.surface.get();
|
||||
}
|
||||
|
||||
void QWaylandInputDevice::Pointer::cursorTimerCallback()
|
||||
{
|
||||
mCursor.gotTimerCallback = true;
|
||||
if (mCursor.gotFrameCallback) {
|
||||
updateCursor();
|
||||
}
|
||||
}
|
||||
|
||||
void QWaylandInputDevice::Pointer::cursorFrameCallback()
|
||||
{
|
||||
mCursor.gotFrameCallback = true;
|
||||
if (mCursor.gotTimerCallback) {
|
||||
updateCursor();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // QT_CONFIG(cursor)
|
||||
|
||||
QWaylandInputDevice::Touch::Touch(QWaylandInputDevice *p)
|
||||
@ -382,6 +420,8 @@ QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version,
|
||||
if (mQDisplay->textInputManager())
|
||||
mTextInput.reset(new QWaylandTextInput(mQDisplay, mQDisplay->textInputManager()->get_text_input(wl_seat())));
|
||||
|
||||
if (auto *tm = mQDisplay->tabletManager())
|
||||
mTabletSeat.reset(new QWaylandTabletSeatV2(tm, this));
|
||||
}
|
||||
|
||||
QWaylandInputDevice::~QWaylandInputDevice()
|
||||
@ -594,8 +634,8 @@ class EnterEvent : public QWaylandPointerEvent
|
||||
{
|
||||
public:
|
||||
EnterEvent(QWaylandWindow *surface, const QPointF &local, const QPointF &global)
|
||||
: QWaylandPointerEvent(QWaylandPointerEvent::Enter, Qt::NoScrollPhase, surface, 0,
|
||||
local, global, nullptr, Qt::NoModifier)
|
||||
: QWaylandPointerEvent(QEvent::Enter, Qt::NoScrollPhase, surface, 0,
|
||||
local, global, Qt::NoButton, Qt::NoButton, Qt::NoModifier)
|
||||
{}
|
||||
};
|
||||
|
||||
@ -639,8 +679,8 @@ class LeaveEvent : public QWaylandPointerEvent
|
||||
{
|
||||
public:
|
||||
LeaveEvent(QWaylandWindow *surface, const QPointF &localPos, const QPointF &globalPos)
|
||||
: QWaylandPointerEvent(QWaylandPointerEvent::Leave, Qt::NoScrollPhase, surface, 0,
|
||||
localPos, globalPos, nullptr, Qt::NoModifier)
|
||||
: QWaylandPointerEvent(QEvent::Leave, Qt::NoScrollPhase, surface, 0,
|
||||
localPos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier)
|
||||
{}
|
||||
};
|
||||
|
||||
@ -669,8 +709,8 @@ class MotionEvent : public QWaylandPointerEvent
|
||||
public:
|
||||
MotionEvent(QWaylandWindow *surface, ulong timestamp, const QPointF &localPos,
|
||||
const QPointF &globalPos, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
|
||||
: QWaylandPointerEvent(QWaylandPointerEvent::Motion, Qt::NoScrollPhase, surface,
|
||||
timestamp, localPos, globalPos, buttons, modifiers)
|
||||
: QWaylandPointerEvent(QEvent::MouseMove, Qt::NoScrollPhase, surface,
|
||||
timestamp, localPos, globalPos, buttons, Qt::NoButton, modifiers)
|
||||
{
|
||||
}
|
||||
};
|
||||
@ -708,9 +748,10 @@ class PressEvent : public QWaylandPointerEvent
|
||||
{
|
||||
public:
|
||||
PressEvent(QWaylandWindow *surface, ulong timestamp, const QPointF &localPos,
|
||||
const QPointF &globalPos, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
|
||||
: QWaylandPointerEvent(QWaylandPointerEvent::Press, Qt::NoScrollPhase, surface,
|
||||
timestamp, localPos, globalPos, buttons, modifiers)
|
||||
const QPointF &globalPos, Qt::MouseButtons buttons, Qt::MouseButton button,
|
||||
Qt::KeyboardModifiers modifiers)
|
||||
: QWaylandPointerEvent(QEvent::MouseButtonPress, Qt::NoScrollPhase, surface,
|
||||
timestamp, localPos, globalPos, buttons, button, modifiers)
|
||||
{
|
||||
}
|
||||
};
|
||||
@ -719,9 +760,10 @@ class ReleaseEvent : public QWaylandPointerEvent
|
||||
{
|
||||
public:
|
||||
ReleaseEvent(QWaylandWindow *surface, ulong timestamp, const QPointF &localPos,
|
||||
const QPointF &globalPos, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
|
||||
: QWaylandPointerEvent(QWaylandPointerEvent::Release, Qt::NoScrollPhase, surface,
|
||||
timestamp, localPos, globalPos, buttons, modifiers)
|
||||
const QPointF &globalPos, Qt::MouseButtons buttons, Qt::MouseButton button,
|
||||
Qt::KeyboardModifiers modifiers)
|
||||
: QWaylandPointerEvent(QEvent::MouseButtonRelease, Qt::NoScrollPhase, surface,
|
||||
timestamp, localPos, globalPos, buttons, button, modifiers)
|
||||
{
|
||||
}
|
||||
};
|
||||
@ -782,9 +824,9 @@ void QWaylandInputDevice::Pointer::pointer_button(uint32_t serial, uint32_t time
|
||||
}
|
||||
|
||||
if (state)
|
||||
setFrameEvent(new PressEvent(window, time, pos, global, mButtons, mParent->modifiers()));
|
||||
setFrameEvent(new PressEvent(window, time, pos, global, mButtons, qt_button, mParent->modifiers()));
|
||||
else
|
||||
setFrameEvent(new ReleaseEvent(window, time, pos, global, mButtons, mParent->modifiers()));
|
||||
setFrameEvent(new ReleaseEvent(window, time, pos, global, mButtons, qt_button, mParent->modifiers()));
|
||||
}
|
||||
|
||||
void QWaylandInputDevice::Pointer::invalidateFocus()
|
||||
@ -812,7 +854,7 @@ 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)
|
||||
: QWaylandPointerEvent(QWaylandPointerEvent::Wheel, phase, surface, timestamp,
|
||||
: QWaylandPointerEvent(QEvent::Wheel, phase, surface, timestamp,
|
||||
local, global, pixelDelta, angleDelta, source, modifiers)
|
||||
{
|
||||
}
|
||||
@ -968,6 +1010,8 @@ bool QWaylandInputDevice::Pointer::FrameData::hasPixelDelta() const
|
||||
case axis_source_finger:
|
||||
case axis_source_continuous:
|
||||
return !delta.isNull();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1048,11 +1092,13 @@ void QWaylandInputDevice::Pointer::flushFrameEvent()
|
||||
if (auto *event = mFrameData.event) {
|
||||
if (auto window = event->surface) {
|
||||
window->handleMouse(mParent, *event);
|
||||
} else if (mFrameData.event->type == QWaylandPointerEvent::Type::Release) {
|
||||
} else if (mFrameData.event->type == QEvent::MouseButtonRelease) {
|
||||
// If the window has been destroyed, we still need to report an up event, but it can't
|
||||
// be handled by the destroyed window (obviously), so send the event here instead.
|
||||
QWindowSystemInterface::handleMouseEvent(nullptr, event->timestamp, event->local,
|
||||
event->global, event->buttons, event->modifiers);
|
||||
event->global, event->buttons,
|
||||
event->button, event->type,
|
||||
event->modifiers);// , Qt::MouseEventSource source = Qt::MouseEventNotSynthesized);
|
||||
}
|
||||
delete mFrameData.event;
|
||||
mFrameData.event = nullptr;
|
||||
@ -1351,7 +1397,7 @@ void QWaylandInputDevice::Touch::touch_cancel()
|
||||
void QWaylandInputDevice::handleTouchPoint(int id, Qt::TouchPointState state, const QPointF &surfacePosition)
|
||||
{
|
||||
auto end = mTouch->mPendingTouchPoints.end();
|
||||
auto it = std::find_if(mTouch->mPendingTouchPoints.begin(), end, [id](auto tp){ return tp.id == id; });
|
||||
auto it = std::find_if(mTouch->mPendingTouchPoints.begin(), end, [id](const QWindowSystemInterface::TouchPoint &tp){ return tp.id == id; });
|
||||
if (it == end) {
|
||||
it = mTouch->mPendingTouchPoints.insert(end, QWindowSystemInterface::TouchPoint());
|
||||
it->id = id;
|
||||
@ -1372,8 +1418,7 @@ void QWaylandInputDevice::handleTouchPoint(int id, Qt::TouchPointState state, co
|
||||
return;
|
||||
|
||||
tp.area = QRectF(0, 0, 8, 8);
|
||||
QMargins margins = win->frameMargins();
|
||||
QPointF localPosition = surfacePosition - QPointF(margins.left(), margins.top());
|
||||
QPointF localPosition = win->mapFromWlSurface(surfacePosition);
|
||||
// TODO: This doesn't account for high dpi scaling for the delta, but at least it matches
|
||||
// what we have for mouse input.
|
||||
QPointF delta = localPosition - localPosition.toPoint();
|
||||
@ -1381,7 +1426,10 @@ void QWaylandInputDevice::handleTouchPoint(int id, Qt::TouchPointState state, co
|
||||
tp.area.moveCenter(globalPosition);
|
||||
}
|
||||
|
||||
tp.state = state;
|
||||
// If the touch point was pressed earlier this frame, we don't want to overwrite its state.
|
||||
if (tp.state != Qt::TouchPointPressed)
|
||||
tp.state = state;
|
||||
|
||||
tp.pressure = tp.state == Qt::TouchPointReleased ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@ -89,6 +89,7 @@ class QWaylandDisplay;
|
||||
#if QT_CONFIG(wayland_client_primary_selection)
|
||||
class QWaylandPrimarySelectionDeviceV1;
|
||||
#endif
|
||||
class QWaylandTabletSeatV2;
|
||||
class QWaylandTextInput;
|
||||
#if QT_CONFIG(cursor)
|
||||
class QWaylandCursorTheme;
|
||||
@ -127,6 +128,9 @@ public:
|
||||
QWaylandPrimarySelectionDeviceV1 *primarySelectionDevice() const;
|
||||
#endif
|
||||
|
||||
void setTabletSeat(QWaylandTabletSeatV2 *tabletSeat);
|
||||
QWaylandTabletSeatV2* tabletSeat() const;
|
||||
|
||||
void setTextInput(QWaylandTextInput *textInput);
|
||||
QWaylandTextInput *textInput() const;
|
||||
|
||||
@ -183,6 +187,7 @@ private:
|
||||
Touch *mTouch = nullptr;
|
||||
|
||||
QScopedPointer<QWaylandTextInput> mTextInput;
|
||||
QScopedPointer<QWaylandTabletSeatV2> mTabletSeat;
|
||||
|
||||
uint32_t mTime = 0;
|
||||
uint32_t mSerial = 0;
|
||||
@ -286,6 +291,8 @@ public:
|
||||
int idealCursorScale() const;
|
||||
void updateCursorTheme();
|
||||
void updateCursor();
|
||||
void cursorTimerCallback();
|
||||
void cursorFrameCallback();
|
||||
CursorSurface *getOrCreateCursorSurface();
|
||||
#endif
|
||||
QWaylandInputDevice *seat() const { return mParent; }
|
||||
@ -325,6 +332,9 @@ public:
|
||||
QWaylandCursorTheme *theme = nullptr;
|
||||
int themeBufferScale = 0;
|
||||
QScopedPointer<CursorSurface> surface;
|
||||
QTimer frameTimer;
|
||||
bool gotFrameCallback = false;
|
||||
bool gotTimerCallback = false;
|
||||
} mCursor;
|
||||
#endif
|
||||
QPointF mSurfacePos;
|
||||
@ -396,29 +406,21 @@ class QWaylandPointerEvent
|
||||
{
|
||||
Q_GADGET
|
||||
public:
|
||||
enum Type {
|
||||
Enter,
|
||||
Leave,
|
||||
Motion,
|
||||
Press,
|
||||
Release,
|
||||
Wheel
|
||||
};
|
||||
Q_ENUM(Type)
|
||||
|
||||
inline QWaylandPointerEvent(Type type, Qt::ScrollPhase phase, QWaylandWindow *surface,
|
||||
inline QWaylandPointerEvent(QEvent::Type type, Qt::ScrollPhase phase, QWaylandWindow *surface,
|
||||
ulong timestamp, const QPointF &localPos, const QPointF &globalPos,
|
||||
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
|
||||
Qt::MouseButtons buttons, Qt::MouseButton button,
|
||||
Qt::KeyboardModifiers modifiers)
|
||||
: type(type)
|
||||
, phase(phase)
|
||||
, timestamp(timestamp)
|
||||
, local(localPos)
|
||||
, global(globalPos)
|
||||
, buttons(buttons)
|
||||
, button(button)
|
||||
, modifiers(modifiers)
|
||||
, surface(surface)
|
||||
{}
|
||||
inline QWaylandPointerEvent(Type type, Qt::ScrollPhase phase, QWaylandWindow *surface,
|
||||
inline QWaylandPointerEvent(QEvent::Type type, Qt::ScrollPhase phase, QWaylandWindow *surface,
|
||||
ulong timestamp, const QPointF &local, const QPointF &global,
|
||||
const QPoint &pixelDelta, const QPoint &angleDelta,
|
||||
Qt::MouseEventSource source,
|
||||
@ -435,12 +437,13 @@ public:
|
||||
, surface(surface)
|
||||
{}
|
||||
|
||||
Type type;
|
||||
QEvent::Type type = QEvent::None;
|
||||
Qt::ScrollPhase phase = Qt::NoScrollPhase;
|
||||
ulong timestamp = 0;
|
||||
QPointF local;
|
||||
QPointF global;
|
||||
Qt::MouseButtons buttons;
|
||||
Qt::MouseButton button = Qt::NoButton; // Button that caused the event (QMouseEvent::button)
|
||||
Qt::KeyboardModifiers modifiers;
|
||||
QPoint pixelDelta;
|
||||
QPoint angleDelta;
|
||||
|
@ -66,7 +66,10 @@
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
#include <qpa/qplatformcursor.h>
|
||||
#include <QtGui/QSurfaceFormat>
|
||||
#if QT_CONFIG(opengl)
|
||||
#include <QtGui/QOpenGLContext>
|
||||
#include <QtPlatformCompositorSupport/qpa/qplatformbackingstoreopenglsupport.h>
|
||||
#endif // QT_CONFIG(opengl)
|
||||
#include <QSocketNotifier>
|
||||
|
||||
#include <qpa/qplatforminputcontextfactory_p.h>
|
||||
@ -165,10 +168,10 @@ QPlatformWindow *QWaylandIntegration::createPlatformWindow(QWindow *window) cons
|
||||
|
||||
#if QT_CONFIG(vulkan)
|
||||
if (window->surfaceType() == QSurface::VulkanSurface)
|
||||
return new QWaylandVulkanWindow(window);
|
||||
return new QWaylandVulkanWindow(window, mDisplay.data());
|
||||
#endif // QT_CONFIG(vulkan)
|
||||
|
||||
return new QWaylandShmWindow(window);
|
||||
return new QWaylandShmWindow(window, mDisplay.data());
|
||||
}
|
||||
|
||||
#if QT_CONFIG(opengl)
|
||||
@ -182,7 +185,11 @@ QPlatformOpenGLContext *QWaylandIntegration::createPlatformOpenGLContext(QOpenGL
|
||||
|
||||
QPlatformBackingStore *QWaylandIntegration::createPlatformBackingStore(QWindow *window) const
|
||||
{
|
||||
return new QWaylandShmBackingStore(window);
|
||||
auto *backingStore = new QWaylandShmBackingStore(window, mDisplay.data());
|
||||
#if QT_CONFIG(opengl)
|
||||
backingStore->setOpenGLSupport(new QPlatformBackingStoreOpenGLSupport(backingStore));
|
||||
#endif
|
||||
return backingStore;
|
||||
}
|
||||
|
||||
QAbstractEventDispatcher *QWaylandIntegration::createEventDispatcher() const
|
||||
@ -200,10 +207,8 @@ void QWaylandIntegration::initialize()
|
||||
QSocketNotifier *sn = new QSocketNotifier(fd, QSocketNotifier::Read, mDisplay.data());
|
||||
QObject::connect(sn, SIGNAL(activated(int)), mDisplay.data(), SLOT(flushRequests()));
|
||||
|
||||
if (mDisplay->screens().isEmpty()) {
|
||||
qWarning() << "Running on a compositor with no screens is not supported";
|
||||
::exit(EXIT_FAILURE);
|
||||
}
|
||||
// Qt does not support running with no screens
|
||||
mDisplay->ensureScreen();
|
||||
}
|
||||
|
||||
QPlatformFontDatabase *QWaylandIntegration::fontDatabase() const
|
||||
@ -427,6 +432,8 @@ void QWaylandIntegration::initializeShellIntegration()
|
||||
qCWarning(lcQpaWayland) << "Loading shell integration failed.";
|
||||
qCWarning(lcQpaWayland) << "Attempted to load the following shells" << preferredShells;
|
||||
}
|
||||
|
||||
QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
|
||||
}
|
||||
|
||||
QWaylandInputDevice *QWaylandIntegration::createInputDevice(QWaylandDisplay *display, int version, uint32_t id)
|
||||
|
@ -53,6 +53,12 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtWaylandClient {
|
||||
|
||||
QWaylandXdgOutputManagerV1::QWaylandXdgOutputManagerV1(QWaylandDisplay* display, uint id, uint version)
|
||||
: QtWayland::zxdg_output_manager_v1(display->wl_registry(), id, qMin(3u, version))
|
||||
, m_version(qMin(3u, version))
|
||||
{
|
||||
}
|
||||
|
||||
QWaylandScreen::QWaylandScreen(QWaylandDisplay *waylandDisplay, int version, uint32_t id)
|
||||
: QtWayland::wl_output(waylandDisplay->wl_registry(), id, qMin(version, 2))
|
||||
, m_outputId(id)
|
||||
@ -95,7 +101,7 @@ void QWaylandScreen::maybeInitialize()
|
||||
updateXdgOutputProperties();
|
||||
}
|
||||
|
||||
void QWaylandScreen::initXdgOutput(QtWayland::zxdg_output_manager_v1 *xdgOutputManager)
|
||||
void QWaylandScreen::initXdgOutput(QWaylandXdgOutputManagerV1 *xdgOutputManager)
|
||||
{
|
||||
Q_ASSERT(xdgOutputManager);
|
||||
if (zxdg_output_v1::isInitialized())
|
||||
@ -165,11 +171,18 @@ QList<QPlatformScreen *> QWaylandScreen::virtualSiblings() const
|
||||
{
|
||||
QList<QPlatformScreen *> list;
|
||||
const QList<QWaylandScreen*> screens = mWaylandDisplay->screens();
|
||||
list.reserve(screens.count());
|
||||
auto *placeholder = mWaylandDisplay->placeholderScreen();
|
||||
|
||||
list.reserve(screens.count() + (placeholder ? 1 : 0));
|
||||
|
||||
for (QWaylandScreen *screen : qAsConst(screens)) {
|
||||
if (screen->screen())
|
||||
list << screen;
|
||||
}
|
||||
|
||||
if (placeholder)
|
||||
list << placeholder;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -210,9 +223,11 @@ QPlatformCursor *QWaylandScreen::cursor() const
|
||||
}
|
||||
#endif // QT_CONFIG(cursor)
|
||||
|
||||
QWaylandScreen * QWaylandScreen::waylandScreenFromWindow(QWindow *window)
|
||||
QWaylandScreen *QWaylandScreen::waylandScreenFromWindow(QWindow *window)
|
||||
{
|
||||
QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWindow(window);
|
||||
if (platformScreen->isPlaceholder())
|
||||
return nullptr;
|
||||
return static_cast<QWaylandScreen *>(platformScreen);
|
||||
}
|
||||
|
||||
@ -262,10 +277,15 @@ void QWaylandScreen::output_scale(int32_t factor)
|
||||
void QWaylandScreen::output_done()
|
||||
{
|
||||
mOutputDone = true;
|
||||
if (mInitialized)
|
||||
if (zxdg_output_v1::isInitialized() && mWaylandDisplay->xdgOutputManager()->version() >= 3)
|
||||
mXdgOutputDone = true;
|
||||
if (mInitialized) {
|
||||
updateOutputProperties();
|
||||
else
|
||||
if (zxdg_output_v1::isInitialized())
|
||||
updateXdgOutputProperties();
|
||||
} else {
|
||||
maybeInitialize();
|
||||
}
|
||||
}
|
||||
|
||||
void QWaylandScreen::updateOutputProperties()
|
||||
@ -316,6 +336,9 @@ void QWaylandScreen::zxdg_output_v1_logical_size(int32_t width, int32_t height)
|
||||
|
||||
void QWaylandScreen::zxdg_output_v1_done()
|
||||
{
|
||||
if (Q_UNLIKELY(mWaylandDisplay->xdgOutputManager()->version() >= 3))
|
||||
qWarning(lcQpaWayland) << "zxdg_output_v1.done received on version 3 or newer, this is most likely a bug in the compositor";
|
||||
|
||||
mXdgOutputDone = true;
|
||||
if (mInitialized)
|
||||
updateXdgOutputProperties();
|
||||
|
@ -57,7 +57,6 @@
|
||||
#include <QtWaylandClient/private/qwayland-wayland.h>
|
||||
#include <QtWaylandClient/private/qwayland-xdg-output-unstable-v1.h>
|
||||
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtWaylandClient {
|
||||
@ -65,6 +64,14 @@ namespace QtWaylandClient {
|
||||
class QWaylandDisplay;
|
||||
class QWaylandCursor;
|
||||
|
||||
class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgOutputManagerV1 : public QtWayland::zxdg_output_manager_v1 {
|
||||
public:
|
||||
QWaylandXdgOutputManagerV1(QWaylandDisplay *display, uint id, uint version);
|
||||
uint version() const { return m_version; }
|
||||
private:
|
||||
uint m_version = 1; // TODO: remove when we upgrade minimum libwayland requriement to 1.10
|
||||
};
|
||||
|
||||
class Q_WAYLAND_CLIENT_EXPORT QWaylandScreen : public QPlatformScreen, QtWayland::wl_output, QtWayland::zxdg_output_v1
|
||||
{
|
||||
public:
|
||||
@ -73,7 +80,7 @@ public:
|
||||
|
||||
void maybeInitialize();
|
||||
|
||||
void initXdgOutput(QtWayland::zxdg_output_manager_v1 *xdgOutputManager);
|
||||
void initXdgOutput(QWaylandXdgOutputManagerV1 *xdgOutputManager);
|
||||
|
||||
QWaylandDisplay *display() const;
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include <QtCore/qstandardpaths.h>
|
||||
#include <QtCore/qtemporaryfile.h>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QTransform>
|
||||
#include <QMutexLocker>
|
||||
|
||||
#include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
|
||||
@ -151,9 +152,9 @@ QImage *QWaylandShmBuffer::imageInsideMargins(const QMargins &marginsIn)
|
||||
|
||||
}
|
||||
|
||||
QWaylandShmBackingStore::QWaylandShmBackingStore(QWindow *window)
|
||||
QWaylandShmBackingStore::QWaylandShmBackingStore(QWindow *window, QWaylandDisplay *display)
|
||||
: QPlatformBackingStore(window)
|
||||
, mDisplay(QWaylandScreen::waylandScreenFromWindow(window)->display())
|
||||
, mDisplay(display)
|
||||
{
|
||||
|
||||
}
|
||||
@ -328,7 +329,7 @@ void QWaylandShmBackingStore::updateDecorations()
|
||||
qreal dp = sourceImage.devicePixelRatio();
|
||||
int dpWidth = int(sourceImage.width() / dp);
|
||||
int dpHeight = int(sourceImage.height() / dp);
|
||||
QMatrix sourceMatrix;
|
||||
QTransform sourceMatrix;
|
||||
sourceMatrix.scale(dp, dp);
|
||||
QRect target; // needs to be in device independent pixels
|
||||
|
||||
|
@ -88,7 +88,7 @@ private:
|
||||
class Q_WAYLAND_CLIENT_EXPORT QWaylandShmBackingStore : public QPlatformBackingStore
|
||||
{
|
||||
public:
|
||||
QWaylandShmBackingStore(QWindow *window);
|
||||
QWaylandShmBackingStore(QWindow *window, QWaylandDisplay *display);
|
||||
~QWaylandShmBackingStore() override;
|
||||
|
||||
QPaintDevice *paintDevice() override;
|
||||
|
@ -49,8 +49,8 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtWaylandClient {
|
||||
|
||||
QWaylandShmWindow::QWaylandShmWindow(QWindow *window)
|
||||
: QWaylandWindow(window)
|
||||
QWaylandShmWindow::QWaylandShmWindow(QWindow *window, QWaylandDisplay *display)
|
||||
: QWaylandWindow(window, display)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ namespace QtWaylandClient {
|
||||
class Q_WAYLAND_CLIENT_EXPORT QWaylandShmWindow : public QWaylandWindow
|
||||
{
|
||||
public:
|
||||
QWaylandShmWindow(QWindow *window);
|
||||
QWaylandShmWindow(QWindow *window, QWaylandDisplay *display);
|
||||
~QWaylandShmWindow() override;
|
||||
|
||||
WindowType windowType() const override;
|
||||
|
@ -72,8 +72,12 @@ QWaylandSurface *QWaylandSurface::fromWlSurface(::wl_surface *surface)
|
||||
|
||||
void QWaylandSurface::handleScreenRemoved(QScreen *qScreen)
|
||||
{
|
||||
auto *screen = static_cast<QWaylandScreen *>(qScreen->handle());
|
||||
if (m_screens.removeOne(screen))
|
||||
auto *platformScreen = qScreen->handle();
|
||||
if (platformScreen->isPlaceholder())
|
||||
return;
|
||||
|
||||
auto *waylandScreen = static_cast<QWaylandScreen *>(qScreen->handle());
|
||||
if (m_screens.removeOne(waylandScreen))
|
||||
emit screensChanged();
|
||||
}
|
||||
|
||||
|
332
src/plugins/platforms/wayland/qwaylandtabletv2.cpp
Normal file
332
src/plugins/platforms/wayland/qwaylandtabletv2.cpp
Normal file
@ -0,0 +1,332 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qwaylandtabletv2_p.h"
|
||||
#include "qwaylandinputdevice_p.h"
|
||||
#include "qwaylanddisplay_p.h"
|
||||
#include "qwaylandsurface_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtWaylandClient {
|
||||
|
||||
QWaylandTabletManagerV2::QWaylandTabletManagerV2(QWaylandDisplay *display, uint id, uint version)
|
||||
: zwp_tablet_manager_v2(display->wl_registry(), id, qMin(version, uint(1)))
|
||||
{
|
||||
// Create tabletSeats for all seats.
|
||||
// This only works if we get the manager after all seats
|
||||
const auto seats = display->inputDevices();
|
||||
for (auto *seat : seats)
|
||||
createTabletSeat(seat);
|
||||
}
|
||||
|
||||
QWaylandTabletSeatV2 *QWaylandTabletManagerV2::createTabletSeat(QWaylandInputDevice *seat)
|
||||
{
|
||||
return new QWaylandTabletSeatV2(this, seat);
|
||||
}
|
||||
|
||||
QWaylandTabletSeatV2::QWaylandTabletSeatV2(QWaylandTabletManagerV2 *manager, QWaylandInputDevice *seat)
|
||||
: QtWayland::zwp_tablet_seat_v2(manager->get_tablet_seat(seat->wl_seat()))
|
||||
{
|
||||
}
|
||||
|
||||
QWaylandTabletSeatV2::~QWaylandTabletSeatV2()
|
||||
{
|
||||
for (auto *tablet : m_tablets)
|
||||
tablet->destroy();
|
||||
for (auto *tool : m_tools)
|
||||
tool->destroy();
|
||||
for (auto *pad : m_pads)
|
||||
pad->destroy();
|
||||
destroy();
|
||||
}
|
||||
|
||||
void QWaylandTabletSeatV2::zwp_tablet_seat_v2_tablet_added(zwp_tablet_v2 *id)
|
||||
{
|
||||
auto *tablet = new QWaylandTabletV2(id);
|
||||
m_tablets.push_back(tablet);
|
||||
connect(tablet, &QWaylandTabletV2::destroyed, this, [this, tablet] { m_tablets.removeOne(tablet); });
|
||||
}
|
||||
|
||||
void QWaylandTabletSeatV2::zwp_tablet_seat_v2_tool_added(zwp_tablet_tool_v2 *id)
|
||||
{
|
||||
auto *tool = new QWaylandTabletToolV2(id);
|
||||
m_tools.push_back(tool);
|
||||
connect(tool, &QWaylandTabletToolV2::destroyed, this, [this, tool] { m_tools.removeOne(tool); });
|
||||
}
|
||||
|
||||
void QWaylandTabletSeatV2::zwp_tablet_seat_v2_pad_added(zwp_tablet_pad_v2 *id)
|
||||
{
|
||||
auto *pad = new QWaylandTabletPadV2(id);
|
||||
m_pads.push_back(pad);
|
||||
connect(pad, &QWaylandTabletPadV2::destroyed, this, [this, pad] { m_pads.removeOne(pad); });
|
||||
}
|
||||
|
||||
QWaylandTabletV2::QWaylandTabletV2(::zwp_tablet_v2 *tablet)
|
||||
: QtWayland::zwp_tablet_v2(tablet)
|
||||
{
|
||||
}
|
||||
|
||||
void QWaylandTabletV2::zwp_tablet_v2_removed()
|
||||
{
|
||||
destroy();
|
||||
delete this;
|
||||
}
|
||||
|
||||
QWaylandTabletToolV2::QWaylandTabletToolV2(::zwp_tablet_tool_v2 *tool)
|
||||
: QtWayland::zwp_tablet_tool_v2(tool)
|
||||
{
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_type(uint32_t tool_type)
|
||||
{
|
||||
m_toolType = type(tool_type);
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_hardware_serial(uint32_t hardware_serial_hi, uint32_t hardware_serial_lo)
|
||||
{
|
||||
m_uid = (quint64(hardware_serial_hi) << 32) + hardware_serial_lo;
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_capability(uint32_t capability)
|
||||
{
|
||||
if (capability == capability_rotation)
|
||||
m_hasRotation = true;
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_done()
|
||||
{
|
||||
switch (m_toolType) {
|
||||
case type::type_airbrush:
|
||||
case type::type_brush:
|
||||
case type::type_pencil:
|
||||
case type::type_pen:
|
||||
m_pointerType = QTabletEvent::PointerType::Pen;
|
||||
break;
|
||||
case type::type_eraser:
|
||||
m_pointerType = QTabletEvent::PointerType::Eraser;
|
||||
break;
|
||||
case type::type_mouse:
|
||||
case type::type_lens:
|
||||
m_pointerType = QTabletEvent::PointerType::Cursor;
|
||||
break;
|
||||
case type::type_finger:
|
||||
m_pointerType = QTabletEvent::PointerType::UnknownPointer;
|
||||
break;
|
||||
}
|
||||
switch (m_toolType) {
|
||||
case type::type_airbrush:
|
||||
m_tabletDevice = QTabletEvent::TabletDevice::Airbrush;
|
||||
break;
|
||||
case type::type_brush:
|
||||
case type::type_pencil:
|
||||
case type::type_pen:
|
||||
case type::type_eraser:
|
||||
m_tabletDevice = m_hasRotation ? QTabletEvent::TabletDevice::RotationStylus : QTabletEvent::TabletDevice::Stylus;
|
||||
break;
|
||||
case type::type_lens:
|
||||
m_tabletDevice = QTabletEvent::TabletDevice::Puck;
|
||||
break;
|
||||
case type::type_mouse:
|
||||
case type::type_finger:
|
||||
m_tabletDevice = QTabletEvent::TabletDevice::NoDevice;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_removed()
|
||||
{
|
||||
destroy();
|
||||
delete this;
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_proximity_in(uint32_t serial, zwp_tablet_v2 *tablet, wl_surface *surface)
|
||||
{
|
||||
Q_UNUSED(tablet);
|
||||
Q_UNUSED(serial);
|
||||
if (Q_UNLIKELY(!surface)) {
|
||||
qCDebug(lcQpaWayland) << "Ignoring zwp_tablet_tool_v2_proximity_v2 with no surface";
|
||||
return;
|
||||
}
|
||||
m_pending.enteredSurface = true;
|
||||
m_pending.proximitySurface = QWaylandSurface::fromWlSurface(surface);
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_proximity_out()
|
||||
{
|
||||
m_pending.enteredSurface = false;
|
||||
m_pending.proximitySurface = nullptr;
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_down(uint32_t serial)
|
||||
{
|
||||
Q_UNUSED(serial);
|
||||
m_pending.down = true;
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_up()
|
||||
{
|
||||
m_pending.down = false;
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_motion(wl_fixed_t x, wl_fixed_t y)
|
||||
{
|
||||
m_pending.surfacePosition = QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y));
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_pressure(uint32_t pressure)
|
||||
{
|
||||
const int maxPressure = 65535;
|
||||
m_pending.pressure = qreal(pressure)/maxPressure;
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_distance(uint32_t distance)
|
||||
{
|
||||
m_pending.distance = distance;
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_tilt(wl_fixed_t tilt_x, wl_fixed_t tilt_y)
|
||||
{
|
||||
m_pending.xTilt = wl_fixed_to_double(tilt_x);
|
||||
m_pending.yTilt = wl_fixed_to_double(tilt_y);
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_rotation(wl_fixed_t degrees)
|
||||
{
|
||||
m_pending.rotation = wl_fixed_to_double(degrees);
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_slider(int32_t position)
|
||||
{
|
||||
m_pending.slider = qreal(position) / 65535;
|
||||
}
|
||||
|
||||
static Qt::MouseButton mouseButtonFromTablet(uint button)
|
||||
{
|
||||
switch (button) {
|
||||
case 0x110: return Qt::MouseButton::LeftButton; // BTN_LEFT
|
||||
case 0x14b: return Qt::MouseButton::MiddleButton; // BTN_STYLUS
|
||||
case 0x14c: return Qt::MouseButton::RightButton; // BTN_STYLUS2
|
||||
default:
|
||||
return Qt::NoButton;
|
||||
}
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_button(uint32_t serial, uint32_t button, uint32_t state)
|
||||
{
|
||||
Q_UNUSED(serial);
|
||||
Qt::MouseButton mouseButton = mouseButtonFromTablet(button);
|
||||
if (state == button_state_pressed)
|
||||
m_pending.buttons |= mouseButton;
|
||||
else
|
||||
m_pending.buttons &= ~mouseButton;
|
||||
}
|
||||
|
||||
void QWaylandTabletToolV2::zwp_tablet_tool_v2_frame(uint32_t time)
|
||||
{
|
||||
if (m_pending.proximitySurface && !m_applied.proximitySurface) {
|
||||
QWindowSystemInterface::handleTabletEnterProximityEvent(m_tabletDevice, m_pointerType, m_uid);
|
||||
m_applied.proximitySurface = m_pending.proximitySurface;
|
||||
}
|
||||
|
||||
if (!(m_pending == m_applied) && m_pending.proximitySurface) {
|
||||
if (!m_pending.proximitySurface) {
|
||||
qCWarning(lcQpaWayland) << "Can't send tablet event with no proximity surface, ignoring";
|
||||
return;
|
||||
}
|
||||
QWaylandWindow *waylandWindow = QWaylandWindow::fromWlSurface(m_pending.proximitySurface->object());
|
||||
QWindow *window = waylandWindow->window();
|
||||
ulong timestamp = time;
|
||||
const QPointF localPosition = waylandWindow->mapFromWlSurface(m_pending.surfacePosition);
|
||||
|
||||
QPointF delta = localPosition - localPosition.toPoint();
|
||||
QPointF globalPosition = window->mapToGlobal(localPosition.toPoint());
|
||||
globalPosition += delta;
|
||||
|
||||
Qt::MouseButtons buttons = m_pending.down ? Qt::MouseButton::LeftButton : Qt::MouseButton::NoButton;
|
||||
buttons |= m_pending.buttons;
|
||||
qreal pressure = m_pending.pressure;
|
||||
int xTilt = int(m_pending.xTilt);
|
||||
int yTilt = int(m_pending.yTilt);
|
||||
qreal tangentialPressure = m_pending.slider;
|
||||
qreal rotation = m_pending.rotation;
|
||||
int z = int(m_pending.distance);
|
||||
QWindowSystemInterface::handleTabletEvent(window, timestamp, localPosition, globalPosition,
|
||||
m_tabletDevice, m_pointerType, buttons, pressure,
|
||||
xTilt, yTilt, tangentialPressure, rotation, z, m_uid);
|
||||
}
|
||||
|
||||
if (!m_pending.proximitySurface && m_applied.enteredSurface) {
|
||||
QWindowSystemInterface::handleTabletLeaveProximityEvent(m_tabletDevice, m_pointerType, m_uid);
|
||||
m_pending = State(); // Don't leave pressure etc. lying around when we enter the next surface
|
||||
}
|
||||
|
||||
m_applied = m_pending;
|
||||
}
|
||||
|
||||
// TODO: delete when upgrading to c++20
|
||||
bool QWaylandTabletToolV2::State::operator==(const QWaylandTabletToolV2::State &o) const {
|
||||
return
|
||||
down == o.down &&
|
||||
proximitySurface.data() == o.proximitySurface.data() &&
|
||||
enteredSurface == o.enteredSurface &&
|
||||
surfacePosition == o.surfacePosition &&
|
||||
distance == o.distance &&
|
||||
pressure == o.pressure &&
|
||||
rotation == o.rotation &&
|
||||
xTilt == o.xTilt &&
|
||||
yTilt == o.yTilt &&
|
||||
slider == o.slider &&
|
||||
buttons == o.buttons;
|
||||
}
|
||||
|
||||
QWaylandTabletPadV2::QWaylandTabletPadV2(::zwp_tablet_pad_v2 *pad)
|
||||
: QtWayland::zwp_tablet_pad_v2(pad)
|
||||
{
|
||||
}
|
||||
|
||||
void QWaylandTabletPadV2::zwp_tablet_pad_v2_removed()
|
||||
{
|
||||
destroy();
|
||||
delete this;
|
||||
}
|
||||
|
||||
} // namespace QtWaylandClient
|
||||
|
||||
QT_END_NAMESPACE
|
191
src/plugins/platforms/wayland/qwaylandtabletv2_p.h
Normal file
191
src/plugins/platforms/wayland/qwaylandtabletv2_p.h
Normal file
@ -0,0 +1,191 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QWAYLANDTABLETV2_P_H
|
||||
#define QWAYLANDTABLETV2_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-tablet-unstable-v2.h>
|
||||
|
||||
#include <QtWaylandClient/private/qtwaylandclientglobal_p.h>
|
||||
|
||||
#include <QtGui/QTabletEvent>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QPointer>
|
||||
#include <QtCore/QPointF>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtWaylandClient {
|
||||
|
||||
class QWaylandDisplay;
|
||||
class QWaylandInputDevice;
|
||||
class QWaylandSurface;
|
||||
|
||||
class QWaylandTabletSeatV2;
|
||||
class QWaylandTabletV2;
|
||||
class QWaylandTabletToolV2;
|
||||
class QWaylandTabletPadV2;
|
||||
|
||||
class Q_WAYLAND_CLIENT_EXPORT QWaylandTabletManagerV2 : public QtWayland::zwp_tablet_manager_v2
|
||||
{
|
||||
public:
|
||||
explicit QWaylandTabletManagerV2(QWaylandDisplay *display, uint id, uint version);
|
||||
QWaylandTabletSeatV2 *createTabletSeat(QWaylandInputDevice *seat);
|
||||
};
|
||||
|
||||
class Q_WAYLAND_CLIENT_EXPORT QWaylandTabletSeatV2 : public QObject, public QtWayland::zwp_tablet_seat_v2
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QWaylandTabletSeatV2(QWaylandTabletManagerV2 *manager, QWaylandInputDevice *seat);
|
||||
~QWaylandTabletSeatV2() override;
|
||||
|
||||
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:
|
||||
QVector<QWaylandTabletV2 *> m_tablets;
|
||||
QVector<QWaylandTabletToolV2 *> m_tools;
|
||||
QVector<QWaylandTabletPadV2 *> m_pads;
|
||||
};
|
||||
|
||||
class Q_WAYLAND_CLIENT_EXPORT QWaylandTabletV2 : public QObject, public QtWayland::zwp_tablet_v2
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QWaylandTabletV2(::zwp_tablet_v2 *tablet);
|
||||
|
||||
protected:
|
||||
// void zwp_tablet_v2_name(const QString &name) override;
|
||||
// void zwp_tablet_v2_id(uint32_t vid, uint32_t pid) override;
|
||||
// void zwp_tablet_v2_path(const QString &path) override;
|
||||
// void zwp_tablet_v2_done() override;
|
||||
void zwp_tablet_v2_removed() override;
|
||||
};
|
||||
|
||||
class Q_WAYLAND_CLIENT_EXPORT QWaylandTabletToolV2 : public QObject, public QtWayland::zwp_tablet_tool_v2
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QWaylandTabletToolV2(::zwp_tablet_tool_v2 *tool);
|
||||
|
||||
protected:
|
||||
void zwp_tablet_tool_v2_type(uint32_t tool_type) override;
|
||||
void zwp_tablet_tool_v2_hardware_serial(uint32_t hardware_serial_hi, uint32_t hardware_serial_lo) override;
|
||||
// void zwp_tablet_tool_v2_hardware_id_wacom(uint32_t hardware_id_hi, uint32_t hardware_id_lo) override;
|
||||
void zwp_tablet_tool_v2_capability(uint32_t capability) override;
|
||||
void zwp_tablet_tool_v2_done() override;
|
||||
void zwp_tablet_tool_v2_removed() override;
|
||||
void zwp_tablet_tool_v2_proximity_in(uint32_t serial, struct ::zwp_tablet_v2 *tablet, struct ::wl_surface *surface) override;
|
||||
void zwp_tablet_tool_v2_proximity_out() override;
|
||||
void zwp_tablet_tool_v2_down(uint32_t serial) override;
|
||||
void zwp_tablet_tool_v2_up() override;
|
||||
void zwp_tablet_tool_v2_motion(wl_fixed_t x, wl_fixed_t y) override;
|
||||
void zwp_tablet_tool_v2_pressure(uint32_t pressure) override;
|
||||
void zwp_tablet_tool_v2_distance(uint32_t distance) override;
|
||||
void zwp_tablet_tool_v2_tilt(wl_fixed_t tilt_x, wl_fixed_t tilt_y) override;
|
||||
void zwp_tablet_tool_v2_rotation(wl_fixed_t degrees) override;
|
||||
void zwp_tablet_tool_v2_slider(int32_t position) override;
|
||||
// void zwp_tablet_tool_v2_wheel(wl_fixed_t degrees, int32_t clicks) override;
|
||||
void zwp_tablet_tool_v2_button(uint32_t serial, uint32_t button, uint32_t state) override;
|
||||
void zwp_tablet_tool_v2_frame(uint32_t time) override;
|
||||
|
||||
private:
|
||||
|
||||
// Static state (sent before done event)
|
||||
QTabletEvent::PointerType m_pointerType = QTabletEvent::PointerType::UnknownPointer;
|
||||
QTabletEvent::TabletDevice m_tabletDevice = QTabletEvent::TabletDevice::NoDevice;
|
||||
type m_toolType = type_pen;
|
||||
bool m_hasRotation = false;
|
||||
quint64 m_uid = 0;
|
||||
|
||||
// Accumulated state (applied on frame event)
|
||||
struct State {
|
||||
bool down = false;
|
||||
QPointer<QWaylandSurface> proximitySurface;
|
||||
bool enteredSurface = false; // Not enough with just proximitySurface, if the surface is deleted, we still want to send a leave event
|
||||
QPointF surfacePosition;
|
||||
uint distance = 0;
|
||||
qreal pressure = 0;
|
||||
qreal rotation = 0;
|
||||
qreal xTilt = 0;
|
||||
qreal yTilt = 0;
|
||||
qreal slider = 0;
|
||||
Qt::MouseButtons buttons = Qt::MouseButton::NoButton; // Actual buttons, down state -> left mouse is mapped inside the frame handler
|
||||
//auto operator<=>(const Point&) const = default; // TODO: use this when upgrading to C++20
|
||||
bool operator==(const State &o) const;
|
||||
} m_pending, m_applied;
|
||||
};
|
||||
|
||||
// We don't actually use this, but need to handle the "removed" event to comply with the protocol
|
||||
class Q_WAYLAND_CLIENT_EXPORT QWaylandTabletPadV2 : public QObject, public QtWayland::zwp_tablet_pad_v2
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QWaylandTabletPadV2(::zwp_tablet_pad_v2 *pad);
|
||||
|
||||
protected:
|
||||
// void zwp_tablet_pad_v2_group(struct ::zwp_tablet_pad_group_v2 *pad_group) override;
|
||||
// void zwp_tablet_pad_v2_path(const QString &path) override;
|
||||
// void zwp_tablet_pad_v2_buttons(uint32_t buttons) override;
|
||||
// void zwp_tablet_pad_v2_done() override;
|
||||
// void zwp_tablet_pad_v2_button(uint32_t time, uint32_t button, uint32_t state) override;
|
||||
// void zwp_tablet_pad_v2_enter(uint32_t serial, struct ::zwp_tablet_v2 *tablet, struct ::wl_surface *surface) override;
|
||||
// void zwp_tablet_pad_v2_leave(uint32_t serial, struct ::wl_surface *surface) override;
|
||||
void zwp_tablet_pad_v2_removed() override;
|
||||
};
|
||||
|
||||
} // namespace QtWaylandClient
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QWAYLANDTABLETV2_P_H
|
@ -42,6 +42,8 @@
|
||||
#include "qwaylanddisplay_p.h"
|
||||
#include "qwaylandsurface_p.h"
|
||||
|
||||
#include <QtGui/QTouchDevice>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtWaylandClient {
|
||||
@ -165,22 +167,28 @@ void QWaylandTouchExtension::sendTouchEvent()
|
||||
|
||||
QWindowSystemInterface::handleTouchEvent(mTargetWindow, mTimestamp, mTouchDevice, mTouchPoints);
|
||||
|
||||
Qt::TouchPointStates states = 0;
|
||||
Qt::TouchPointStates states = {};
|
||||
for (int i = 0; i < mTouchPoints.count(); ++i)
|
||||
states |= mTouchPoints.at(i).state;
|
||||
|
||||
if (mFlags & QT_TOUCH_EXTENSION_FLAGS_MOUSE_FROM_TOUCH) {
|
||||
if (states == Qt::TouchPointPressed)
|
||||
const bool firstPress = states == Qt::TouchPointPressed;
|
||||
if (firstPress)
|
||||
mMouseSourceId = mTouchPoints.first().id;
|
||||
for (int i = 0; i < mTouchPoints.count(); ++i) {
|
||||
const QWindowSystemInterface::TouchPoint &tp(mTouchPoints.at(i));
|
||||
if (tp.id == mMouseSourceId) {
|
||||
Qt::MouseButtons buttons = tp.state == Qt::TouchPointReleased ? Qt::NoButton : Qt::LeftButton;
|
||||
const bool released = tp.state == Qt::TouchPointReleased;
|
||||
Qt::MouseButtons buttons = released ? Qt::NoButton : Qt::LeftButton;
|
||||
QEvent::Type eventType = firstPress ? QEvent::MouseButtonPress
|
||||
: released ? QEvent::MouseButtonRelease
|
||||
: QEvent::MouseMove;
|
||||
mLastMouseGlobal = tp.area.center();
|
||||
QPoint globalPoint = mLastMouseGlobal.toPoint();
|
||||
QPointF delta = mLastMouseGlobal - globalPoint;
|
||||
mLastMouseLocal = mTargetWindow->mapFromGlobal(globalPoint) + delta;
|
||||
QWindowSystemInterface::handleMouseEvent(mTargetWindow, mTimestamp, mLastMouseLocal, mLastMouseGlobal, buttons);
|
||||
QWindowSystemInterface::handleMouseEvent(mTargetWindow, mTimestamp, mLastMouseLocal, mLastMouseGlobal,
|
||||
buttons, Qt::LeftButton, eventType);
|
||||
if (buttons == Qt::NoButton)
|
||||
mMouseSourceId = -1;
|
||||
break;
|
||||
@ -200,7 +208,7 @@ void QWaylandTouchExtension::touchCanceled()
|
||||
mTouchPoints.clear();
|
||||
mPrevTouchPoints.clear();
|
||||
if (mMouseSourceId != -1)
|
||||
QWindowSystemInterface::handleMouseEvent(mTargetWindow, mTimestamp, mLastMouseLocal, mLastMouseGlobal, Qt::NoButton);
|
||||
QWindowSystemInterface::handleMouseEvent(mTargetWindow, mTimestamp, mLastMouseLocal, mLastMouseGlobal, Qt::NoButton, Qt::LeftButton, QEvent::MouseButtonRelease);
|
||||
}
|
||||
|
||||
void QWaylandTouchExtension::touch_extension_configure(uint32_t flags)
|
||||
|
@ -43,8 +43,8 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtWaylandClient {
|
||||
|
||||
QWaylandVulkanWindow::QWaylandVulkanWindow(QWindow *window)
|
||||
: QWaylandWindow(window)
|
||||
QWaylandVulkanWindow::QWaylandVulkanWindow(QWindow *window, QWaylandDisplay *display)
|
||||
: QWaylandWindow(window, display)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ namespace QtWaylandClient {
|
||||
class QWaylandVulkanWindow : public QWaylandWindow
|
||||
{
|
||||
public:
|
||||
explicit QWaylandVulkanWindow(QWindow *window);
|
||||
explicit QWaylandVulkanWindow(QWindow *window, QWaylandDisplay *display);
|
||||
~QWaylandVulkanWindow() override;
|
||||
|
||||
WindowType windowType() const override;
|
||||
|
@ -73,9 +73,9 @@ Q_LOGGING_CATEGORY(lcWaylandBackingstore, "qt.qpa.wayland.backingstore")
|
||||
|
||||
QWaylandWindow *QWaylandWindow::mMouseGrab = nullptr;
|
||||
|
||||
QWaylandWindow::QWaylandWindow(QWindow *window)
|
||||
QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
|
||||
: QPlatformWindow(window)
|
||||
, mDisplay(waylandScreen()->display())
|
||||
, mDisplay(display)
|
||||
, mFrameQueue(mDisplay->createEventQueue())
|
||||
, mResizeAfterSwap(qEnvironmentVariableIsSet("QT_WAYLAND_RESIZE_AFTER_SWAP"))
|
||||
{
|
||||
@ -125,9 +125,10 @@ void QWaylandWindow::initWindow()
|
||||
if (shouldCreateSubSurface()) {
|
||||
Q_ASSERT(!mSubSurfaceWindow);
|
||||
|
||||
QWaylandWindow *p = static_cast<QWaylandWindow *>(QPlatformWindow::parent());
|
||||
if (::wl_subsurface *ss = mDisplay->createSubSurface(this, p)) {
|
||||
mSubSurfaceWindow = new QWaylandSubSurface(this, p, ss);
|
||||
auto *parent = static_cast<QWaylandWindow *>(QPlatformWindow::parent());
|
||||
if (parent->wlSurface()) {
|
||||
if (::wl_subsurface *subsurface = mDisplay->createSubSurface(this, parent))
|
||||
mSubSurfaceWindow = new QWaylandSubSurface(this, parent, subsurface);
|
||||
}
|
||||
} else if (shouldCreateShellSurface()) {
|
||||
Q_ASSERT(!mShellSurface);
|
||||
@ -176,7 +177,7 @@ void QWaylandWindow::initWindow()
|
||||
}
|
||||
}
|
||||
|
||||
mScale = waylandScreen()->scale();
|
||||
mScale = waylandScreen() ? waylandScreen()->scale() : 1; // fallback to 1 if we don't have a real screen
|
||||
|
||||
// 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()
|
||||
@ -401,14 +402,14 @@ void QWaylandWindow::closePopups(QWaylandWindow *parent)
|
||||
}
|
||||
}
|
||||
|
||||
QWaylandScreen *QWaylandWindow::calculateScreenFromSurfaceEvents() const
|
||||
QPlatformScreen *QWaylandWindow::calculateScreenFromSurfaceEvents() const
|
||||
{
|
||||
if (mSurface) {
|
||||
if (auto *screen = mSurface->oldestEnteredScreen())
|
||||
return screen;
|
||||
}
|
||||
|
||||
return waylandScreen();
|
||||
return QPlatformWindow::screen();
|
||||
}
|
||||
|
||||
void QWaylandWindow::setVisible(bool visible)
|
||||
@ -425,8 +426,7 @@ void QWaylandWindow::setVisible(bool visible)
|
||||
// QWaylandShmBackingStore::beginPaint().
|
||||
} else {
|
||||
sendExposeEvent(QRect());
|
||||
if (window()->type() == Qt::Popup)
|
||||
closePopups(this);
|
||||
closePopups(this);
|
||||
reset();
|
||||
}
|
||||
}
|
||||
@ -672,6 +672,19 @@ QRect QWaylandWindow::windowContentGeometry() const
|
||||
return QRect(QPoint(), surfaceSize());
|
||||
}
|
||||
|
||||
/*!
|
||||
* Converts from wl_surface coordinates to Qt window coordinates. Qt window
|
||||
* coordinates start inside (not including) the window decorations, while
|
||||
* wl_surface coordinates start at the first pixel of the buffer. Potentially,
|
||||
* this should be in the window shadow, although we don't have those. So for
|
||||
* now, it's the first pixel of the decorations.
|
||||
*/
|
||||
QPointF QWaylandWindow::mapFromWlSurface(const QPointF &surfacePosition) const
|
||||
{
|
||||
const QMargins margins = frameMargins();
|
||||
return QPointF(surfacePosition.x() - margins.left(), surfacePosition.y() - margins.top());
|
||||
}
|
||||
|
||||
wl_surface *QWaylandWindow::wlSurface()
|
||||
{
|
||||
return mSurface ? mSurface->object() : nullptr;
|
||||
@ -689,7 +702,11 @@ QWaylandSubSurface *QWaylandWindow::subSurfaceWindow() const
|
||||
|
||||
QWaylandScreen *QWaylandWindow::waylandScreen() const
|
||||
{
|
||||
return static_cast<QWaylandScreen *>(QPlatformWindow::screen());
|
||||
auto *platformScreen = QPlatformWindow::screen();
|
||||
Q_ASSERT(platformScreen);
|
||||
if (platformScreen->isPlaceholder())
|
||||
return nullptr;
|
||||
return static_cast<QWaylandScreen *>(platformScreen);
|
||||
}
|
||||
|
||||
void QWaylandWindow::handleContentOrientationChange(Qt::ScreenOrientation orientation)
|
||||
@ -852,7 +869,7 @@ QWaylandWindow *QWaylandWindow::transientParent() const
|
||||
|
||||
void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e)
|
||||
{
|
||||
if (e.type == QWaylandPointerEvent::Leave) {
|
||||
if (e.type == QEvent::Leave) {
|
||||
if (mWindowDecoration) {
|
||||
if (mMouseEventsInContentArea)
|
||||
QWindowSystemInterface::handleLeaveEvent(window());
|
||||
@ -869,24 +886,26 @@ void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, const QWaylan
|
||||
handleMouseEventWithDecoration(inputDevice, e);
|
||||
} else {
|
||||
switch (e.type) {
|
||||
case QWaylandPointerEvent::Enter:
|
||||
case QEvent::Enter:
|
||||
QWindowSystemInterface::handleEnterEvent(window(), e.local, e.global);
|
||||
break;
|
||||
case QWaylandPointerEvent::Press:
|
||||
case QWaylandPointerEvent::Release:
|
||||
case QWaylandPointerEvent::Motion:
|
||||
QWindowSystemInterface::handleMouseEvent(window(), e.timestamp, e.local, e.global, e.buttons, e.modifiers);
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::MouseMove:
|
||||
QWindowSystemInterface::handleMouseEvent(window(), e.timestamp, e.local, e.global, e.buttons, e.button, e.type, e.modifiers);
|
||||
break;
|
||||
case QWaylandPointerEvent::Wheel:
|
||||
case QEvent::Wheel:
|
||||
QWindowSystemInterface::handleWheelEvent(window(), e.timestamp, e.local, e.global,
|
||||
e.pixelDelta, e.angleDelta, e.modifiers,
|
||||
e.phase, e.source, false);
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
#if QT_CONFIG(cursor)
|
||||
if (e.type == QWaylandPointerEvent::Enter) {
|
||||
if (e.type == QEvent::Enter) {
|
||||
QRect contentGeometry = windowContentGeometry().marginsRemoved(frameMargins());
|
||||
if (contentGeometry.contains(e.local.toPoint()))
|
||||
restoreMouseCursor(inputDevice);
|
||||
@ -918,10 +937,8 @@ void QWaylandWindow::handleMouseEventWithDecoration(QWaylandInputDevice *inputDe
|
||||
geometry().size().width() - marg.right(),
|
||||
geometry().size().height() - marg.bottom());
|
||||
if (windowRect.contains(e.local.toPoint()) || mMousePressedInContentArea != Qt::NoButton) {
|
||||
QPointF localTranslated = e.local;
|
||||
const QPointF localTranslated = mapFromWlSurface(e.local);
|
||||
QPointF globalTranslated = e.global;
|
||||
localTranslated.setX(localTranslated.x() - marg.left());
|
||||
localTranslated.setY(localTranslated.y() - marg.top());
|
||||
globalTranslated.setX(globalTranslated.x() - marg.left());
|
||||
globalTranslated.setY(globalTranslated.y() - marg.top());
|
||||
if (!mMouseEventsInContentArea) {
|
||||
@ -932,21 +949,23 @@ void QWaylandWindow::handleMouseEventWithDecoration(QWaylandInputDevice *inputDe
|
||||
}
|
||||
|
||||
switch (e.type) {
|
||||
case QWaylandPointerEvent::Enter:
|
||||
case QEvent::Enter:
|
||||
QWindowSystemInterface::handleEnterEvent(window(), localTranslated, globalTranslated);
|
||||
break;
|
||||
case QWaylandPointerEvent::Press:
|
||||
case QWaylandPointerEvent::Release:
|
||||
case QWaylandPointerEvent::Motion:
|
||||
QWindowSystemInterface::handleMouseEvent(window(), e.timestamp, localTranslated, globalTranslated, e.buttons, e.modifiers);
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::MouseMove:
|
||||
QWindowSystemInterface::handleMouseEvent(window(), e.timestamp, localTranslated, globalTranslated, e.buttons, e.button, e.type, e.modifiers);
|
||||
break;
|
||||
case QWaylandPointerEvent::Wheel: {
|
||||
case QEvent::Wheel: {
|
||||
QWindowSystemInterface::handleWheelEvent(window(), e.timestamp,
|
||||
localTranslated, globalTranslated,
|
||||
e.pixelDelta, e.angleDelta, e.modifiers,
|
||||
e.phase, e.source, false);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
mMouseEventsInContentArea = true;
|
||||
@ -961,7 +980,7 @@ void QWaylandWindow::handleMouseEventWithDecoration(QWaylandInputDevice *inputDe
|
||||
|
||||
void QWaylandWindow::handleScreensChanged()
|
||||
{
|
||||
QWaylandScreen *newScreen = calculateScreenFromSurfaceEvents();
|
||||
QPlatformScreen *newScreen = calculateScreenFromSurfaceEvents();
|
||||
|
||||
if (newScreen == mLastReportedScreen)
|
||||
return;
|
||||
@ -969,7 +988,7 @@ void QWaylandWindow::handleScreensChanged()
|
||||
QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen());
|
||||
mLastReportedScreen = newScreen;
|
||||
|
||||
int scale = newScreen->scale();
|
||||
int scale = newScreen->isPlaceholder() ? 1 : static_cast<QWaylandScreen *>(newScreen)->scale();
|
||||
if (scale != mScale) {
|
||||
mScale = scale;
|
||||
if (mSurface && mDisplay->compositorVersion() >= 3)
|
||||
|
@ -93,7 +93,7 @@ public:
|
||||
Vulkan
|
||||
};
|
||||
|
||||
QWaylandWindow(QWindow *window);
|
||||
QWaylandWindow(QWindow *window, QWaylandDisplay *display);
|
||||
~QWaylandWindow() override;
|
||||
|
||||
virtual WindowType windowType() const = 0;
|
||||
@ -129,6 +129,7 @@ public:
|
||||
QMargins frameMargins() const override;
|
||||
QSize surfaceSize() const;
|
||||
QRect windowContentGeometry() const;
|
||||
QPointF mapFromWlSurface(const QPointF &surfacePosition) const;
|
||||
|
||||
QWaylandSurface *waylandSurface() const { return mSurface.data(); }
|
||||
::wl_surface *wlSurface();
|
||||
@ -195,7 +196,7 @@ public:
|
||||
void propagateSizeHints() override;
|
||||
void addAttachOffset(const QPoint point);
|
||||
|
||||
bool startSystemMove(const QPoint &pos) override;
|
||||
bool startSystemMove(const QPoint &pos);
|
||||
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
void requestUpdate() override;
|
||||
@ -241,7 +242,7 @@ protected:
|
||||
bool mSentInitialResize = false;
|
||||
QPoint mOffset;
|
||||
int mScale = 1;
|
||||
QWaylandScreen *mLastReportedScreen = nullptr;
|
||||
QPlatformScreen *mLastReportedScreen = nullptr;
|
||||
|
||||
QIcon mWindowIcon;
|
||||
|
||||
@ -262,7 +263,7 @@ private:
|
||||
void reset(bool sendDestroyEvent = true);
|
||||
void sendExposeEvent(const QRect &rect);
|
||||
static void closePopups(QWaylandWindow *parent);
|
||||
QWaylandScreen *calculateScreenFromSurfaceEvents() const;
|
||||
QPlatformScreen *calculateScreenFromSurfaceEvents() const;
|
||||
|
||||
void handleMouseEventWithDecoration(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e);
|
||||
void handleScreensChanged();
|
||||
|
@ -467,6 +467,9 @@ bool Scanner::process()
|
||||
if (m_xml->hasError())
|
||||
return false;
|
||||
|
||||
printf("// This file was generated by qtwaylandscanner\n");
|
||||
printf("// source file is %s\n\n", qPrintable(m_protocolFilePath));
|
||||
|
||||
for (auto b : qAsConst(m_includes))
|
||||
printf("#include %s\n", b.constData());
|
||||
|
||||
|
@ -5,11 +5,13 @@ SUBDIRS += \
|
||||
datadevicev1 \
|
||||
fullscreenshellv1 \
|
||||
iviapplication \
|
||||
nooutput \
|
||||
output \
|
||||
primaryselectionv1 \
|
||||
seatv4 \
|
||||
seatv5 \
|
||||
surface \
|
||||
tabletv2 \
|
||||
wl_connect \
|
||||
xdgdecorationv1 \
|
||||
xdgoutput \
|
||||
|
@ -28,8 +28,8 @@
|
||||
|
||||
#include "mockcompositor.h"
|
||||
|
||||
#include <QtOpenGL/QOpenGLWindow>
|
||||
#include <QtGui/QRasterWindow>
|
||||
#include <QtGui/QOpenGLWindow>
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtGui/QDrag>
|
||||
|
||||
|
5
tests/auto/wayland/nooutput/nooutput.pro
Normal file
5
tests/auto/wayland/nooutput/nooutput.pro
Normal file
@ -0,0 +1,5 @@
|
||||
include (../shared/shared.pri)
|
||||
|
||||
TARGET = tst_nooutput
|
||||
SOURCES += tst_nooutput.cpp
|
||||
|
68
tests/auto/wayland/nooutput/tst_nooutput.cpp
Normal file
68
tests/auto/wayland/nooutput/tst_nooutput.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "mockcompositor.h"
|
||||
#include <QtGui/QScreen>
|
||||
#include <QtGui/QRasterWindow>
|
||||
|
||||
using namespace MockCompositor;
|
||||
|
||||
class NoOutputCompositor : public DefaultCompositor {
|
||||
public:
|
||||
NoOutputCompositor()
|
||||
{
|
||||
exec([this] { removeAll<Output>(); });
|
||||
m_config.autoConfigure = true;
|
||||
}
|
||||
};
|
||||
|
||||
class tst_nooutput : public QObject, private NoOutputCompositor
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void cleanup()
|
||||
{
|
||||
// There should be no wl_outputs in this test
|
||||
QCOMPOSITOR_COMPARE(getAll<Output>().size(), 0);
|
||||
QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage()));
|
||||
}
|
||||
void noScreens();
|
||||
};
|
||||
|
||||
void tst_nooutput::noScreens()
|
||||
{
|
||||
QRasterWindow window;
|
||||
window.resize(16, 16);
|
||||
window.show();
|
||||
|
||||
// We have to handle showing a window when there are no real outputs
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
|
||||
}
|
||||
|
||||
QCOMPOSITOR_TEST_MAIN(tst_nooutput)
|
||||
#include "tst_nooutput.moc"
|
@ -53,6 +53,7 @@ private slots:
|
||||
void windowScreens();
|
||||
void removePrimaryScreen();
|
||||
void screenOrder();
|
||||
void removeAllScreens();
|
||||
};
|
||||
|
||||
void tst_output::primaryScreen()
|
||||
@ -227,5 +228,47 @@ void tst_output::screenOrder()
|
||||
});
|
||||
}
|
||||
|
||||
// This is different from tst_nooutput::noScreens because here we have a screen at platform
|
||||
// integration initialization, which we then remove.
|
||||
void tst_output::removeAllScreens()
|
||||
{
|
||||
QRasterWindow window1;
|
||||
window1.resize(400, 320);
|
||||
window1.show();
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgSurface(0) && xdgSurface(0)->m_committedConfigureSerial);
|
||||
|
||||
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()); });
|
||||
|
||||
// Make sure the wl_output is actually removed before we continue
|
||||
QTRY_VERIFY(!QGuiApplication::primaryScreen() || QGuiApplication::primaryScreen()->model() != wlOutputPrimaryScreenModel);
|
||||
|
||||
// Adding a window while there are no screens should also work
|
||||
QRasterWindow window2;
|
||||
window2.resize(400, 320);
|
||||
window2.show();
|
||||
|
||||
exec([=] { add<Output>(screenInfo); });
|
||||
|
||||
// Things should be back to normal
|
||||
QTRY_VERIFY(QGuiApplication::primaryScreen());
|
||||
QTRY_COMPARE(QGuiApplication::primaryScreen()->model(), wlOutputPrimaryScreenModel);
|
||||
|
||||
// Test that we don't leave any fake screens around after we get a wl_output back.
|
||||
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
||||
|
||||
// Qt may choose to recreate/hide windows in response to changing screens, so give the client
|
||||
// some time to potentially mess up before we verify that the windows are visible.
|
||||
xdgPingAndWaitForPong();
|
||||
|
||||
// Windows should be visible after we've reconnected the screen
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgToplevel(0) && xdgToplevel(0)->m_xdgSurface->m_committedConfigureSerial);
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgToplevel(1) && xdgToplevel(1)->m_xdgSurface->m_committedConfigureSerial);
|
||||
|
||||
}
|
||||
|
||||
QCOMPOSITOR_TEST_MAIN(tst_output)
|
||||
#include "tst_output.moc"
|
||||
|
@ -30,8 +30,8 @@
|
||||
|
||||
#include <qwayland-server-wp-primary-selection-unstable-v1.h>
|
||||
|
||||
#include <QtOpenGL/QOpenGLWindow>
|
||||
#include <QtGui/QRasterWindow>
|
||||
#include <QtGui/QOpenGLWindow>
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtCore/private/qcore_unix_p.h>
|
||||
|
||||
|
@ -28,8 +28,8 @@
|
||||
|
||||
#include "mockcompositor.h"
|
||||
|
||||
#include <QtOpenGL/QOpenGLWindow>
|
||||
#include <QtGui/QRasterWindow>
|
||||
#include <QtGui/QOpenGLWindow>
|
||||
#if QT_CONFIG(cursor)
|
||||
#include <wayland-cursor.h>
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
@ -289,8 +289,8 @@ void tst_seatv4::simpleAxis()
|
||||
{
|
||||
Event() = default;
|
||||
|
||||
const QPoint pixelDelta;
|
||||
const QPoint angleDelta; // eights of a degree, positive is upwards, left
|
||||
QPoint pixelDelta;
|
||||
QPoint angleDelta; // eights of a degree, positive is upwards, left
|
||||
};
|
||||
QVector<Event> m_events;
|
||||
};
|
||||
|
@ -27,8 +27,8 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "mockcompositor.h"
|
||||
#include <QtOpenGL/QOpenGLWindow>
|
||||
#include <QtGui/QRasterWindow>
|
||||
#include <QtGui/QOpenGLWindow>
|
||||
|
||||
using namespace MockCompositor;
|
||||
|
||||
@ -71,6 +71,7 @@ private slots:
|
||||
void singleTapFloat();
|
||||
void multiTouch();
|
||||
void multiTouchUpAndMotionFrame();
|
||||
void tapAndMoveInSameFrame();
|
||||
};
|
||||
|
||||
void tst_seatv5::bindsToSeat()
|
||||
@ -155,10 +156,10 @@ public:
|
||||
, source(event->source())
|
||||
{
|
||||
}
|
||||
const Qt::ScrollPhase phase{};
|
||||
const QPoint pixelDelta;
|
||||
const QPoint angleDelta; // eights of a degree, positive is upwards, left
|
||||
const Qt::MouseEventSource source{};
|
||||
Qt::ScrollPhase phase{};
|
||||
QPoint pixelDelta;
|
||||
QPoint angleDelta; // eights of a degree, positive is upwards, left
|
||||
Qt::MouseEventSource source{};
|
||||
};
|
||||
QVector<Event> m_events;
|
||||
};
|
||||
@ -396,9 +397,9 @@ public:
|
||||
, touchPoints(event->touchPoints())
|
||||
{
|
||||
}
|
||||
const QEvent::Type type{};
|
||||
const Qt::TouchPointStates touchPointStates{};
|
||||
const QList<QTouchEvent::TouchPoint> touchPoints;
|
||||
QEvent::Type type{};
|
||||
Qt::TouchPointStates touchPointStates{};
|
||||
QList<QTouchEvent::TouchPoint> touchPoints;
|
||||
};
|
||||
QVector<Event> m_events;
|
||||
};
|
||||
@ -586,5 +587,37 @@ void tst_seatv5::multiTouchUpAndMotionFrame()
|
||||
QVERIFY(window.m_events.empty());
|
||||
}
|
||||
|
||||
void tst_seatv5::tapAndMoveInSameFrame()
|
||||
{
|
||||
TouchWindow window;
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
|
||||
|
||||
exec([=] {
|
||||
auto *t = touch();
|
||||
auto *c = client();
|
||||
|
||||
t->sendDown(xdgToplevel()->surface(), {32, 32}, 0);
|
||||
t->sendMotion(c, {33, 33}, 0);
|
||||
t->sendFrame(c);
|
||||
|
||||
// Don't leave touch in a weird state
|
||||
t->sendUp(c, 0);
|
||||
t->sendFrame(c);
|
||||
});
|
||||
|
||||
QTRY_VERIFY(!window.m_events.empty());
|
||||
{
|
||||
auto e = window.m_events.takeFirst();
|
||||
QCOMPARE(e.type, QEvent::TouchBegin);
|
||||
QCOMPARE(e.touchPoints.size(), 1);
|
||||
QCOMPARE(e.touchPoints[0].state(), Qt::TouchPointState::TouchPointPressed);
|
||||
// Position isn't that important, we just want to make sure we actually get the pressed event
|
||||
}
|
||||
|
||||
// Make sure we eventually release
|
||||
QTRY_VERIFY(!window.m_events.empty());
|
||||
QTRY_COMPARE(window.m_events.last().touchPoints.first().state(), Qt::TouchPointState::TouchPointReleased);
|
||||
}
|
||||
|
||||
QCOMPOSITOR_TEST_MAIN(tst_seatv5)
|
||||
#include "tst_seatv5.moc"
|
||||
|
@ -164,6 +164,16 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
class Subsurface : public QObject, public QtWaylandServer::wl_subsurface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Subsurface(wl_client *client, int id, int version)
|
||||
: QtWaylandServer::wl_subsurface(client, id, version)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class SubCompositor : public Global, public QtWaylandServer::wl_subcompositor
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -171,7 +181,20 @@ public:
|
||||
explicit SubCompositor(CoreCompositor *compositor, int version = 1)
|
||||
: QtWaylandServer::wl_subcompositor(compositor->m_display, version)
|
||||
{}
|
||||
// TODO
|
||||
QVector<Subsurface *> m_subsurfaces;
|
||||
|
||||
signals:
|
||||
void subsurfaceCreated(Subsurface *subsurface);
|
||||
|
||||
protected:
|
||||
void subcompositor_get_subsurface(Resource *resource, uint32_t id, ::wl_resource *surface, ::wl_resource *parent) override
|
||||
{
|
||||
QTRY_VERIFY(parent);
|
||||
QTRY_VERIFY(surface);
|
||||
auto *subsurface = new Subsurface(resource->client(), id, resource->version());
|
||||
m_subsurfaces.append(subsurface); // TODO: clean up?
|
||||
emit subsurfaceCreated(subsurface);
|
||||
}
|
||||
};
|
||||
|
||||
struct OutputMode {
|
||||
|
@ -52,19 +52,16 @@ DefaultCompositor::DefaultCompositor()
|
||||
// Pretend we made a copy of the buffer and just release it immediately
|
||||
surface->m_committed.buffer->send_release();
|
||||
}
|
||||
if (m_config.autoEnter && surface->m_outputs.empty())
|
||||
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, [&] (XdgToplevel *toplevel) {
|
||||
// Needed because lambdas don't support Qt::DirectConnection
|
||||
exec([&]{
|
||||
if (m_config.autoConfigure)
|
||||
toplevel->sendCompleteConfigure();
|
||||
});
|
||||
});
|
||||
QObject::connect(get<XdgWmBase>(), &XdgWmBase::toplevelCreated, get<XdgWmBase>(), [&] (XdgToplevel *toplevel) {
|
||||
if (m_config.autoConfigure)
|
||||
toplevel->sendCompleteConfigure();
|
||||
}, Qt::DirectConnection);
|
||||
}
|
||||
Q_ASSERT(isClean());
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ public:
|
||||
// Convenience functions
|
||||
Output *output(int i = 0) { return getAll<Output>().value(i, nullptr); }
|
||||
Surface *surface(int i = 0) { return get<WlCompositor>()->m_surfaces.value(i, nullptr); }
|
||||
Subsurface *subSurface(int i = 0) { return get<SubCompositor>()->m_subsurfaces.value(i, nullptr); }
|
||||
XdgSurface *xdgSurface(int i = 0) { return get<XdgWmBase>()->m_xdgSurfaces.value(i, nullptr); }
|
||||
XdgToplevel *xdgToplevel(int i = 0) { return get<XdgWmBase>()->toplevel(i); }
|
||||
XdgPopup *xdgPopup(int i = 0) { return get<XdgWmBase>()->popup(i); }
|
||||
|
@ -1,4 +1,4 @@
|
||||
QT += testlib waylandclient-private
|
||||
QT += testlib waylandclient-private opengl
|
||||
CONFIG += testcase wayland-scanner
|
||||
QMAKE_USE += wayland-server
|
||||
|
||||
|
@ -83,7 +83,7 @@ XdgSurface::XdgSurface(XdgWmBase *xdgWmBase, Surface *surface, wl_client *client
|
||||
{
|
||||
QVERIFY(!surface->m_pending.buffer);
|
||||
QVERIFY(!surface->m_committed.buffer);
|
||||
connect(this, &XdgSurface::toplevelCreated, xdgWmBase, &XdgWmBase::toplevelCreated);
|
||||
connect(this, &XdgSurface::toplevelCreated, xdgWmBase, &XdgWmBase::toplevelCreated, Qt::DirectConnection);
|
||||
connect(surface, &Surface::attach, this, &XdgSurface::verifyConfigured);
|
||||
connect(surface, &Surface::commit, this, [this] {
|
||||
m_committed = m_pending;
|
||||
|
@ -312,9 +312,9 @@ void *MockCompositor::run(void *data)
|
||||
Impl::Compositor compositor(controller);
|
||||
|
||||
controller->m_compositor = &compositor;
|
||||
controller->m_waitCondition.wakeOne();
|
||||
|
||||
while (!controller->m_ready) {
|
||||
controller->m_waitCondition.wakeOne();
|
||||
controller->dispatchCommands();
|
||||
compositor.dispatchEvents(20);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
CONFIG += testcase link_pkgconfig
|
||||
QT += testlib
|
||||
QT += core-private gui-private waylandclient-private
|
||||
QT += core-private gui-private waylandclient-private opengl
|
||||
|
||||
QMAKE_USE += wayland-client wayland-server
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "mockcompositor.h"
|
||||
#include <QtGui/QRasterWindow>
|
||||
#if QT_CONFIG(opengl)
|
||||
#include <QtGui/QOpenGLWindow>
|
||||
#include <QtOpenGL/QOpenGLWindow>
|
||||
#endif
|
||||
|
||||
using namespace MockCompositor;
|
||||
@ -45,6 +45,10 @@ private slots:
|
||||
void waitForFrameCallbackGl();
|
||||
#endif
|
||||
void negotiateShmFormat();
|
||||
|
||||
// Subsurfaces
|
||||
void createSubsurface();
|
||||
void createSubsurfaceForHiddenParent();
|
||||
};
|
||||
|
||||
void tst_surface::createDestroySurface()
|
||||
@ -160,5 +164,42 @@ void tst_surface::negotiateShmFormat()
|
||||
});
|
||||
}
|
||||
|
||||
void tst_surface::createSubsurface()
|
||||
{
|
||||
QRasterWindow window;
|
||||
window.resize(64, 64);
|
||||
window.show();
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
|
||||
exec([=] { xdgToplevel()->sendCompleteConfigure(); });
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgSurface()->m_committedConfigureSerial);
|
||||
|
||||
QRasterWindow subWindow;
|
||||
subWindow.setParent(&window);
|
||||
subWindow.resize(64, 64);
|
||||
subWindow.show();
|
||||
QCOMPOSITOR_TRY_VERIFY(subSurface());
|
||||
}
|
||||
|
||||
// Used to cause a crash in libwayland (QTBUG-79674)
|
||||
void tst_surface::createSubsurfaceForHiddenParent()
|
||||
{
|
||||
QRasterWindow window;
|
||||
window.resize(64, 64);
|
||||
window.show();
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
|
||||
exec([=] { xdgToplevel()->sendCompleteConfigure(); });
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgSurface()->m_committedConfigureSerial);
|
||||
|
||||
window.hide();
|
||||
|
||||
QRasterWindow subWindow;
|
||||
subWindow.setParent(&window);
|
||||
subWindow.resize(64, 64);
|
||||
subWindow.show();
|
||||
|
||||
// Make sure the client doesn't quit before it has a chance to crash
|
||||
xdgPingAndWaitForPong();
|
||||
}
|
||||
|
||||
QCOMPOSITOR_TEST_MAIN(tst_surface)
|
||||
#include "tst_surface.moc"
|
||||
|
7
tests/auto/wayland/tabletv2/tabletv2.pro
Normal file
7
tests/auto/wayland/tabletv2/tabletv2.pro
Normal file
@ -0,0 +1,7 @@
|
||||
include (../shared/shared.pri)
|
||||
|
||||
WAYLANDSERVERSOURCES += \
|
||||
$$PWD/../../../../src/3rdparty/protocol/tablet-unstable-v2.xml
|
||||
|
||||
TARGET = tst_tabletv2
|
||||
SOURCES += tst_tabletv2.cpp
|
918
tests/auto/wayland/tabletv2/tst_tabletv2.cpp
Normal file
918
tests/auto/wayland/tabletv2/tst_tabletv2.cpp
Normal file
@ -0,0 +1,918 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "mockcompositor.h"
|
||||
|
||||
#include <qwayland-server-tablet-unstable-v2.h>
|
||||
|
||||
#include <QtGui/QRasterWindow>
|
||||
|
||||
using namespace MockCompositor;
|
||||
|
||||
constexpr int tabletVersion = 1; // protocol VERSION, not the name suffix (_v2)
|
||||
|
||||
class TabletManagerV2;
|
||||
class TabletSeatV2;
|
||||
|
||||
class TabletV2 : public QObject, public QtWaylandServer::zwp_tablet_v2
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TabletV2(TabletSeatV2 *tabletSeat)
|
||||
: m_tabletSeat(tabletSeat)
|
||||
{
|
||||
}
|
||||
|
||||
void send_removed() = delete;
|
||||
void send_removed(struct ::wl_resource *resource) = delete;
|
||||
void sendRemoved();
|
||||
|
||||
QPointer<TabletSeatV2> m_tabletSeat; // destroy order is not guaranteed
|
||||
protected:
|
||||
void zwp_tablet_v2_destroy(Resource *resource) override;
|
||||
};
|
||||
|
||||
class TabletToolV2 : public QObject, public QtWaylandServer::zwp_tablet_tool_v2
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using ToolType = QtWaylandServer::zwp_tablet_tool_v2::type;
|
||||
explicit TabletToolV2(TabletSeatV2 *tabletSeat, ToolType toolType, quint64 hardwareSerial)
|
||||
: m_tabletSeat(tabletSeat)
|
||||
, m_toolType(toolType)
|
||||
, m_hardwareSerial(hardwareSerial)
|
||||
{
|
||||
}
|
||||
|
||||
wl_resource *toolResource() // for convenience
|
||||
{
|
||||
Q_ASSERT(resourceMap().size() == 1);
|
||||
// Strictly speaking, there may be more than one resource for the tool, for intsance if
|
||||
// if there are multiple clients, or a client has called get_tablet_seat multiple times.
|
||||
// For now we'll pretend there can only be one resource.
|
||||
return resourceMap().first()->handle;
|
||||
}
|
||||
|
||||
void send_removed() = delete;
|
||||
void send_removed(struct ::wl_resource *resource) = delete;
|
||||
void sendRemoved();
|
||||
|
||||
uint sendProximityIn(TabletV2 *tablet, Surface *surface);
|
||||
void sendProximityOut();
|
||||
void sendMotion(QPointF position)
|
||||
{
|
||||
Q_ASSERT(m_proximitySurface);
|
||||
for (auto *resource : resourceMap())
|
||||
send_motion(resource->handle, wl_fixed_from_double(position.x()), wl_fixed_from_double(position.y()));
|
||||
}
|
||||
uint sendDown();
|
||||
void sendUp() { send_up(toolResource()); }
|
||||
void sendPressure(uint pressure);
|
||||
void sendTilt(qreal tiltX, qreal tiltY) { send_tilt(toolResource(), wl_fixed_from_double(tiltX), wl_fixed_from_double(tiltY)); }
|
||||
void sendRotation(qreal rotation) { send_rotation(toolResource(), wl_fixed_from_double(rotation)); }
|
||||
uint sendButton(uint button, bool pressed);
|
||||
uint sendFrame();
|
||||
|
||||
QPointer<TabletSeatV2> m_tabletSeat; // destruction order is not guaranteed
|
||||
ToolType m_toolType = ToolType::type_pen;
|
||||
quint64 m_hardwareSerial = 0;
|
||||
QPointer<Surface> m_proximitySurface;
|
||||
protected:
|
||||
void zwp_tablet_tool_v2_destroy(Resource *resource) override;
|
||||
};
|
||||
|
||||
class TabletPadV2 : public QObject, public QtWaylandServer::zwp_tablet_pad_v2
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TabletPadV2(TabletSeatV2 *tabletSeat)
|
||||
: m_tabletSeat(tabletSeat)
|
||||
{
|
||||
}
|
||||
|
||||
void send_removed() = delete;
|
||||
void send_removed(struct ::wl_resource *resource) = delete;
|
||||
void sendRemoved();
|
||||
|
||||
QPointer<TabletSeatV2> m_tabletSeat; // destroy order is not guaranteed
|
||||
protected:
|
||||
void zwp_tablet_pad_v2_destroy(Resource *resource) override;
|
||||
};
|
||||
|
||||
class TabletSeatV2 : public QObject, public QtWaylandServer::zwp_tablet_seat_v2
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TabletSeatV2(TabletManagerV2 *manager, Seat *seat)
|
||||
: m_manager(manager)
|
||||
, m_seat(seat)
|
||||
{}
|
||||
TabletV2 *addTablet()
|
||||
{
|
||||
auto *tablet = new TabletV2(this);
|
||||
m_tablets.append(tablet);
|
||||
for (auto *resource : resourceMap())
|
||||
sendTabletAdded(resource, tablet);
|
||||
return tablet;
|
||||
}
|
||||
|
||||
void sendTabletAdded(Resource *resource, TabletV2 *tablet)
|
||||
{
|
||||
// Although, not necessarily correct, assuming just one tablet_seat per client
|
||||
auto *tabletResource = tablet->add(resource->client(), resource->version());
|
||||
zwp_tablet_seat_v2::send_tablet_added(resource->handle, tabletResource->handle);
|
||||
// TODO: send extra stuff before done?
|
||||
tablet->send_done(tabletResource->handle);
|
||||
}
|
||||
|
||||
using ToolType = QtWaylandServer::zwp_tablet_tool_v2::type;
|
||||
TabletToolV2 *addTool(ToolType toolType = ToolType::type_pen, quint64 hardwareSerial = 0)
|
||||
{
|
||||
auto *tool = new TabletToolV2(this, toolType, hardwareSerial);
|
||||
m_tools.append(tool);
|
||||
for (auto *resource : resourceMap())
|
||||
sendToolAdded(resource, tool);
|
||||
return tool;
|
||||
}
|
||||
|
||||
void sendToolAdded(Resource *resource, TabletToolV2 *tool)
|
||||
{
|
||||
// Although, not necessarily correct, assuming just one tablet_seat per client
|
||||
auto *toolResource = tool->add(resource->client(), resource->version())->handle;
|
||||
zwp_tablet_seat_v2::send_tool_added(resource->handle, toolResource);
|
||||
tool->send_type(toolResource, tool->m_toolType);
|
||||
if (tool->m_hardwareSerial) {
|
||||
const uint hi = tool->m_hardwareSerial >> 32;
|
||||
const uint lo = tool->m_hardwareSerial & 0xffffffff;
|
||||
tool->send_hardware_serial(toolResource, hi, lo);
|
||||
}
|
||||
tool->send_done(toolResource);
|
||||
}
|
||||
|
||||
TabletPadV2 *addPad()
|
||||
{
|
||||
auto *pad = new TabletPadV2(this);
|
||||
m_pads.append(pad);
|
||||
for (auto *resource : resourceMap())
|
||||
sendPadAdded(resource, pad);
|
||||
return pad;
|
||||
}
|
||||
|
||||
void sendPadAdded(Resource *resource, TabletPadV2 *pad)
|
||||
{
|
||||
// Although, not necessarily correct, assuming just one tablet_seat per client
|
||||
auto *padResource = pad->add(resource->client(), resource->version())->handle;
|
||||
zwp_tablet_seat_v2::send_pad_added(resource->handle, padResource);
|
||||
pad->send_done(padResource);
|
||||
}
|
||||
|
||||
void removeAll()
|
||||
{
|
||||
const auto tools = m_tools;
|
||||
for (auto *tool : tools)
|
||||
tool->sendRemoved();
|
||||
|
||||
const auto tablets = m_tablets;
|
||||
for (auto *tablet : tablets)
|
||||
tablet->sendRemoved();
|
||||
|
||||
const auto pads = m_pads;
|
||||
for (auto *pad : pads)
|
||||
pad->sendRemoved();
|
||||
}
|
||||
|
||||
TabletManagerV2 *m_manager = nullptr;
|
||||
Seat *m_seat = nullptr;
|
||||
QVector<TabletV2 *> m_tablets;
|
||||
QVector<TabletV2 *> m_tabletsWaitingForDestroy;
|
||||
QVector<TabletToolV2 *> m_tools;
|
||||
QVector<TabletToolV2 *> m_toolsWaitingForDestroy;
|
||||
QVector<TabletPadV2 *> m_pads;
|
||||
QVector<TabletPadV2 *> m_padsWaitingForDestroy;
|
||||
|
||||
protected:
|
||||
void zwp_tablet_seat_v2_bind_resource(Resource *resource)
|
||||
{
|
||||
for (auto *tablet : m_tablets)
|
||||
sendTabletAdded(resource, tablet);
|
||||
for (auto *tool : m_tools)
|
||||
sendToolAdded(resource, tool);
|
||||
for (auto *pad : m_pads)
|
||||
sendPadAdded(resource, pad);
|
||||
}
|
||||
};
|
||||
|
||||
class TabletManagerV2 : public Global, public QtWaylandServer::zwp_tablet_manager_v2
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TabletManagerV2(CoreCompositor *compositor, int version = 1)
|
||||
: QtWaylandServer::zwp_tablet_manager_v2(compositor->m_display, version)
|
||||
, m_version(version)
|
||||
{}
|
||||
bool isClean() override
|
||||
{
|
||||
for (auto *seat : m_tabletSeats) {
|
||||
if (!seat->m_tabletsWaitingForDestroy.empty())
|
||||
return false;
|
||||
if (!seat->m_toolsWaitingForDestroy.empty())
|
||||
return false;
|
||||
if (!seat->m_padsWaitingForDestroy.empty())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TabletSeatV2 *tabletSeatFor(Seat *seat)
|
||||
{
|
||||
Q_ASSERT(seat);
|
||||
if (auto *tabletSeat = m_tabletSeats.value(seat, nullptr))
|
||||
return tabletSeat;
|
||||
|
||||
auto *tabletSeat = new TabletSeatV2(this, seat);
|
||||
m_tabletSeats[seat] = tabletSeat;
|
||||
return tabletSeat;
|
||||
}
|
||||
|
||||
int m_version = 1; // TODO: Remove on libwayland upgrade
|
||||
QMap<Seat *, TabletSeatV2 *> m_tabletSeats;
|
||||
|
||||
protected:
|
||||
void zwp_tablet_manager_v2_destroy(Resource *resource) override
|
||||
{
|
||||
// tablet_seats created from this object are unaffected and should be destroyed separately.
|
||||
wl_resource_destroy(resource->handle);
|
||||
}
|
||||
|
||||
void zwp_tablet_manager_v2_get_tablet_seat(Resource *resource, uint32_t id, ::wl_resource *seatResource) override
|
||||
{
|
||||
auto *seat = fromResource<Seat>(seatResource);
|
||||
QVERIFY(seat);
|
||||
auto *tabletSeat = tabletSeatFor(seat);
|
||||
tabletSeat->add(resource->client(), id, resource->version());
|
||||
}
|
||||
};
|
||||
|
||||
void TabletV2::sendRemoved()
|
||||
{
|
||||
for (auto *resource : resourceMap())
|
||||
zwp_tablet_v2_send_removed(resource->handle);
|
||||
bool removed = m_tabletSeat->m_tablets.removeOne(this);
|
||||
QVERIFY(removed);
|
||||
m_tabletSeat->m_tabletsWaitingForDestroy.append(this);
|
||||
}
|
||||
|
||||
void TabletV2::zwp_tablet_v2_destroy(QtWaylandServer::zwp_tablet_v2::Resource *resource)
|
||||
{
|
||||
Q_UNUSED(resource)
|
||||
if (m_tabletSeat) {
|
||||
bool removed = m_tabletSeat->m_tabletsWaitingForDestroy.removeOne(this);
|
||||
QVERIFY(removed);
|
||||
}
|
||||
wl_resource_destroy(resource->handle);
|
||||
}
|
||||
|
||||
void TabletToolV2::sendRemoved()
|
||||
{
|
||||
for (auto *resource : resourceMap())
|
||||
zwp_tablet_tool_v2_send_removed(resource->handle);
|
||||
bool removed = m_tabletSeat->m_tools.removeOne(this);
|
||||
QVERIFY(removed);
|
||||
m_tabletSeat->m_toolsWaitingForDestroy.append(this);
|
||||
}
|
||||
|
||||
uint TabletToolV2::sendProximityIn(TabletV2 *tablet, Surface *surface)
|
||||
{
|
||||
Q_ASSERT(!m_proximitySurface);
|
||||
m_proximitySurface = surface;
|
||||
uint serial = m_tabletSeat->m_seat->m_compositor->nextSerial();
|
||||
auto *client = surface->resource()->client();
|
||||
auto tabletResource = tablet->resourceMap().value(client)->handle;
|
||||
send_proximity_in(toolResource(), serial, tabletResource, surface->resource()->handle);
|
||||
return serial;
|
||||
}
|
||||
|
||||
void TabletToolV2::sendProximityOut()
|
||||
{
|
||||
Q_ASSERT(m_proximitySurface);
|
||||
send_proximity_out(toolResource());
|
||||
m_proximitySurface = nullptr;
|
||||
}
|
||||
|
||||
uint TabletToolV2::sendDown()
|
||||
{
|
||||
uint serial = m_tabletSeat->m_seat->m_compositor->nextSerial();
|
||||
send_down(toolResource(), serial);
|
||||
return serial;
|
||||
}
|
||||
|
||||
void TabletToolV2::sendPressure(uint pressure)
|
||||
{
|
||||
Q_ASSERT(m_proximitySurface);
|
||||
auto *client = m_proximitySurface->resource()->client();
|
||||
auto toolResource = resourceMap().value(client)->handle;
|
||||
send_pressure(toolResource, pressure);
|
||||
}
|
||||
|
||||
uint TabletToolV2::sendButton(uint button, bool pressed)
|
||||
{
|
||||
button_state state = pressed ? button_state_pressed : button_state_released;
|
||||
uint serial = m_tabletSeat->m_seat->m_compositor->nextSerial();
|
||||
send_button(toolResource(), serial, button, state);
|
||||
return serial;
|
||||
}
|
||||
|
||||
uint TabletToolV2::sendFrame()
|
||||
{
|
||||
uint time = m_tabletSeat->m_seat->m_compositor->currentTimeMilliseconds();
|
||||
for (auto *resource : resourceMap())
|
||||
send_frame(resource->handle, time);
|
||||
return time;
|
||||
}
|
||||
|
||||
void TabletToolV2::zwp_tablet_tool_v2_destroy(QtWaylandServer::zwp_tablet_tool_v2::Resource *resource)
|
||||
{
|
||||
if (m_tabletSeat) {
|
||||
bool removed = m_tabletSeat->m_toolsWaitingForDestroy.removeOne(this);
|
||||
QVERIFY(removed);
|
||||
}
|
||||
wl_resource_destroy(resource->handle);
|
||||
}
|
||||
|
||||
void TabletPadV2::sendRemoved()
|
||||
{
|
||||
for (auto *resource : resourceMap())
|
||||
zwp_tablet_pad_v2_send_removed(resource->handle);
|
||||
bool removed = m_tabletSeat->m_pads.removeOne(this);
|
||||
QVERIFY(removed);
|
||||
m_tabletSeat->m_padsWaitingForDestroy.append(this);
|
||||
}
|
||||
|
||||
void TabletPadV2::zwp_tablet_pad_v2_destroy(QtWaylandServer::zwp_tablet_pad_v2::Resource *resource)
|
||||
{
|
||||
if (m_tabletSeat) {
|
||||
bool removed = m_tabletSeat->m_padsWaitingForDestroy.removeOne(this);
|
||||
QVERIFY(removed);
|
||||
}
|
||||
wl_resource_destroy(resource->handle);
|
||||
}
|
||||
|
||||
class TabletCompositor : public DefaultCompositor {
|
||||
public:
|
||||
explicit TabletCompositor()
|
||||
{
|
||||
exec([this] {
|
||||
m_config.autoConfigure = true;
|
||||
add<TabletManagerV2>(tabletVersion);
|
||||
});
|
||||
}
|
||||
TabletSeatV2 *tabletSeat(int i = 0)
|
||||
{
|
||||
return get<TabletManagerV2>()->tabletSeatFor(get<Seat>(i));
|
||||
}
|
||||
TabletV2 *tablet(int i = 0, int iSeat = 0)
|
||||
{
|
||||
if (auto *ts = tabletSeat(iSeat))
|
||||
return ts->m_tablets.value(i, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
TabletToolV2 *tabletTool(int i = 0, int iSeat = 0)
|
||||
{
|
||||
if (auto *ts = tabletSeat(iSeat))
|
||||
return ts->m_tools.value(i, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
TabletPadV2 *tabletPad(int i = 0, int iSeat = 0)
|
||||
{
|
||||
if (auto *ts = tabletSeat(iSeat))
|
||||
return ts->m_pads.value(i, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(QtWaylandServer::zwp_tablet_tool_v2::type);
|
||||
Q_DECLARE_METATYPE(QTabletEvent::PointerType);
|
||||
Q_DECLARE_METATYPE(Qt::MouseButton);
|
||||
|
||||
class tst_tabletv2 : public QObject, private TabletCompositor
|
||||
{
|
||||
using ToolType = QtWaylandServer::zwp_tablet_tool_v2::type;
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void cleanup();
|
||||
void bindsToManager();
|
||||
void createsTabletSeat();
|
||||
void destroysTablet();
|
||||
void destroysTool();
|
||||
void destroysPad();
|
||||
void proximityEvents();
|
||||
void moveEvent();
|
||||
void pointerType_data();
|
||||
void pointerType();
|
||||
void hardwareSerial();
|
||||
void buttons_data();
|
||||
void buttons();
|
||||
void tabletEvents();
|
||||
};
|
||||
|
||||
class ProximityFilter : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ProximityFilter() { qApp->installEventFilter(this); }
|
||||
~ProximityFilter() override { qDeleteAll(m_events); }
|
||||
QVector<QTabletEvent *> m_events;
|
||||
|
||||
int nextEventIndex = 0;
|
||||
int numEvents() const { return m_events.size() - nextEventIndex; }
|
||||
QTabletEvent *popEvent()
|
||||
{
|
||||
auto *event = m_events.value(nextEventIndex, nullptr);
|
||||
if (event)
|
||||
++nextEventIndex;
|
||||
return event;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *object, QEvent *event) override
|
||||
{
|
||||
Q_UNUSED(object);
|
||||
switch (event->type()) {
|
||||
case QEvent::TabletEnterProximity:
|
||||
case QEvent::TabletLeaveProximity: {
|
||||
auto *e = static_cast<QTabletEvent *>(event);
|
||||
auto *ev = new QTabletEvent(e->type(), e->posF(), e->globalPosF(), e->deviceType(),
|
||||
e->pointerType(), e->pressure(), e->xTilt(), e->yTilt(),
|
||||
e->tangentialPressure(), e->rotation(), e->z(),
|
||||
Qt::KeyboardModifier::NoModifier, e->uniqueId(),
|
||||
e->button(), e->buttons());
|
||||
m_events << ev;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void tst_tabletv2::cleanup()
|
||||
{
|
||||
exec([&] {
|
||||
tabletSeat()->removeAll();
|
||||
});
|
||||
QCOMPOSITOR_COMPARE(get<TabletManagerV2>()->m_tabletSeats.size(), 1);
|
||||
QCOMPOSITOR_COMPARE(tabletSeat()->m_tablets.size(), 0);
|
||||
QCOMPOSITOR_COMPARE(tabletSeat()->m_tools.size(), 0);
|
||||
QCOMPOSITOR_COMPARE(tabletSeat()->m_pads.size(), 0);
|
||||
|
||||
QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage()));
|
||||
}
|
||||
|
||||
void tst_tabletv2::bindsToManager()
|
||||
{
|
||||
QCOMPOSITOR_TRY_COMPARE(get<TabletManagerV2>()->resourceMap().size(), 1);
|
||||
QCOMPOSITOR_TRY_COMPARE(get<TabletManagerV2>()->resourceMap().first()->version(), tabletVersion);
|
||||
}
|
||||
|
||||
void tst_tabletv2::createsTabletSeat()
|
||||
{
|
||||
QCOMPOSITOR_TRY_VERIFY(tabletSeat());
|
||||
QCOMPOSITOR_TRY_VERIFY(tabletSeat()->resourceMap().contains(client()));
|
||||
QCOMPOSITOR_TRY_COMPARE(tabletSeat()->resourceMap().value(client())->version(), tabletVersion);
|
||||
//TODO: Maybe also assert some capability reported though qt APIs?
|
||||
}
|
||||
|
||||
void tst_tabletv2::destroysTablet()
|
||||
{
|
||||
QCOMPOSITOR_TRY_VERIFY(tabletSeat());
|
||||
exec([&] {
|
||||
tabletSeat()->addTablet();
|
||||
});
|
||||
QCOMPOSITOR_TRY_VERIFY(tablet());
|
||||
|
||||
exec([&] {
|
||||
tablet()->sendRemoved();
|
||||
});
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(!tablet());
|
||||
QCOMPOSITOR_TRY_VERIFY(tabletSeat()->m_tabletsWaitingForDestroy.empty());
|
||||
}
|
||||
|
||||
void tst_tabletv2::destroysTool()
|
||||
{
|
||||
QCOMPOSITOR_TRY_VERIFY(tabletSeat());
|
||||
exec([&] {
|
||||
tabletSeat()->addTool();
|
||||
});
|
||||
QCOMPOSITOR_TRY_VERIFY(tabletTool());
|
||||
|
||||
exec([&] {
|
||||
tabletTool()->sendRemoved();
|
||||
});
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(!tabletTool());
|
||||
QCOMPOSITOR_TRY_VERIFY(tabletSeat()->m_toolsWaitingForDestroy.empty());
|
||||
}
|
||||
|
||||
void tst_tabletv2::destroysPad()
|
||||
{
|
||||
QCOMPOSITOR_TRY_VERIFY(tabletSeat());
|
||||
exec([&] {
|
||||
tabletSeat()->addPad();
|
||||
});
|
||||
QCOMPOSITOR_TRY_VERIFY(tabletPad());
|
||||
|
||||
exec([&] {
|
||||
tabletPad()->sendRemoved();
|
||||
});
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(!tabletPad());
|
||||
QCOMPOSITOR_TRY_VERIFY(tabletSeat()->m_padsWaitingForDestroy.empty());
|
||||
}
|
||||
|
||||
void tst_tabletv2::proximityEvents()
|
||||
{
|
||||
ProximityFilter filter;
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(tabletSeat());
|
||||
exec([&] {
|
||||
tabletSeat()->addTablet();
|
||||
tabletSeat()->addTool();
|
||||
});
|
||||
|
||||
QRasterWindow window;
|
||||
window.resize(64, 64);
|
||||
window.show();
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(tablet());
|
||||
exec([&] {
|
||||
auto *surface = xdgSurface()->m_surface;
|
||||
auto *tool = tabletTool();
|
||||
tool->sendProximityIn(tablet(), surface);
|
||||
tool->sendFrame();
|
||||
});
|
||||
|
||||
QTRY_COMPARE(filter.numEvents(), 1);
|
||||
QTabletEvent *enterEvent = filter.popEvent();
|
||||
QCOMPARE(enterEvent->type(), QEvent::TabletEnterProximity);
|
||||
|
||||
exec([&] {
|
||||
auto *tool = tabletTool();
|
||||
tool->sendProximityOut();
|
||||
tool->sendFrame();
|
||||
});
|
||||
|
||||
QTRY_COMPARE(filter.numEvents(), 1);
|
||||
QTabletEvent *leaveEvent = filter.popEvent();
|
||||
QCOMPARE(leaveEvent->type(), QEvent::TabletLeaveProximity);
|
||||
}
|
||||
|
||||
class TabletWindow : public QRasterWindow {
|
||||
Q_OBJECT
|
||||
public:
|
||||
~TabletWindow() override { qDeleteAll(m_events); }
|
||||
|
||||
void tabletEvent(QTabletEvent *e) override
|
||||
{
|
||||
m_events << new QTabletEvent(e->type(), e->posF(), e->globalPosF(), e->deviceType(),
|
||||
e->pointerType(), e->pressure(), e->xTilt(), e->yTilt(),
|
||||
e->tangentialPressure(), e->rotation(), e->z(),
|
||||
Qt::KeyboardModifier::NoModifier, e->uniqueId(), e->button(),
|
||||
e->buttons());
|
||||
emit tabletEventReceived(m_events.last());
|
||||
}
|
||||
int nextEventIndex = 0;
|
||||
int numEvents() const { return m_events.size() - nextEventIndex; }
|
||||
QTabletEvent *popEvent()
|
||||
{
|
||||
auto *event = m_events.value(nextEventIndex, nullptr);
|
||||
if (event)
|
||||
++nextEventIndex;
|
||||
return event;
|
||||
}
|
||||
|
||||
signals:
|
||||
void tabletEventReceived(QTabletEvent *event);
|
||||
|
||||
private:
|
||||
QVector<QTabletEvent *> m_events;
|
||||
};
|
||||
|
||||
void tst_tabletv2::moveEvent()
|
||||
{
|
||||
QCOMPOSITOR_TRY_VERIFY(tabletSeat());
|
||||
exec([&] {
|
||||
tabletSeat()->addTablet();
|
||||
tabletSeat()->addTool();
|
||||
});
|
||||
|
||||
TabletWindow window;
|
||||
window.resize(64, 64);
|
||||
window.show();
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(tablet());
|
||||
exec([&] {
|
||||
auto *surface = xdgSurface()->m_surface;
|
||||
auto *tool = tabletTool();
|
||||
tool->sendProximityIn(tablet(), surface);
|
||||
QMargins margins = window.frameMargins();
|
||||
tool->sendMotion(QPointF(12 + margins.left(), 34 + margins.top()));
|
||||
tool->sendFrame();
|
||||
});
|
||||
QTRY_VERIFY(window.numEvents());
|
||||
QTabletEvent *event = window.popEvent();
|
||||
QCOMPARE(event->type(), QEvent::TabletMove);
|
||||
QCOMPARE(event->pressure(), 0);
|
||||
QCOMPARE(event->posF(), QPointF(12, 34));
|
||||
}
|
||||
|
||||
void tst_tabletv2::pointerType_data()
|
||||
{
|
||||
QTest::addColumn<ToolType>("toolType");
|
||||
QTest::addColumn<QTabletEvent::PointerType>("pointerType");
|
||||
QTest::addColumn<QTabletEvent::TabletDevice>("tabletDevice");
|
||||
|
||||
QTest::newRow("pen") << ToolType::type_pen << QTabletEvent::PointerType::Pen << QTabletEvent::TabletDevice::Stylus;
|
||||
QTest::newRow("eraser") << ToolType::type_eraser << QTabletEvent::PointerType::Eraser << QTabletEvent::TabletDevice::Stylus;
|
||||
QTest::newRow("pencil") << ToolType::type_pencil << QTabletEvent::PointerType::Pen << QTabletEvent::TabletDevice::Stylus;
|
||||
QTest::newRow("airbrush") << ToolType::type_airbrush << QTabletEvent::PointerType::Pen << QTabletEvent::TabletDevice::Airbrush;
|
||||
QTest::newRow("brush") << ToolType::type_brush << QTabletEvent::PointerType::Pen << QTabletEvent::TabletDevice::Stylus; // TODO: is TabletDevice::Stylus the right thing?
|
||||
QTest::newRow("lens") << ToolType::type_lens << QTabletEvent::PointerType::Cursor << QTabletEvent::TabletDevice::Puck;
|
||||
// TODO: also add tests for FourDMouse and RotationStylus (also need to send capabilities)
|
||||
|
||||
// TODO: should these rather be mapped to touch/mouse events?
|
||||
QTest::newRow("finger") << ToolType::type_finger << QTabletEvent::PointerType::UnknownPointer << QTabletEvent::TabletDevice::NoDevice;
|
||||
QTest::newRow("mouse") << ToolType::type_mouse << QTabletEvent::PointerType::Cursor << QTabletEvent::TabletDevice::NoDevice;
|
||||
}
|
||||
|
||||
void tst_tabletv2::pointerType()
|
||||
{
|
||||
using ToolType = QtWaylandServer::zwp_tablet_tool_v2::type;
|
||||
QFETCH(ToolType, toolType);
|
||||
QFETCH(QTabletEvent::PointerType, pointerType);
|
||||
QFETCH(QTabletEvent::TabletDevice, tabletDevice);
|
||||
|
||||
ProximityFilter filter;
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(tabletSeat());
|
||||
exec([&] {
|
||||
tabletSeat()->addTablet();
|
||||
tabletSeat()->addTool(toolType);
|
||||
});
|
||||
|
||||
TabletWindow window;
|
||||
window.resize(64, 64);
|
||||
window.show();
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(tablet());
|
||||
exec([&] {
|
||||
auto *surface = xdgSurface()->m_surface;
|
||||
auto *tool = tabletTool();
|
||||
tool->sendProximityIn(tablet(), surface);
|
||||
QMargins margins = window.frameMargins();
|
||||
tool->sendMotion(QPointF(12 + margins.left(), 34 + margins.top()));
|
||||
tool->sendFrame();
|
||||
});
|
||||
|
||||
QTRY_COMPARE(filter.numEvents(), 1);
|
||||
QTabletEvent *event = filter.popEvent();
|
||||
QCOMPARE(event->pointerType(), pointerType);
|
||||
QCOMPARE(event->deviceType(), tabletDevice);
|
||||
|
||||
QTRY_VERIFY(window.numEvents());
|
||||
event = window.popEvent();
|
||||
QCOMPARE(event->pointerType(), pointerType);
|
||||
QCOMPARE(event->deviceType(), tabletDevice);
|
||||
|
||||
exec([&] {
|
||||
tabletTool()->sendProximityOut();
|
||||
tabletTool()->sendFrame();
|
||||
});
|
||||
|
||||
QTRY_VERIFY(filter.numEvents());
|
||||
event = filter.popEvent();
|
||||
QCOMPARE(event->pointerType(), pointerType);
|
||||
QCOMPARE(event->deviceType(), tabletDevice);
|
||||
}
|
||||
|
||||
void tst_tabletv2::hardwareSerial()
|
||||
{
|
||||
ProximityFilter filter;
|
||||
const quint64 uid = 0xbaba15dead15f00d;
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(tabletSeat());
|
||||
exec([&] {
|
||||
tabletSeat()->addTablet();
|
||||
tabletSeat()->addTool(ToolType::type_pen, uid);
|
||||
});
|
||||
|
||||
TabletWindow window;
|
||||
window.resize(64, 64);
|
||||
window.show();
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(tablet());
|
||||
exec([&] {
|
||||
auto *surface = xdgSurface()->m_surface;
|
||||
auto *tool = tabletTool();
|
||||
tool->sendProximityIn(tablet(), surface);
|
||||
QMargins margins = window.frameMargins();
|
||||
tool->sendMotion(QPointF(12 + margins.left(), 34 + margins.top()));
|
||||
tool->sendFrame();
|
||||
});
|
||||
|
||||
QTRY_COMPARE(filter.numEvents(), 1);
|
||||
QTabletEvent *event = filter.popEvent();
|
||||
QCOMPARE(event->uniqueId(), uid);
|
||||
|
||||
QTRY_VERIFY(window.numEvents());
|
||||
event = window.popEvent();
|
||||
QCOMPARE(event->uniqueId(), uid);
|
||||
|
||||
exec([&] {
|
||||
tabletTool()->sendProximityOut();
|
||||
tabletTool()->sendFrame();
|
||||
});
|
||||
|
||||
QTRY_VERIFY(filter.numEvents());
|
||||
event = filter.popEvent();
|
||||
QCOMPARE(event->uniqueId(), uid);
|
||||
}
|
||||
|
||||
// As defined in linux/input-event-codes.h
|
||||
#ifndef BTN_STYLUS
|
||||
#define BTN_STYLUS 0x14b
|
||||
#endif
|
||||
#ifndef BTN_STYLUS2
|
||||
#define BTN_STYLUS2 0x14c
|
||||
#endif
|
||||
|
||||
void tst_tabletv2::buttons_data()
|
||||
{
|
||||
QTest::addColumn<uint>("tabletButton");
|
||||
QTest::addColumn<Qt::MouseButton>("mouseButton");
|
||||
|
||||
QTest::newRow("BTN_STYLUS2") << uint(BTN_STYLUS2) << Qt::MouseButton::RightButton;
|
||||
QTest::newRow("BTN_STYLUS") << uint(BTN_STYLUS) << Qt::MouseButton::MiddleButton;
|
||||
}
|
||||
|
||||
void tst_tabletv2::buttons()
|
||||
{
|
||||
QFETCH(uint, tabletButton);
|
||||
QFETCH(Qt::MouseButton, mouseButton);
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(tabletSeat());
|
||||
exec([&] {
|
||||
tabletSeat()->addTablet();
|
||||
tabletSeat()->addTool();
|
||||
});
|
||||
|
||||
TabletWindow window;
|
||||
window.resize(64, 64);
|
||||
window.show();
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(tablet());
|
||||
exec([&] {
|
||||
tabletTool()->sendProximityIn(tablet(), xdgSurface()->m_surface);
|
||||
QMargins margins = window.frameMargins();
|
||||
tabletTool()->sendMotion(QPointF(12 + margins.left(), 34 + margins.top()));
|
||||
tabletTool()->sendFrame();
|
||||
});
|
||||
|
||||
QTRY_VERIFY(window.numEvents());
|
||||
window.popEvent();
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(tablet());
|
||||
exec([&] {
|
||||
tabletTool()->sendButton(tabletButton, true);
|
||||
tabletTool()->sendFrame();
|
||||
tabletTool()->sendButton(tabletButton, false);
|
||||
tabletTool()->sendFrame();
|
||||
});
|
||||
|
||||
QTRY_VERIFY(window.numEvents());
|
||||
QTabletEvent *event = window.popEvent();
|
||||
QCOMPARE(event->buttons(), mouseButton);
|
||||
|
||||
exec([&] {
|
||||
tabletTool()->sendProximityOut();
|
||||
tabletTool()->sendFrame();
|
||||
});
|
||||
}
|
||||
|
||||
void tst_tabletv2::tabletEvents()
|
||||
{
|
||||
QCOMPOSITOR_TRY_VERIFY(tabletSeat());
|
||||
exec([&] {
|
||||
tabletSeat()->addTablet();
|
||||
tabletSeat()->addTool();
|
||||
});
|
||||
|
||||
TabletWindow window;
|
||||
window.resize(64, 64);
|
||||
window.show();
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
|
||||
|
||||
const QPointF insideDecorations(window.frameMargins().left(), window.frameMargins().top());
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(tablet());
|
||||
exec([&] {
|
||||
auto *surface = xdgSurface()->m_surface;
|
||||
auto *tool = tabletTool();
|
||||
// TODO: encapsulate this into a helper function?
|
||||
tool->sendProximityIn(tablet(), surface);
|
||||
tool->sendMotion(QPointF(12, 34) + insideDecorations);
|
||||
tool->sendDown();
|
||||
tool->sendPressure(65535);
|
||||
tool->sendFrame();
|
||||
});
|
||||
|
||||
QTRY_VERIFY(window.numEvents());
|
||||
QTabletEvent *event = window.popEvent();
|
||||
QCOMPARE(event->type(), QEvent::TabletPress);
|
||||
QCOMPARE(event->pressure(), 1.0);
|
||||
QCOMPARE(event->posF(), QPointF(12, 34));
|
||||
|
||||
// Values we didn't send should be 0
|
||||
QCOMPARE(event->rotation(), 0);
|
||||
QCOMPARE(event->xTilt(), 0);
|
||||
QCOMPARE(event->yTilt(), 0);
|
||||
|
||||
exec([&] {
|
||||
tabletTool()->sendMotion(QPointF(45, 56) + insideDecorations);
|
||||
tabletTool()->sendPressure(65535/2);
|
||||
tabletTool()->sendRotation(90);
|
||||
tabletTool()->sendTilt(13, 37);
|
||||
tabletTool()->sendFrame();
|
||||
});
|
||||
|
||||
QTRY_VERIFY(window.numEvents());
|
||||
event = window.popEvent();
|
||||
QCOMPARE(event->type(), QEvent::TabletMove);
|
||||
QVERIFY(qAbs(event->pressure() - 0.5) < 0.01);
|
||||
QVERIFY(qAbs(event->rotation() - 90) < 0.01);
|
||||
QVERIFY(qAbs(event->xTilt() - 13) < 0.01);
|
||||
QVERIFY(qAbs(event->yTilt() - 37) < 0.01);
|
||||
QCOMPARE(event->posF(), QPointF(45, 56));
|
||||
|
||||
// Verify that the values stay the same if we don't update them
|
||||
exec([&] {
|
||||
tabletTool()->sendMotion(QPointF(10, 11) + insideDecorations); // Change position only
|
||||
tabletTool()->sendFrame();
|
||||
});
|
||||
QTRY_VERIFY(window.numEvents());
|
||||
event = window.popEvent();
|
||||
QCOMPARE(event->type(), QEvent::TabletMove);
|
||||
QVERIFY(qAbs(event->pressure() - 0.5) < 0.01);
|
||||
QVERIFY(qAbs(event->rotation() - 90) < 0.01);
|
||||
QVERIFY(qAbs(event->xTilt() - 13) < 0.01);
|
||||
QVERIFY(qAbs(event->yTilt() - 37) < 0.01);
|
||||
QCOMPARE(event->posF(), QPointF(10, 11));
|
||||
|
||||
exec([&] {
|
||||
tabletTool()->sendPressure(0);
|
||||
tabletTool()->sendUp();
|
||||
tabletTool()->sendFrame();
|
||||
|
||||
tabletTool()->sendProximityOut();
|
||||
tabletTool()->sendFrame();
|
||||
});
|
||||
|
||||
QTRY_VERIFY(window.numEvents());
|
||||
event = window.popEvent();
|
||||
QCOMPARE(event->type(), QEvent::TabletRelease);
|
||||
QCOMPARE(event->pressure(), 0);
|
||||
QCOMPARE(event->posF(), QPointF(10, 11));
|
||||
}
|
||||
|
||||
QCOMPOSITOR_TEST_MAIN(tst_tabletv2)
|
||||
#include "tst_tabletv2.moc"
|
@ -30,8 +30,8 @@
|
||||
|
||||
#include <qwayland-server-xdg-decoration-unstable-v1.h>
|
||||
|
||||
#include <QtOpenGL/QOpenGLWindow>
|
||||
#include <QtGui/QRasterWindow>
|
||||
#include <QtGui/QOpenGLWindow>
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtCore/private/qcore_unix_p.h>
|
||||
|
||||
|
@ -27,8 +27,8 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "mockcompositor.h"
|
||||
#include <QtOpenGL/QOpenGLWindow>
|
||||
#include <QtGui/QRasterWindow>
|
||||
#include <QtGui/QOpenGLWindow>
|
||||
#include <QtGui/QScreen>
|
||||
|
||||
#include <qwayland-server-xdg-output-unstable-v1.h>
|
||||
|
@ -27,8 +27,8 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "mockcompositor.h"
|
||||
#include <QtOpenGL/QOpenGLWindow>
|
||||
#include <QtGui/QRasterWindow>
|
||||
#include <QtGui/QOpenGLWindow>
|
||||
#include <QtGui/qpa/qplatformnativeinterface.h>
|
||||
#include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
|
||||
|
||||
@ -46,6 +46,7 @@ private slots:
|
||||
void popup();
|
||||
void tooltipOnPopup();
|
||||
void switchPopups();
|
||||
void hidePopupParent();
|
||||
void pongs();
|
||||
void minMaxSize();
|
||||
void windowGeometry();
|
||||
@ -219,8 +220,8 @@ void tst_xdgshell::popup()
|
||||
p->sendFrame(c);
|
||||
uint serial = p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
|
||||
p->sendButton(c, BTN_LEFT, Pointer::button_state_released);
|
||||
return serial;
|
||||
p->sendFrame(c);
|
||||
return serial;
|
||||
});
|
||||
|
||||
QTRY_VERIFY(window.m_popup);
|
||||
@ -429,6 +430,50 @@ void tst_xdgshell::switchPopups()
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_xdgSurface->m_committedConfigureSerial);
|
||||
}
|
||||
|
||||
void tst_xdgshell::hidePopupParent()
|
||||
{
|
||||
class Window : public QRasterWindow {
|
||||
public:
|
||||
void mousePressEvent(QMouseEvent *event) override
|
||||
{
|
||||
QRasterWindow::mousePressEvent(event);
|
||||
m_popup.reset(new QRasterWindow);
|
||||
m_popup->setTransientParent(this);
|
||||
m_popup->setFlags(Qt::Popup);
|
||||
m_popup->resize(100, 100);
|
||||
m_popup->show();
|
||||
}
|
||||
QScopedPointer<QRasterWindow> m_popup;
|
||||
};
|
||||
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(c, BTN_LEFT, Pointer::button_state_pressed);
|
||||
p->sendButton(c, BTN_LEFT, Pointer::button_state_released);
|
||||
p->sendFrame(c);
|
||||
});
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgPopup());
|
||||
exec([=] {
|
||||
xdgPopup()->sendConfigure(QRect(100, 100, 100, 100));
|
||||
xdgPopup()->m_xdgSurface->sendConfigure();
|
||||
});
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgPopup()->m_xdgSurface->m_committedConfigureSerial);
|
||||
|
||||
window.hide();
|
||||
QCOMPOSITOR_TRY_VERIFY(!xdgToplevel());
|
||||
}
|
||||
|
||||
void tst_xdgshell::pongs()
|
||||
{
|
||||
// Create and show a window to trigger shell integration initialzation,
|
||||
|
@ -403,7 +403,7 @@ void tst_WaylandClientXdgShellV6::flushUnconfiguredXdgSurface()
|
||||
m_compositor->sendShellSurfaceConfigure(surface);
|
||||
QTRY_COMPARE(surface->image.size(), window.frameGeometry().size());
|
||||
QTRY_COMPARE(surface->image.pixel(window.frameMargins().left(), window.frameMargins().top()), color.rgba());
|
||||
QVERIFY(window.isExposed());
|
||||
QTRY_VERIFY(window.isExposed());
|
||||
}
|
||||
|
||||
void tst_WaylandClientXdgShellV6::dontSpamExposeEvents()
|
||||
|
Loading…
x
Reference in New Issue
Block a user