diff options
Diffstat (limited to 'src')
55 files changed, 2619 insertions, 191 deletions
diff --git a/src/3rdparty/protocol/qt_attribution.json b/src/3rdparty/protocol/qt_attribution.json index c49ead4f3..dad8c4256 100644 --- a/src/3rdparty/protocol/qt_attribution.json +++ b/src/3rdparty/protocol/qt_attribution.json @@ -90,6 +90,24 @@ Copyright (c) 2013 BMW Car IT GmbH" }, { + "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", "QDocModule": "qtwaylandcompositor", diff --git a/src/3rdparty/protocol/tablet-unstable-v2.xml b/src/3rdparty/protocol/tablet-unstable-v2.xml new file mode 100644 index 000000000..b286d964a --- /dev/null +++ b/src/3rdparty/protocol/tablet-unstable-v2.xml @@ -0,0 +1,1178 @@ +<?xml version="1.0" encoding="UTF-8"?> +<protocol name="tablet_unstable_v2"> + + <copyright> + Copyright 2014 © Stephen "Lyude" Chandler Paul + Copyright 2015-2016 © Red Hat, Inc. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice (including the + next paragraph) shall be included in all copies or substantial + portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + </copyright> + + <description summary="Wayland protocol for graphics tablets"> + This description provides a high-level overview of the interplay between + the interfaces defined this protocol. For details, see the protocol + specification. + + More than one tablet may exist, and device-specifics matter. Tablets are + not represented by a single virtual device like wl_pointer. A client + binds to the tablet manager object which is just a proxy object. From + that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat) + and that returns the actual interface that has all the tablets. With + this indirection, we can avoid merging wp_tablet into the actual Wayland + protocol, a long-term benefit. + + The wp_tablet_seat sends a "tablet added" event for each tablet + connected. That event is followed by descriptive events about the + hardware; currently that includes events for name, vid/pid and + a wp_tablet.path event that describes a local path. This path can be + used to uniquely identify a tablet or get more information through + libwacom. Emulated or nested tablets can skip any of those, e.g. a + virtual tablet may not have a vid/pid. The sequence of descriptive + events is terminated by a wp_tablet.done event to signal that a client + may now finalize any initialization for that tablet. + + Events from tablets require a tool in proximity. Tools are also managed + by the tablet seat; a "tool added" event is sent whenever a tool is new + to the compositor. That event is followed by a number of descriptive + events about the hardware; currently that includes capabilities, + hardware id and serial number, and tool type. Similar to the tablet + interface, a wp_tablet_tool.done event is sent to terminate that initial + sequence. + + Any event from a tool happens on the wp_tablet_tool interface. When the + tool gets into proximity of the tablet, a proximity_in event is sent on + the wp_tablet_tool interface, listing the tablet and the surface. That + event is followed by a motion event with the coordinates. After that, + it's the usual motion, axis, button, etc. events. The protocol's + serialisation means events are grouped by wp_tablet_tool.frame events. + + Two special events (that don't exist in X) are down and up. They signal + "tip touching the surface". For tablets without real proximity + detection, the sequence is: proximity_in, motion, down, frame. + + When the tool leaves proximity, a proximity_out event is sent. If any + button is still down, a button release event is sent before this + proximity event. These button events are sent in the same frame as the + proximity event to signal to the client that the buttons were held when + the tool left proximity. + + If the tool moves out of the surface but stays in proximity (i.e. + between windows), compositor-specific grab policies apply. This usually + means that the proximity-out is delayed until all buttons are released. + + Moving a tool physically from one tablet to the other has no real effect + on the protocol, since we already have the tool object from the "tool + added" event. All the information is already there and the proximity + events on both tablets are all a client needs to reconstruct what + happened. + + Some extra axes are normalized, i.e. the client knows the range as + specified in the protocol (e.g. [0, 65535]), the granularity however is + unknown. The current normalized axes are pressure, distance, and slider. + + Other extra axes are in physical units as specified in the protocol. + The current extra axes with physical units are tilt, rotation and + wheel rotation. + + Since tablets work independently of the pointer controlled by the mouse, + the focus handling is independent too and controlled by proximity. + The wp_tablet_tool.set_cursor request sets a tool-specific cursor. + This cursor surface may be the same as the mouse cursor, and it may be + the same across tools but it is possible to be more fine-grained. For + example, a client may set different cursors for the pen and eraser. + + Tools are generally independent of tablets and it is + compositor-specific policy when a tool can be removed. Common approaches + will likely include some form of removing a tool when all tablets the + tool was used on are removed. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible changes + may be added together with the corresponding interface version bump. + Backward incompatible changes are done by bumping the version number in + the protocol and interface names and resetting the interface version. + Once the protocol is to be declared stable, the 'z' prefix and the + version number in the protocol and interface names are removed and the + interface version number is reset. + </description> + + <interface name="zwp_tablet_manager_v2" version="1"> + <description summary="controller object for graphic tablet devices"> + An object that provides access to the graphics tablets available on this + system. All tablets are associated with a seat, to get access to the + actual tablets, use wp_tablet_manager.get_tablet_seat. + </description> + + <request name="get_tablet_seat"> + <description summary="get the tablet seat"> + Get the wp_tablet_seat object for the given seat. This object + provides access to all graphics tablets in this seat. + </description> + <arg name="tablet_seat" type="new_id" interface="zwp_tablet_seat_v2"/> + <arg name="seat" type="object" interface="wl_seat" summary="The wl_seat object to retrieve the tablets for" /> + </request> + + <request name="destroy" type="destructor"> + <description summary="release the memory for the tablet manager object"> + Destroy the wp_tablet_manager object. Objects created from this + object are unaffected and should be destroyed separately. + </description> + </request> + </interface> + + <interface name="zwp_tablet_seat_v2" version="1"> + <description summary="controller object for graphic tablet devices of a seat"> + An object that provides access to the graphics tablets available on this + seat. After binding to this interface, the compositor sends a set of + wp_tablet_seat.tablet_added and wp_tablet_seat.tool_added events. + </description> + + <request name="destroy" type="destructor"> + <description summary="release the memory for the tablet seat object"> + Destroy the wp_tablet_seat object. Objects created from this + object are unaffected and should be destroyed separately. + </description> + </request> + + <event name="tablet_added"> + <description summary="new device notification"> + This event is sent whenever a new tablet becomes available on this + seat. This event only provides the object id of the tablet, any + static information about the tablet (device name, vid/pid, etc.) is + sent through the wp_tablet interface. + </description> + <arg name="id" type="new_id" interface="zwp_tablet_v2" summary="the newly added graphics tablet"/> + </event> + + <event name="tool_added"> + <description summary="a new tool has been used with a tablet"> + This event is sent whenever a tool that has not previously been used + with a tablet comes into use. This event only provides the object id + of the tool; any static information about the tool (capabilities, + type, etc.) is sent through the wp_tablet_tool interface. + </description> + <arg name="id" type="new_id" interface="zwp_tablet_tool_v2" summary="the newly added tablet tool"/> + </event> + + <event name="pad_added"> + <description summary="new pad notification"> + This event is sent whenever a new pad is known to the system. Typically, + pads are physically attached to tablets and a pad_added event is + sent immediately after the wp_tablet_seat.tablet_added. + However, some standalone pad devices logically attach to tablets at + runtime, and the client must wait for wp_tablet_pad.enter to know + the tablet a pad is attached to. + + This event only provides the object id of the pad. All further + features (buttons, strips, rings) are sent through the wp_tablet_pad + interface. + </description> + <arg name="id" type="new_id" interface="zwp_tablet_pad_v2" summary="the newly added pad"/> + </event> + </interface> + + <interface name="zwp_tablet_tool_v2" version="1"> + <description summary="a physical tablet tool"> + An object that represents a physical tool that has been, or is + currently in use with a tablet in this seat. Each wp_tablet_tool + object stays valid until the client destroys it; the compositor + reuses the wp_tablet_tool object to indicate that the object's + respective physical tool has come into proximity of a tablet again. + + A wp_tablet_tool object's relation to a physical tool depends on the + tablet's ability to report serial numbers. If the tablet supports + this capability, then the object represents a specific physical tool + and can be identified even when used on multiple tablets. + + A tablet tool has a number of static characteristics, e.g. tool type, + hardware_serial and capabilities. These capabilities are sent in an + event sequence after the wp_tablet_seat.tool_added event before any + actual events from this tool. This initial event sequence is + terminated by a wp_tablet_tool.done event. + + Tablet tool events are grouped by wp_tablet_tool.frame events. + Any events received before a wp_tablet_tool.frame event should be + considered part of the same hardware state change. + </description> + + <request name="set_cursor"> + <description summary="set the tablet tool's surface"> + Sets the surface of the cursor used for this tool on the given + tablet. This request only takes effect if the tool is in proximity + of one of the requesting client's surfaces or the surface parameter + is the current pointer surface. If there was a previous surface set + with this request it is replaced. If surface is NULL, the cursor + image is hidden. + + The parameters hotspot_x and hotspot_y define the position of the + pointer surface relative to the pointer location. Its top-left corner + is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the + coordinates of the pointer location, in surface-local coordinates. + + On surface.attach requests to the pointer surface, hotspot_x and + hotspot_y are decremented by the x and y parameters passed to the + request. Attach must be confirmed by wl_surface.commit as usual. + + The hotspot can also be updated by passing the currently set pointer + surface to this request with new values for hotspot_x and hotspot_y. + + The current and pending input regions of the wl_surface are cleared, + and wl_surface.set_input_region is ignored until the wl_surface is no + longer used as the cursor. When the use as a cursor ends, the current + and pending input regions become undefined, and the wl_surface is + unmapped. + + This request gives the surface the role of a wp_tablet_tool cursor. A + surface may only ever be used as the cursor surface for one + wp_tablet_tool. If the surface already has another role or has + previously been used as cursor surface for a different tool, a + protocol error is raised. + </description> + <arg name="serial" type="uint" summary="serial of the enter event"/> + <arg name="surface" type="object" interface="wl_surface" allow-null="true"/> + <arg name="hotspot_x" type="int" summary="surface-local x coordinate"/> + <arg name="hotspot_y" type="int" summary="surface-local y coordinate"/> + </request> + + <request name="destroy" type="destructor"> + <description summary="destroy the tool object"> + This destroys the client's resource for this tool object. + </description> + </request> + + <enum name="type"> + <description summary="a physical tool type"> + Describes the physical type of a tool. The physical type of a tool + generally defines its base usage. + + The mouse tool represents a mouse-shaped tool that is not a relative + device but bound to the tablet's surface, providing absolute + coordinates. + + The lens tool is a mouse-shaped tool with an attached lens to + provide precision focus. + </description> + <entry name="pen" value="0x140" summary="Pen"/> + <entry name="eraser" value="0x141" summary="Eraser"/> + <entry name="brush" value="0x142" summary="Brush"/> + <entry name="pencil" value="0x143" summary="Pencil"/> + <entry name="airbrush" value="0x144" summary="Airbrush"/> + <entry name="finger" value="0x145" summary="Finger"/> + <entry name="mouse" value="0x146" summary="Mouse"/> + <entry name="lens" value="0x147" summary="Lens"/> + </enum> + + <event name="type"> + <description summary="tool type"> + The tool type is the high-level type of the tool and usually decides + the interaction expected from this tool. + + This event is sent in the initial burst of events before the + wp_tablet_tool.done event. + </description> + <arg name="tool_type" type="uint" enum="type" summary="the physical tool type"/> + </event> + + <event name="hardware_serial"> + <description summary="unique hardware serial number of the tool"> + If the physical tool can be identified by a unique 64-bit serial + number, this event notifies the client of this serial number. + + If multiple tablets are available in the same seat and the tool is + uniquely identifiable by the serial number, that tool may move + between tablets. + + Otherwise, if the tool has no serial number and this event is + missing, the tool is tied to the tablet it first comes into + proximity with. Even if the physical tool is used on multiple + tablets, separate wp_tablet_tool objects will be created, one per + tablet. + + This event is sent in the initial burst of events before the + wp_tablet_tool.done event. + </description> + <arg name="hardware_serial_hi" type="uint" summary="the unique serial number of the tool, most significant bits"/> + <arg name="hardware_serial_lo" type="uint" summary="the unique serial number of the tool, least significant bits"/> + </event> + + <event name="hardware_id_wacom"> + <description summary="hardware id notification in Wacom's format"> + This event notifies the client of a hardware id available on this tool. + + The hardware id is a device-specific 64-bit id that provides extra + information about the tool in use, beyond the wl_tool.type + enumeration. The format of the id is specific to tablets made by + Wacom Inc. For example, the hardware id of a Wacom Grip + Pen (a stylus) is 0x802. + + This event is sent in the initial burst of events before the + wp_tablet_tool.done event. + </description> + <arg name="hardware_id_hi" type="uint" summary="the hardware id, most significant bits"/> + <arg name="hardware_id_lo" type="uint" summary="the hardware id, least significant bits"/> + </event> + + <enum name="capability"> + <description summary="capability flags for a tool"> + Describes extra capabilities on a tablet. + + Any tool must provide x and y values, extra axes are + device-specific. + </description> + <entry name="tilt" value="1" summary="Tilt axes"/> + <entry name="pressure" value="2" summary="Pressure axis"/> + <entry name="distance" value="3" summary="Distance axis"/> + <entry name="rotation" value="4" summary="Z-rotation axis"/> + <entry name="slider" value="5" summary="Slider axis"/> + <entry name="wheel" value="6" summary="Wheel axis"/> + </enum> + + <event name="capability"> + <description summary="tool capability notification"> + This event notifies the client of any capabilities of this tool, + beyond the main set of x/y axes and tip up/down detection. + + One event is sent for each extra capability available on this tool. + + This event is sent in the initial burst of events before the + wp_tablet_tool.done event. + </description> + <arg name="capability" type="uint" enum="capability" summary="the capability"/> + </event> + + <event name="done"> + <description summary="tool description events sequence complete"> + This event signals the end of the initial burst of descriptive + events. A client may consider the static description of the tool to + be complete and finalize initialization of the tool. + </description> + </event> + + <event name="removed"> + <description summary="tool removed"> + This event is sent when the tool is removed from the system and will + send no further events. Should the physical tool come back into + proximity later, a new wp_tablet_tool object will be created. + + It is compositor-dependent when a tool is removed. A compositor may + remove a tool on proximity out, tablet removal or any other reason. + A compositor may also keep a tool alive until shutdown. + + If the tool is currently in proximity, a proximity_out event will be + sent before the removed event. See wp_tablet_tool.proximity_out for + the handling of any buttons logically down. + + When this event is received, the client must wp_tablet_tool.destroy + the object. + </description> + </event> + + <event name="proximity_in"> + <description summary="proximity in event"> + Notification that this tool is focused on a certain surface. + + This event can be received when the tool has moved from one surface to + another, or when the tool has come back into proximity above the + surface. + + If any button is logically down when the tool comes into proximity, + the respective button event is sent after the proximity_in event but + within the same frame as the proximity_in event. + </description> + <arg name="serial" type="uint"/> + <arg name="tablet" type="object" interface="zwp_tablet_v2" summary="The tablet the tool is in proximity of"/> + <arg name="surface" type="object" interface="wl_surface" summary="The current surface the tablet tool is over"/> + </event> + + <event name="proximity_out"> + <description summary="proximity out event"> + Notification that this tool has either left proximity, or is no + longer focused on a certain surface. + + When the tablet tool leaves proximity of the tablet, button release + events are sent for each button that was held down at the time of + leaving proximity. These events are sent before the proximity_out + event but within the same wp_tablet.frame. + + If the tool stays within proximity of the tablet, but the focus + changes from one surface to another, a button release event may not + be sent until the button is actually released or the tool leaves the + proximity of the tablet. + </description> + </event> + + <event name="down"> + <description summary="tablet tool is making contact"> + Sent whenever the tablet tool comes in contact with the surface of the + tablet. + + If the tool is already in contact with the tablet when entering the + input region, the client owning said region will receive a + wp_tablet.proximity_in event, followed by a wp_tablet.down + event and a wp_tablet.frame event. + + Note that this event describes logical contact, not physical + contact. On some devices, a compositor may not consider a tool in + logical contact until a minimum physical pressure threshold is + exceeded. + </description> + <arg name="serial" type="uint"/> + </event> + + <event name="up"> + <description summary="tablet tool is no longer making contact"> + Sent whenever the tablet tool stops making contact with the surface of + the tablet, or when the tablet tool moves out of the input region + and the compositor grab (if any) is dismissed. + + If the tablet tool moves out of the input region while in contact + with the surface of the tablet and the compositor does not have an + ongoing grab on the surface, the client owning said region will + receive a wp_tablet.up event, followed by a wp_tablet.proximity_out + event and a wp_tablet.frame event. If the compositor has an ongoing + grab on this device, this event sequence is sent whenever the grab + is dismissed in the future. + + Note that this event describes logical contact, not physical + contact. On some devices, a compositor may not consider a tool out + of logical contact until physical pressure falls below a specific + threshold. + </description> + </event> + + <event name="motion"> + <description summary="motion event"> + Sent whenever a tablet tool moves. + </description> + <arg name="x" type="fixed" summary="surface-local x coordinate"/> + <arg name="y" type="fixed" summary="surface-local y coordinate"/> + </event> + + <event name="pressure"> + <description summary="pressure change event"> + Sent whenever the pressure axis on a tool changes. The value of this + event is normalized to a value between 0 and 65535. + + Note that pressure may be nonzero even when a tool is not in logical + contact. See the down and up events for more details. + </description> + <arg name="pressure" type="uint" summary="The current pressure value"/> + </event> + + <event name="distance"> + <description summary="distance change event"> + Sent whenever the distance axis on a tool changes. The value of this + event is normalized to a value between 0 and 65535. + + Note that distance may be nonzero even when a tool is not in logical + contact. See the down and up events for more details. + </description> + <arg name="distance" type="uint" summary="The current distance value"/> + </event> + + <event name="tilt"> + <description summary="tilt change event"> + Sent whenever one or both of the tilt axes on a tool change. Each tilt + value is in degrees, relative to the z-axis of the tablet. + The angle is positive when the top of a tool tilts along the + positive x or y axis. + </description> + <arg name="tilt_x" type="fixed" summary="The current value of the X tilt axis"/> + <arg name="tilt_y" type="fixed" summary="The current value of the Y tilt axis"/> + </event> + + <event name="rotation"> + <description summary="z-rotation change event"> + Sent whenever the z-rotation axis on the tool changes. The + rotation value is in degrees clockwise from the tool's + logical neutral position. + </description> + <arg name="degrees" type="fixed" summary="The current rotation of the Z axis"/> + </event> + + <event name="slider"> + <description summary="Slider position change event"> + Sent whenever the slider position on the tool changes. The + value is normalized between -65535 and 65535, with 0 as the logical + neutral position of the slider. + + The slider is available on e.g. the Wacom Airbrush tool. + </description> + <arg name="position" type="int" summary="The current position of slider"/> + </event> + + <event name="wheel"> + <description summary="Wheel delta event"> + Sent whenever the wheel on the tool emits an event. This event + contains two values for the same axis change. The degrees value is + in the same orientation as the wl_pointer.vertical_scroll axis. The + clicks value is in discrete logical clicks of the mouse wheel. This + value may be zero if the movement of the wheel was less + than one logical click. + + Clients should choose either value and avoid mixing degrees and + clicks. The compositor may accumulate values smaller than a logical + click and emulate click events when a certain threshold is met. + Thus, wl_tablet_tool.wheel events with non-zero clicks values may + have different degrees values. + </description> + <arg name="degrees" type="fixed" summary="The wheel delta in degrees"/> + <arg name="clicks" type="int" summary="The wheel delta in discrete clicks"/> + </event> + + <enum name="button_state"> + <description summary="physical button state"> + Describes the physical state of a button that produced the button event. + </description> + <entry name="released" value="0" summary="button is not pressed"/> + <entry name="pressed" value="1" summary="button is pressed"/> + </enum> + + <event name="button"> + <description summary="button event"> + Sent whenever a button on the tool is pressed or released. + + If a button is held down when the tool moves in or out of proximity, + button events are generated by the compositor. See + wp_tablet_tool.proximity_in and wp_tablet_tool.proximity_out for + details. + </description> + <arg name="serial" type="uint"/> + <arg name="button" type="uint" summary="The button whose state has changed"/> + <arg name="state" type="uint" enum="button_state" summary="Whether the button was pressed or released"/> + </event> + + <event name="frame"> + <description summary="frame event"> + Marks the end of a series of axis and/or button updates from the + tablet. The Wayland protocol requires axis updates to be sent + sequentially, however all events within a frame should be considered + one hardware event. + </description> + <arg name="time" type="uint" summary="The time of the event with millisecond granularity"/> + </event> + + <enum name="error"> + <entry name="role" value="0" summary="given wl_surface has another role"/> + </enum> + </interface> + + <interface name="zwp_tablet_v2" version="1"> + <description summary="graphics tablet device"> + The wp_tablet interface represents one graphics tablet device. The + tablet interface itself does not generate events; all events are + generated by wp_tablet_tool objects when in proximity above a tablet. + + A tablet has a number of static characteristics, e.g. device name and + pid/vid. These capabilities are sent in an event sequence after the + wp_tablet_seat.tablet_added event. This initial event sequence is + terminated by a wp_tablet.done event. + </description> + + <request name="destroy" type="destructor"> + <description summary="destroy the tablet object"> + This destroys the client's resource for this tablet object. + </description> + </request> + + <event name="name"> + <description summary="tablet device name"> + This event is sent in the initial burst of events before the + wp_tablet.done event. + </description> + <arg name="name" type="string" summary="the device name"/> + </event> + + <event name="id"> + <description summary="tablet device USB vendor/product id"> + This event is sent in the initial burst of events before the + wp_tablet.done event. + </description> + <arg name="vid" type="uint" summary="USB vendor id"/> + <arg name="pid" type="uint" summary="USB product id"/> + </event> + + <event name="path"> + <description summary="path to the device"> + A system-specific device path that indicates which device is behind + this wp_tablet. This information may be used to gather additional + information about the device, e.g. through libwacom. + + A device may have more than one device path. If so, multiple + wp_tablet.path events are sent. A device may be emulated and not + have a device path, and in that case this event will not be sent. + + The format of the path is unspecified, it may be a device node, a + sysfs path, or some other identifier. It is up to the client to + identify the string provided. + + This event is sent in the initial burst of events before the + wp_tablet.done event. + </description> + <arg name="path" type="string" summary="path to local device"/> + </event> + + <event name="done"> + <description summary="tablet description events sequence complete"> + This event is sent immediately to signal the end of the initial + burst of descriptive events. A client may consider the static + description of the tablet to be complete and finalize initialization + of the tablet. + </description> + </event> + + <event name="removed"> + <description summary="tablet removed event"> + Sent when the tablet has been removed from the system. When a tablet + is removed, some tools may be removed. + + When this event is received, the client must wp_tablet.destroy + the object. + </description> + </event> + </interface> + + <interface name="zwp_tablet_pad_ring_v2" version="1"> + <description summary="pad ring"> + A circular interaction area, such as the touch ring on the Wacom Intuos + Pro series tablets. + + Events on a ring are logically grouped by the wl_tablet_pad_ring.frame + event. + </description> + + <request name="set_feedback"> + <description summary="set compositor feedback"> + Request that the compositor use the provided feedback string + associated with this ring. This request should be issued immediately + after a wp_tablet_pad_group.mode_switch event from the corresponding + group is received, or whenever the ring is mapped to a different + action. See wp_tablet_pad_group.mode_switch for more details. + + Clients are encouraged to provide context-aware descriptions for + the actions associated with the ring; compositors may use this + information to offer visual feedback about the button layout + (eg. on-screen displays). + + The provided string 'description' is a UTF-8 encoded string to be + associated with this ring, and is considered user-visible; general + internationalization rules apply. + + The serial argument will be that of the last + wp_tablet_pad_group.mode_switch event received for the group of this + ring. Requests providing other serials than the most recent one will be + ignored. + </description> + <arg name="description" type="string" summary="ring description"/> + <arg name="serial" type="uint" summary="serial of the mode switch event"/> + </request> + + <request name="destroy" type="destructor"> + <description summary="destroy the ring object"> + This destroys the client's resource for this ring object. + </description> + </request> + + <enum name="source"> + <description summary="ring axis source"> + Describes the source types for ring events. This indicates to the + client how a ring event was physically generated; a client may + adjust the user interface accordingly. For example, events + from a "finger" source may trigger kinetic scrolling. + </description> + <entry name="finger" value="1" summary="finger"/> + </enum> + + <event name="source"> + <description summary="ring event source"> + Source information for ring events. + + This event does not occur on its own. It is sent before a + wp_tablet_pad_ring.frame event and carries the source information + for all events within that frame. + + The source specifies how this event was generated. If the source is + wp_tablet_pad_ring.source.finger, a wp_tablet_pad_ring.stop event + will be sent when the user lifts the finger off the device. + + This event is optional. If the source is unknown for an interaction, + no event is sent. + </description> + <arg name="source" type="uint" enum="source" summary="the event source"/> + </event> + + <event name="angle"> + <description summary="angle changed"> + Sent whenever the angle on a ring changes. + + The angle is provided in degrees clockwise from the logical + north of the ring in the pad's current rotation. + </description> + <arg name="degrees" type="fixed" summary="the current angle in degrees"/> + </event> + + <event name="stop"> + <description summary="interaction stopped"> + Stop notification for ring events. + + For some wp_tablet_pad_ring.source types, a wp_tablet_pad_ring.stop + event is sent to notify a client that the interaction with the ring + has terminated. This enables the client to implement kinetic scrolling. + See the wp_tablet_pad_ring.source documentation for information on + when this event may be generated. + + Any wp_tablet_pad_ring.angle events with the same source after this + event should be considered as the start of a new interaction. + </description> + </event> + + <event name="frame"> + <description summary="end of a ring event sequence"> + Indicates the end of a set of ring events that logically belong + together. A client is expected to accumulate the data in all events + within the frame before proceeding. + + All wp_tablet_pad_ring events before a wp_tablet_pad_ring.frame event belong + logically together. For example, on termination of a finger interaction + on a ring the compositor will send a wp_tablet_pad_ring.source event, + a wp_tablet_pad_ring.stop event and a wp_tablet_pad_ring.frame event. + + A wp_tablet_pad_ring.frame event is sent for every logical event + group, even if the group only contains a single wp_tablet_pad_ring + event. Specifically, a client may get a sequence: angle, frame, + angle, frame, etc. + </description> + <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> + </event> + </interface> + + <interface name="zwp_tablet_pad_strip_v2" version="1"> + <description summary="pad strip"> + A linear interaction area, such as the strips found in Wacom Cintiq + models. + + Events on a strip are logically grouped by the wl_tablet_pad_strip.frame + event. + </description> + + <request name="set_feedback"> + <description summary="set compositor feedback"> + Requests the compositor to use the provided feedback string + associated with this strip. This request should be issued immediately + after a wp_tablet_pad_group.mode_switch event from the corresponding + group is received, or whenever the strip is mapped to a different + action. See wp_tablet_pad_group.mode_switch for more details. + + Clients are encouraged to provide context-aware descriptions for + the actions associated with the strip, and compositors may use this + information to offer visual feedback about the button layout + (eg. on-screen displays). + + The provided string 'description' is a UTF-8 encoded string to be + associated with this ring, and is considered user-visible; general + internationalization rules apply. + + The serial argument will be that of the last + wp_tablet_pad_group.mode_switch event received for the group of this + strip. Requests providing other serials than the most recent one will be + ignored. + </description> + <arg name="description" type="string" summary="strip description"/> + <arg name="serial" type="uint" summary="serial of the mode switch event"/> + </request> + + <request name="destroy" type="destructor"> + <description summary="destroy the strip object"> + This destroys the client's resource for this strip object. + </description> + </request> + + <enum name="source"> + <description summary="strip axis source"> + Describes the source types for strip events. This indicates to the + client how a strip event was physically generated; a client may + adjust the user interface accordingly. For example, events + from a "finger" source may trigger kinetic scrolling. + </description> + <entry name="finger" value="1" summary="finger"/> + </enum> + + <event name="source"> + <description summary="strip event source"> + Source information for strip events. + + This event does not occur on its own. It is sent before a + wp_tablet_pad_strip.frame event and carries the source information + for all events within that frame. + + The source specifies how this event was generated. If the source is + wp_tablet_pad_strip.source.finger, a wp_tablet_pad_strip.stop event + will be sent when the user lifts their finger off the device. + + This event is optional. If the source is unknown for an interaction, + no event is sent. + </description> + <arg name="source" type="uint" enum="source" summary="the event source"/> + </event> + + <event name="position"> + <description summary="position changed"> + Sent whenever the position on a strip changes. + + The position is normalized to a range of [0, 65535], the 0-value + represents the top-most and/or left-most position of the strip in + the pad's current rotation. + </description> + <arg name="position" type="uint" summary="the current position"/> + </event> + + <event name="stop"> + <description summary="interaction stopped"> + Stop notification for strip events. + + For some wp_tablet_pad_strip.source types, a wp_tablet_pad_strip.stop + event is sent to notify a client that the interaction with the strip + has terminated. This enables the client to implement kinetic + scrolling. See the wp_tablet_pad_strip.source documentation for + information on when this event may be generated. + + Any wp_tablet_pad_strip.position events with the same source after this + event should be considered as the start of a new interaction. + </description> + </event> + + <event name="frame"> + <description summary="end of a strip event sequence"> + Indicates the end of a set of events that represent one logical + hardware strip event. A client is expected to accumulate the data + in all events within the frame before proceeding. + + All wp_tablet_pad_strip events before a wp_tablet_pad_strip.frame event belong + logically together. For example, on termination of a finger interaction + on a strip the compositor will send a wp_tablet_pad_strip.source event, + a wp_tablet_pad_strip.stop event and a wp_tablet_pad_strip.frame + event. + + A wp_tablet_pad_strip.frame event is sent for every logical event + group, even if the group only contains a single wp_tablet_pad_strip + event. Specifically, a client may get a sequence: position, frame, + position, frame, etc. + </description> + <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> + </event> + </interface> + + <interface name="zwp_tablet_pad_group_v2" version="1"> + <description summary="a set of buttons, rings and strips"> + A pad group describes a distinct (sub)set of buttons, rings and strips + present in the tablet. The criteria of this grouping is usually positional, + eg. if a tablet has buttons on the left and right side, 2 groups will be + presented. The physical arrangement of groups is undisclosed and may + change on the fly. + + Pad groups will announce their features during pad initialization. Between + the corresponding wp_tablet_pad.group event and wp_tablet_pad_group.done, the + pad group will announce the buttons, rings and strips contained in it, + plus the number of supported modes. + + Modes are a mechanism to allow multiple groups of actions for every element + in the pad group. The number of groups and available modes in each is + persistent across device plugs. The current mode is user-switchable, it + will be announced through the wp_tablet_pad_group.mode_switch event both + whenever it is switched, and after wp_tablet_pad.enter. + + The current mode logically applies to all elements in the pad group, + although it is at clients' discretion whether to actually perform different + actions, and/or issue the respective .set_feedback requests to notify the + compositor. See the wp_tablet_pad_group.mode_switch event for more details. + </description> + + <request name="destroy" type="destructor"> + <description summary="destroy the pad object"> + Destroy the wp_tablet_pad_group object. Objects created from this object + are unaffected and should be destroyed separately. + </description> + </request> + + <event name="buttons"> + <description summary="buttons announced"> + Sent on wp_tablet_pad_group initialization to announce the available + buttons in the group. Button indices start at 0, a button may only be + in one group at a time. + + This event is first sent in the initial burst of events before the + wp_tablet_pad_group.done event. + + Some buttons are reserved by the compositor. These buttons may not be + assigned to any wp_tablet_pad_group. Compositors may broadcast this + event in the case of changes to the mapping of these reserved buttons. + If the compositor happens to reserve all buttons in a group, this event + will be sent with an empty array. + </description> + <arg name="buttons" type="array" summary="buttons in this group"/> + </event> + + <event name="ring"> + <description summary="ring announced"> + Sent on wp_tablet_pad_group initialization to announce available rings. + One event is sent for each ring available on this pad group. + + This event is sent in the initial burst of events before the + wp_tablet_pad_group.done event. + </description> + <arg name="ring" type="new_id" interface="zwp_tablet_pad_ring_v2"/> + </event> + + <event name="strip"> + <description summary="strip announced"> + Sent on wp_tablet_pad initialization to announce available strips. + One event is sent for each strip available on this pad group. + + This event is sent in the initial burst of events before the + wp_tablet_pad_group.done event. + </description> + <arg name="strip" type="new_id" interface="zwp_tablet_pad_strip_v2"/> + </event> + + <event name="modes"> + <description summary="mode-switch ability announced"> + Sent on wp_tablet_pad_group initialization to announce that the pad + group may switch between modes. A client may use a mode to store a + specific configuration for buttons, rings and strips and use the + wl_tablet_pad_group.mode_switch event to toggle between these + configurations. Mode indices start at 0. + + Switching modes is compositor-dependent. See the + wp_tablet_pad_group.mode_switch event for more details. + + This event is sent in the initial burst of events before the + wp_tablet_pad_group.done event. This event is only sent when more than + more than one mode is available. + </description> + <arg name="modes" type="uint" summary="the number of modes"/> + </event> + + <event name="done"> + <description summary="tablet group description events sequence complete"> + This event is sent immediately to signal the end of the initial + burst of descriptive events. A client may consider the static + description of the tablet to be complete and finalize initialization + of the tablet group. + </description> + </event> + + <event name="mode_switch"> + <description summary="mode switch event"> + Notification that the mode was switched. + + A mode applies to all buttons, rings and strips in a group + simultaneously, but a client is not required to assign different actions + for each mode. For example, a client may have mode-specific button + mappings but map the ring to vertical scrolling in all modes. Mode + indices start at 0. + + Switching modes is compositor-dependent. The compositor may provide + visual cues to the client about the mode, e.g. by toggling LEDs on + the tablet device. Mode-switching may be software-controlled or + controlled by one or more physical buttons. For example, on a Wacom + Intuos Pro, the button inside the ring may be assigned to switch + between modes. + + The compositor will also send this event after wp_tablet_pad.enter on + each group in order to notify of the current mode. Groups that only + feature one mode will use mode=0 when emitting this event. + + If a button action in the new mode differs from the action in the + previous mode, the client should immediately issue a + wp_tablet_pad.set_feedback request for each changed button. + + If a ring or strip action in the new mode differs from the action + in the previous mode, the client should immediately issue a + wp_tablet_ring.set_feedback or wp_tablet_strip.set_feedback request + for each changed ring or strip. + </description> + <arg name="time" type="uint" summary="the time of the event with millisecond granularity"/> + <arg name="serial" type="uint"/> + <arg name="mode" type="uint" summary="the new mode of the pad"/> + </event> + </interface> + + <interface name="zwp_tablet_pad_v2" version="1"> + <description summary="a set of buttons, rings and strips"> + A pad device is a set of buttons, rings and strips + usually physically present on the tablet device itself. Some + exceptions exist where the pad device is physically detached, e.g. the + Wacom ExpressKey Remote. + + Pad devices have no axes that control the cursor and are generally + auxiliary devices to the tool devices used on the tablet surface. + + A pad device has a number of static characteristics, e.g. the number + of rings. These capabilities are sent in an event sequence after the + wp_tablet_seat.pad_added event before any actual events from this pad. + This initial event sequence is terminated by a wp_tablet_pad.done + event. + + All pad features (buttons, rings and strips) are logically divided into + groups and all pads have at least one group. The available groups are + notified through the wp_tablet_pad.group event; the compositor will + emit one event per group before emitting wp_tablet_pad.done. + + Groups may have multiple modes. Modes allow clients to map multiple + actions to a single pad feature. Only one mode can be active per group, + although different groups may have different active modes. + </description> + + <request name="set_feedback"> + <description summary="set compositor feedback"> + Requests the compositor to use the provided feedback string + associated with this button. This request should be issued immediately + after a wp_tablet_pad_group.mode_switch event from the corresponding + group is received, or whenever a button is mapped to a different + action. See wp_tablet_pad_group.mode_switch for more details. + + Clients are encouraged to provide context-aware descriptions for + the actions associated with each button, and compositors may use + this information to offer visual feedback on the button layout + (e.g. on-screen displays). + + Button indices start at 0. Setting the feedback string on a button + that is reserved by the compositor (i.e. not belonging to any + wp_tablet_pad_group) does not generate an error but the compositor + is free to ignore the request. + + The provided string 'description' is a UTF-8 encoded string to be + associated with this ring, and is considered user-visible; general + internationalization rules apply. + + The serial argument will be that of the last + wp_tablet_pad_group.mode_switch event received for the group of this + button. Requests providing other serials than the most recent one will + be ignored. + </description> + <arg name="button" type="uint" summary="button index"/> + <arg name="description" type="string" summary="button description"/> + <arg name="serial" type="uint" summary="serial of the mode switch event"/> + </request> + + <request name="destroy" type="destructor"> + <description summary="destroy the pad object"> + Destroy the wp_tablet_pad object. Objects created from this object + are unaffected and should be destroyed separately. + </description> + </request> + + <event name="group"> + <description summary="group announced"> + Sent on wp_tablet_pad initialization to announce available groups. + One event is sent for each pad group available. + + This event is sent in the initial burst of events before the + wp_tablet_pad.done event. At least one group will be announced. + </description> + <arg name="pad_group" type="new_id" interface="zwp_tablet_pad_group_v2"/> + </event> + + <event name="path"> + <description summary="path to the device"> + A system-specific device path that indicates which device is behind + this wp_tablet_pad. This information may be used to gather additional + information about the device, e.g. through libwacom. + + The format of the path is unspecified, it may be a device node, a + sysfs path, or some other identifier. It is up to the client to + identify the string provided. + + This event is sent in the initial burst of events before the + wp_tablet_pad.done event. + </description> + <arg name="path" type="string" summary="path to local device"/> + </event> + + <event name="buttons"> + <description summary="buttons announced"> + Sent on wp_tablet_pad initialization to announce the available + buttons. + + This event is sent in the initial burst of events before the + wp_tablet_pad.done event. This event is only sent when at least one + button is available. + </description> + <arg name="buttons" type="uint" summary="the number of buttons"/> + </event> + + <event name="done"> + <description summary="pad description event sequence complete"> + This event signals the end of the initial burst of descriptive + events. A client may consider the static description of the pad to + be complete and finalize initialization of the pad. + </description> + </event> + + <enum name="button_state"> + <description summary="physical button state"> + Describes the physical state of a button that caused the button + event. + </description> + <entry name="released" value="0" summary="the button is not pressed"/> + <entry name="pressed" value="1" summary="the button is pressed"/> + </enum> + + <event name="button"> + <description summary="physical button state"> + Sent whenever the physical state of a button changes. + </description> + <arg name="time" type="uint" summary="the time of the event with millisecond granularity"/> + <arg name="button" type="uint" summary="the index of the button that changed state"/> + <arg name="state" type="uint" enum="button_state"/> + </event> + + <event name="enter"> + <description summary="enter event"> + Notification that this pad is focused on the specified surface. + </description> + <arg name="serial" type="uint" summary="serial number of the enter event"/> + <arg name="tablet" type="object" interface="zwp_tablet_v2" summary="the tablet the pad is attached to"/> + <arg name="surface" type="object" interface="wl_surface" summary="surface the pad is focused on"/> + </event> + + <event name="leave"> + <description summary="enter event"> + Notification that this pad is no longer focused on the specified + surface. + </description> + <arg name="serial" type="uint" summary="serial number of the leave event"/> + <arg name="surface" type="object" interface="wl_surface" summary="surface the pad is no longer focused on"/> + </event> + + <event name="removed"> + <description summary="pad removed event"> + Sent when the pad has been removed from the system. When a tablet + is removed its pad(s) will be removed too. + + When this event is received, the client must destroy all rings, strips + and groups that were offered by this pad, and issue wp_tablet_pad.destroy + the pad itself. + </description> + </event> + </interface> +</protocol> diff --git a/src/client/client.pro b/src/client/client.pro index 32156470c..793a44183 100644 --- a/src/client/client.pro +++ b/src/client/client.pro @@ -5,6 +5,10 @@ QT += core-private gui-private QT_FOR_PRIVATE += service_support-private QT_PRIVATE += fontdatabase_support-private eventdispatcher_support-private theme_support-private +qtConfig(vulkan) { + QT_PRIVATE += vulkan_support-private +} + # We have a bunch of C code with casts, so we can't have this option QMAKE_CXXFLAGS_WARN_ON -= -Wcast-qual @@ -32,6 +36,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 @@ -48,6 +53,7 @@ SOURCES += qwaylandintegration.cpp \ qwaylandextendedsurface.cpp \ qwaylandsubsurface.cpp \ qwaylandsurface.cpp \ + qwaylandtabletv2.cpp \ qwaylandtouch.cpp \ qwaylandqtkey.cpp \ ../shared/qwaylandmimehelper.cpp \ @@ -73,6 +79,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 \ @@ -97,6 +104,16 @@ include(shellintegration/shellintegration.pri) include(inputdeviceintegration/inputdeviceintegration.pri) include(global/global.pri) +qtConfig(vulkan) { + HEADERS += \ + qwaylandvulkaninstance_p.h \ + qwaylandvulkanwindow_p.h + + SOURCES += \ + qwaylandvulkaninstance.cpp \ + qwaylandvulkanwindow.cpp +} + qtConfig(cursor) { QMAKE_USE += wayland-cursor diff --git a/src/client/configure.json b/src/client/configure.json index 062139685..7d4468240 100644 --- a/src/client/configure.json +++ b/src/client/configure.json @@ -9,7 +9,24 @@ "libraries": { "wayland-client": { "label": "Wayland client library", - "test": "wayland", + "headers": "wayland-version.h", + "test": { + "main": [ + "#if WAYLAND_VERSION_MAJOR < 1", + "# error Wayland 1.8.0 or higher required", + "#endif", + "#if WAYLAND_VERSION_MAJOR == 1", + "# if WAYLAND_VERSION_MINOR < 8", + "# error Wayland 1.8.0 or higher required", + "# endif", + "# if WAYLAND_VERSION_MINOR == 8", + "# if WAYLAND_VERSION_MICRO < 0", + "# error Wayland 1.8.0 or higher required", + "# endif", + "# endif", + "#endif" + ] + }, "sources": [ { "type": "pkgConfig", "args": "wayland-client" }, "-lwayland-client" @@ -17,7 +34,10 @@ }, "wayland-cursor": { "label": "Wayland cursor library", - "test": "wayland_cursor", + "headers": "wayland-cursor.h", + "test": { + "main": "struct wl_cursor_image *image = 0;" + }, "use": "wayland-client", "sources": [ { "type": "pkgConfig", "args": "wayland-cursor" }, @@ -26,7 +46,10 @@ }, "wayland-egl": { "label": "Wayland EGL library", - "test": "wayland_egl", + "headers": "wayland-egl.h", + "test": { + "main": "struct wl_egl_window *window = wl_egl_window_create(0, 100, 100);" + }, "sources": [ { "type": "pkgConfig", "args": "wayland-egl" }, "-lwayland-egl", @@ -35,7 +58,11 @@ }, "xcomposite": { "label": "XComposite", - "test": "xcomposite", + "headers": "X11/extensions/Xcomposite.h", + "test": { + "main": "XCompositeRedirectWindow((Display *)0,(Window) 0, CompositeRedirectManual);" + + }, "sources": [ { "type": "pkgConfig", "args": "xcomposite" }, "-lxcomposite" @@ -43,7 +70,14 @@ }, "glx": { "label": "GLX", - "test": "glx", + "headers": "GL/glx.h", + "test": { + "main": [ + "Display *dpy = XOpenDisplay(0);", + "int items = 0;", + "GLXFBConfig *fbc = glXChooseFBConfig(dpy, DefaultScreen(dpy), 0 , &items);" + ] + }, "sources": [ { "type": "pkgConfig", "args": "x11 gl" }, "-lX11 -lGl" @@ -61,25 +95,79 @@ "drm-egl-server": { "label": "DRM EGL Server", "type": "compile", - "test": "drm_egl_server", + "test": { + "include": [ + "EGL/egl.h", + "EGL/eglext.h" + ], + "main": [ + "#ifdef EGL_MESA_drm_image", + "return 0;", + "#else", + "#error Requires EGL_MESA_drm_image to be defined", + "return 1;", + "#endif" + ] + }, "use": "egl" }, "libhybris-egl-server": { "label": "libhybris EGL Server", "type": "compile", - "test": "libhybris_egl_server", + "test": { + "include": [ + "EGL/egl.h", + "EGL/eglext.h", + "hybris/eglplatformcommon/hybris_nativebufferext.h" + ], + "main": [ + "#ifdef EGL_HYBRIS_native_buffer", + "return 0;", + "#else", + "#error Requires EGL_HYBRIS_native_buffer to be defined", + "return 1;", + "#endif" + ] + }, "use": "egl" }, "dmabuf-server-buffer": { "label": "Linux dma-buf Buffer Sharing", "type": "compile", - "test": "dmabuf_server_buffer", + "test": { + "include": [ + "EGL/egl.h", + "EGL/eglext.h", + "drm_fourcc.h" + ], + "main": [ + "#ifdef EGL_LINUX_DMA_BUF_EXT", + "return 0;", + "#else", + "#error Requires EGL_LINUX_DMA_BUF_EXT", + "return 1;", + "#endif" + ] + }, "use": "egl drm" }, "vulkan-server-buffer": { "label": "Vulkan Buffer Sharing", "type": "compile", - "test": "vulkan_server_buffer" + "test": { + "head": [ + "#define VK_USE_PLATFORM_WAYLAND_KHR 1" + ], + "include": [ + "vulkan/vulkan.h" + ], + "main": [ + "VkExportMemoryAllocateInfoKHR exportAllocInfo = {};", + "exportAllocInfo.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;", + "exportAllocInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;", + "return 0;" + ] + } } }, @@ -165,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": { diff --git a/src/client/qwaylanddatadevice.cpp b/src/client/qwaylanddatadevice.cpp index f7d135e49..19944a349 100644 --- a/src/client/qwaylanddatadevice.cpp +++ b/src/client/qwaylanddatadevice.cpp @@ -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); diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp index 0464d3a42..ffcc72ff9 100644 --- a/src/client/qwaylanddisplay.cpp +++ b/src/client/qwaylanddisplay.cpp @@ -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> @@ -188,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); @@ -253,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; } @@ -267,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() @@ -314,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)); @@ -362,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; } diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h index 14bb77198..e99ec1983 100644 --- a/src/client/qwaylanddisplay_p.h +++ b/src/client/qwaylanddisplay_p.h @@ -76,6 +76,7 @@ QT_BEGIN_NAMESPACE class QAbstractEventDispatcher; class QSocketNotifier; class QPlatformScreen; +class QPlatformPlaceholderScreen; namespace QtWayland { class qt_surface_extension; @@ -96,6 +97,7 @@ 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,6 +161,7 @@ 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(); } @@ -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,6 +249,7 @@ private: QScopedPointer<QWaylandTouchExtension> mTouchExtension; QScopedPointer<QWaylandQtKeyExtension> mQtKeyExtension; QScopedPointer<QWaylandWindowManagerIntegration> mWindowManagerIntegration; + QScopedPointer<QWaylandTabletManagerV2> mTabletManager; #if QT_CONFIG(wayland_client_primary_selection) QScopedPointer<QWaylandPrimarySelectionDeviceManagerV1> mPrimarySelectionManager; #endif diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp index 320e34040..e0f0c6c8e 100644 --- a/src/client/qwaylandinputdevice.cpp +++ b/src/client/qwaylandinputdevice.cpp @@ -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" @@ -418,6 +419,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() @@ -630,8 +633,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) {} }; @@ -675,8 +678,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) {} }; @@ -705,8 +708,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) { } }; @@ -744,9 +747,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) { } }; @@ -755,9 +759,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) { } }; @@ -818,9 +823,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() @@ -848,7 +853,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) { } @@ -1004,6 +1009,8 @@ bool QWaylandInputDevice::Pointer::FrameData::hasPixelDelta() const case axis_source_finger: case axis_source_continuous: return !delta.isNull(); + default: + return false; } } @@ -1084,11 +1091,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; @@ -1408,8 +1417,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(); diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h index a567c57b4..448d0fce5 100644 --- a/src/client/qwaylandinputdevice_p.h +++ b/src/client/qwaylandinputdevice_p.h @@ -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; @@ -401,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, @@ -440,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; diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp index f6a80e18f..85c1990b6 100644 --- a/src/client/qwaylandintegration.cpp +++ b/src/client/qwaylandintegration.cpp @@ -86,7 +86,7 @@ #include "qwaylandinputdeviceintegration_p.h" #include "qwaylandinputdeviceintegrationfactory_p.h" -#ifndef QT_NO_ACCESSIBILITY_ATSPI_BRIDGE +#if QT_CONFIG(accessibility_atspi_bridge) #include <QtLinuxAccessibilitySupport/private/bridge_p.h> #endif @@ -94,41 +94,14 @@ #include <QtXkbCommonSupport/private/qxkbcommon_p.h> #endif -QT_BEGIN_NAMESPACE - -namespace QtWaylandClient { - -class GenericWaylandTheme: public QGenericUnixTheme -{ -public: - static QStringList themeNames() - { - QStringList result; - - if (QGuiApplication::desktopSettingsAware()) { - const QByteArray desktopEnvironment = QGuiApplicationPrivate::platformIntegration()->services()->desktopEnvironment(); - - if (desktopEnvironment == QByteArrayLiteral("KDE")) { -#if QT_CONFIG(settings) - result.push_back(QStringLiteral("kde")); +#if QT_CONFIG(vulkan) +#include "qwaylandvulkaninstance_p.h" +#include "qwaylandvulkanwindow_p.h" #endif - } else if (!desktopEnvironment.isEmpty() && - desktopEnvironment != QByteArrayLiteral("UNKNOWN") && - desktopEnvironment != QByteArrayLiteral("GNOME") && - desktopEnvironment != QByteArrayLiteral("UNITY") && - desktopEnvironment != QByteArrayLiteral("MATE") && - desktopEnvironment != QByteArrayLiteral("XFCE") && - desktopEnvironment != QByteArrayLiteral("LXDE")) - // Ignore X11 desktop environments - result.push_back(QString::fromLocal8Bit(desktopEnvironment.toLower())); - } - if (result.isEmpty()) - result.push_back(QLatin1String(QGenericUnixTheme::name)); +QT_BEGIN_NAMESPACE - return result; - } -}; +namespace QtWaylandClient { QWaylandIntegration::QWaylandIntegration() #if defined(Q_OS_MACOS) @@ -190,7 +163,12 @@ QPlatformWindow *QWaylandIntegration::createPlatformWindow(QWindow *window) cons && mDisplay->clientBufferIntegration()) return mDisplay->clientBufferIntegration()->createEglWindow(window); - return new QWaylandShmWindow(window); +#if QT_CONFIG(vulkan) + if (window->surfaceType() == QSurface::VulkanSurface) + return new QWaylandVulkanWindow(window, mDisplay.data()); +#endif // QT_CONFIG(vulkan) + + return new QWaylandShmWindow(window, mDisplay.data()); } #if QT_CONFIG(opengl) @@ -204,7 +182,7 @@ QPlatformOpenGLContext *QWaylandIntegration::createPlatformOpenGLContext(QOpenGL QPlatformBackingStore *QWaylandIntegration::createPlatformBackingStore(QWindow *window) const { - return new QWaylandShmBackingStore(window); + return new QWaylandShmBackingStore(window, mDisplay.data()); } QAbstractEventDispatcher *QWaylandIntegration::createEventDispatcher() const @@ -222,10 +200,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 @@ -271,7 +247,7 @@ QVariant QWaylandIntegration::styleHint(StyleHint hint) const QPlatformAccessibility *QWaylandIntegration::accessibility() const { if (!mAccessibility) { -#ifndef QT_NO_ACCESSIBILITY_ATSPI_BRIDGE +#if QT_CONFIG(accessibility_atspi_bridge) Q_ASSERT_X(QCoreApplication::eventDispatcher(), "QWaylandIntegration", "Initializing accessibility without event-dispatcher!"); mAccessibility.reset(new QSpiAccessibleBridge()); @@ -302,14 +278,21 @@ QList<int> QWaylandIntegration::possibleKeys(const QKeyEvent *event) const QStringList QWaylandIntegration::themeNames() const { - return GenericWaylandTheme::themeNames(); + return QGenericUnixTheme::themeNames(); } QPlatformTheme *QWaylandIntegration::createPlatformTheme(const QString &name) const { - return GenericWaylandTheme::createUnixTheme(name); + return QGenericUnixTheme::createUnixTheme(name); } +#if QT_CONFIG(vulkan) +QPlatformVulkanInstance *QWaylandIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const +{ + return new QWaylandVulkanInstance(instance); +} +#endif // QT_CONFIG(vulkan) + // May be called from non-GUI threads QWaylandClientBufferIntegration *QWaylandIntegration::clientBufferIntegration() const { @@ -442,6 +425,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) diff --git a/src/client/qwaylandintegration_p.h b/src/client/qwaylandintegration_p.h index a66999c7f..ff70ae25d 100644 --- a/src/client/qwaylandintegration_p.h +++ b/src/client/qwaylandintegration_p.h @@ -113,6 +113,10 @@ public: QPlatformTheme *createPlatformTheme(const QString &name) const override; +#if QT_CONFIG(vulkan) + QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const override; +#endif + QWaylandInputDevice *createInputDevice(QWaylandDisplay *display, int version, uint32_t id); virtual QWaylandClientBufferIntegration *clientBufferIntegration() const; diff --git a/src/client/qwaylandnativeinterface.cpp b/src/client/qwaylandnativeinterface.cpp index b4ecc0090..bf54a1a00 100644 --- a/src/client/qwaylandnativeinterface.cpp +++ b/src/client/qwaylandnativeinterface.cpp @@ -51,6 +51,9 @@ #include <QtGui/private/qguiapplication_p.h> #include <QtGui/QScreen> #include <QtWaylandClient/private/qwaylandclientbufferintegration_p.h> +#if QT_CONFIG(vulkan) +#include <QtWaylandClient/private/qwaylandvulkanwindow_p.h> +#endif #include <QtPlatformHeaders/qwaylandwindowfunctions.h> @@ -117,6 +120,15 @@ void *QWaylandNativeInterface::nativeResourceForWindow(const QByteArray &resourc if (lowerCaseResource == "egldisplay" && m_integration->clientBufferIntegration()) return m_integration->clientBufferIntegration()->nativeResource(QWaylandClientBufferIntegration::EglDisplay); +#if QT_CONFIG(vulkan) + if (lowerCaseResource == "vksurface") { + if (window->surfaceType() == QSurface::VulkanSurface && window->handle()) { + // return a pointer to the VkSurfaceKHR value, not the value itself + return static_cast<QWaylandVulkanWindow *>(window->handle())->surface(); + } + } +#endif + if (auto shellIntegration = m_integration->shellIntegration()) return shellIntegration->nativeResourceForWindow(resourceString, window); diff --git a/src/client/qwaylandscreen.cpp b/src/client/qwaylandscreen.cpp index e70796832..4f0cd9b0a 100644 --- a/src/client/qwaylandscreen.cpp +++ b/src/client/qwaylandscreen.cpp @@ -165,11 +165,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 +217,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); } diff --git a/src/client/qwaylandscreen_p.h b/src/client/qwaylandscreen_p.h index e9e07d9cd..ae91c6211 100644 --- a/src/client/qwaylandscreen_p.h +++ b/src/client/qwaylandscreen_p.h @@ -57,7 +57,6 @@ #include <QtWaylandClient/private/qwayland-wayland.h> #include <QtWaylandClient/private/qwayland-xdg-output-unstable-v1.h> - QT_BEGIN_NAMESPACE namespace QtWaylandClient { diff --git a/src/client/qwaylandshmbackingstore.cpp b/src/client/qwaylandshmbackingstore.cpp index 9b5971a21..8d5b977d5 100644 --- a/src/client/qwaylandshmbackingstore.cpp +++ b/src/client/qwaylandshmbackingstore.cpp @@ -151,9 +151,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) { } diff --git a/src/client/qwaylandshmbackingstore_p.h b/src/client/qwaylandshmbackingstore_p.h index 8a85cd7f3..e01632daf 100644 --- a/src/client/qwaylandshmbackingstore_p.h +++ b/src/client/qwaylandshmbackingstore_p.h @@ -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; diff --git a/src/client/qwaylandshmwindow.cpp b/src/client/qwaylandshmwindow.cpp index 52833803d..e305d028d 100644 --- a/src/client/qwaylandshmwindow.cpp +++ b/src/client/qwaylandshmwindow.cpp @@ -49,8 +49,8 @@ QT_BEGIN_NAMESPACE namespace QtWaylandClient { -QWaylandShmWindow::QWaylandShmWindow(QWindow *window) - : QWaylandWindow(window) +QWaylandShmWindow::QWaylandShmWindow(QWindow *window, QWaylandDisplay *display) + : QWaylandWindow(window, display) { } diff --git a/src/client/qwaylandshmwindow_p.h b/src/client/qwaylandshmwindow_p.h index ae1727859..81251b3aa 100644 --- a/src/client/qwaylandshmwindow_p.h +++ b/src/client/qwaylandshmwindow_p.h @@ -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; diff --git a/src/client/qwaylandsurface.cpp b/src/client/qwaylandsurface.cpp index c35f01b56..21e70ce4f 100644 --- a/src/client/qwaylandsurface.cpp +++ b/src/client/qwaylandsurface.cpp @@ -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(); } diff --git a/src/client/qwaylandtabletv2.cpp b/src/client/qwaylandtabletv2.cpp new file mode 100644 index 000000000..eb2e865f6 --- /dev/null +++ b/src/client/qwaylandtabletv2.cpp @@ -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 diff --git a/src/client/qwaylandtabletv2_p.h b/src/client/qwaylandtabletv2_p.h new file mode 100644 index 000000000..b4daaf5db --- /dev/null +++ b/src/client/qwaylandtabletv2_p.h @@ -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 diff --git a/src/client/qwaylandtouch.cpp b/src/client/qwaylandtouch.cpp index 0394aef31..8f56e7aa6 100644 --- a/src/client/qwaylandtouch.cpp +++ b/src/client/qwaylandtouch.cpp @@ -165,22 +165,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 +206,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) diff --git a/src/client/qwaylandvulkaninstance.cpp b/src/client/qwaylandvulkaninstance.cpp new file mode 100644 index 000000000..5edbd4757 --- /dev/null +++ b/src/client/qwaylandvulkaninstance.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of 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 "qwaylandvulkaninstance_p.h" +#include "qwaylandwindow_p.h" +#include "qwaylandscreen_p.h" +#include "qwaylanddisplay_p.h" + +QT_BEGIN_NAMESPACE + +namespace QtWaylandClient { + +QWaylandVulkanInstance::QWaylandVulkanInstance(QVulkanInstance *instance) + : m_instance(instance) +{ + loadVulkanLibrary(QStringLiteral("vulkan")); +} + +QWaylandVulkanInstance::~QWaylandVulkanInstance() = default; + +void QWaylandVulkanInstance::createOrAdoptInstance() +{ + QByteArrayList extraExtensions; + extraExtensions << QByteArrayLiteral("VK_KHR_wayland_surface"); + initInstance(m_instance, extraExtensions); + + if (!m_vkInst) + return; + + m_getPhysDevPresSupport = reinterpret_cast<PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR>( + m_vkGetInstanceProcAddr(m_vkInst, "vkGetPhysicalDeviceWaylandPresentationSupportKHR")); + if (!m_getPhysDevPresSupport) + qWarning() << "Failed to find vkGetPhysicalDeviceWaylandPresentationSupportKHR"; +} + +bool QWaylandVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + QWindow *window) +{ + if (!m_getPhysDevPresSupport || !m_getPhysDevSurfaceSupport) + return true; + + auto *w = static_cast<QWaylandWindow *>(window->handle()); + if (!w) { + qWarning() << "Attempted to call supportsPresent() without a valid platform window"; + return false; + } + wl_display *display = w->display()->wl_display(); + bool ok = m_getPhysDevPresSupport(physicalDevice, queueFamilyIndex, display); + + VkSurfaceKHR surface = QVulkanInstance::surfaceForWindow(window); + VkBool32 supported = false; + m_getPhysDevSurfaceSupport(physicalDevice, queueFamilyIndex, surface, &supported); + ok &= bool(supported); + + return ok; +} + +VkSurfaceKHR QWaylandVulkanInstance::createSurface(QWaylandWindow *window) +{ + VkSurfaceKHR surface = VK_NULL_HANDLE; + + if (!m_createSurface) { + m_createSurface = reinterpret_cast<PFN_vkCreateWaylandSurfaceKHR>( + m_vkGetInstanceProcAddr(m_vkInst, "vkCreateWaylandSurfaceKHR")); + } + if (!m_createSurface) { + qWarning() << "Failed to find vkCreateWaylandSurfaceKHR"; + return surface; + } + + VkWaylandSurfaceCreateInfoKHR surfaceInfo; + memset(&surfaceInfo, 0, sizeof(surfaceInfo)); + surfaceInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; + surfaceInfo.display = window->display()->wl_display(); + surfaceInfo.surface = window->wlSurface(); + VkResult err = m_createSurface(m_vkInst, &surfaceInfo, nullptr, &surface); + if (err != VK_SUCCESS) + qWarning("Failed to create Vulkan surface: %d", err); + + return surface; +} + +void QWaylandVulkanInstance::presentAboutToBeQueued(QWindow *window) +{ + auto *w = static_cast<QWaylandWindow *>(window->handle()); + if (!w) { + qWarning() << "Attempted to call presentAboutToBeQueued() without a valid platform window"; + return; + } + w->handleUpdate(); +} + +} // namespace QtWaylandClient + +QT_END_NAMESPACE diff --git a/src/client/qwaylandvulkaninstance_p.h b/src/client/qwaylandvulkaninstance_p.h new file mode 100644 index 000000000..b68293b78 --- /dev/null +++ b/src/client/qwaylandvulkaninstance_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of 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 QWAYLANDVULKANINSTANCE_P_H +#define QWAYLANDVULKANINSTANCE_P_H + +#if defined(VULKAN_H_) && !defined(VK_USE_PLATFORM_WAYLAND_KHR) +#error "vulkan.h included without Wayland WSI" +#endif + +#define VK_USE_PLATFORM_WAYLAND_KHR + +#include <QtVulkanSupport/private/qbasicvulkanplatforminstance_p.h> +#include <QLibrary> + +QT_BEGIN_NAMESPACE + +namespace QtWaylandClient { + +class QWaylandWindow; + +class QWaylandVulkanInstance : public QBasicPlatformVulkanInstance +{ +public: + explicit QWaylandVulkanInstance(QVulkanInstance *instance); + ~QWaylandVulkanInstance() override; + + void createOrAdoptInstance() override; + bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) override; + void presentAboutToBeQueued(QWindow *window) override; + + VkSurfaceKHR createSurface(QWaylandWindow *window); + +private: + QVulkanInstance *m_instance = nullptr; + PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR m_getPhysDevPresSupport = nullptr; + PFN_vkCreateWaylandSurfaceKHR m_createSurface = nullptr; +}; + +} // namespace QtWaylandClient + +QT_END_NAMESPACE + +#endif // QWAYLANDVULKANINSTANCE_P_H diff --git a/src/client/qwaylandvulkanwindow.cpp b/src/client/qwaylandvulkanwindow.cpp new file mode 100644 index 000000000..eb341529a --- /dev/null +++ b/src/client/qwaylandvulkanwindow.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** 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 "qwaylandvulkanwindow_p.h" + +QT_BEGIN_NAMESPACE + +namespace QtWaylandClient { + +QWaylandVulkanWindow::QWaylandVulkanWindow(QWindow *window, QWaylandDisplay *display) + : QWaylandWindow(window, display) +{ +} + +QWaylandVulkanWindow::~QWaylandVulkanWindow() +{ + if (m_surface) { + QVulkanInstance *inst = window()->vulkanInstance(); + if (inst) + static_cast<QWaylandVulkanInstance *>(inst->handle())->destroySurface(m_surface); + } +} + +QWaylandWindow::WindowType QWaylandVulkanWindow::windowType() const +{ + return QWaylandWindow::Vulkan; +} + +VkSurfaceKHR *QWaylandVulkanWindow::surface() +{ + if (m_surface) + return &m_surface; + + QVulkanInstance *vulkanInstance = window()->vulkanInstance(); + if (!vulkanInstance) { + qWarning() << "Attempted to create Vulkan surface without an instance; was QWindow::setVulkanInstance() called?"; + return nullptr; + } + + auto *waylandVulkanInstance = static_cast<QWaylandVulkanInstance *>(vulkanInstance->handle()); + m_surface = waylandVulkanInstance->createSurface(this); + + return &m_surface; +} + +} // namespace QtWaylandClient + +QT_END_NAMESPACE diff --git a/src/client/qwaylandvulkanwindow_p.h b/src/client/qwaylandvulkanwindow_p.h new file mode 100644 index 000000000..3fd394e62 --- /dev/null +++ b/src/client/qwaylandvulkanwindow_p.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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 QWAYLANDVULKANWINDOW_P_H +#define QWAYLANDVULKANWINDOW_P_H + +#include "qwaylandwindow_p.h" +#include "qwaylandvulkaninstance_p.h" + +QT_BEGIN_NAMESPACE + +namespace QtWaylandClient { + +class QWaylandVulkanWindow : public QWaylandWindow +{ +public: + explicit QWaylandVulkanWindow(QWindow *window, QWaylandDisplay *display); + ~QWaylandVulkanWindow() override; + + WindowType windowType() const override; + + VkSurfaceKHR *surface(); + +private: + VkSurfaceKHR m_surface = VK_NULL_HANDLE; +}; + +} // namespace QtWaylandClient + +QT_END_NAMESPACE + +#endif // QWAYLANDVULKANWINDOW_P_H diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp index 0df99d9fe..8cc26d71c 100644 --- a/src/client/qwaylandwindow.cpp +++ b/src/client/qwaylandwindow.cpp @@ -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")) { @@ -177,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() @@ -402,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) @@ -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) diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h index 5f15ca304..35fa1fdfc 100644 --- a/src/client/qwaylandwindow_p.h +++ b/src/client/qwaylandwindow_p.h @@ -89,10 +89,11 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandWindow : public QObject, public QPlatformW public: enum WindowType { Shm, - Egl + Egl, + Vulkan }; - QWaylandWindow(QWindow *window); + QWaylandWindow(QWindow *window, QWaylandDisplay *display); ~QWaylandWindow() override; virtual WindowType windowType() const = 0; @@ -128,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(); @@ -240,7 +242,7 @@ protected: bool mSentInitialResize = false; QPoint mOffset; int mScale = 1; - QWaylandScreen *mLastReportedScreen = nullptr; + QPlatformScreen *mLastReportedScreen = nullptr; QIcon mWindowIcon; @@ -261,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(); diff --git a/src/compositor/compositor_api/qwaylandcompositor.cpp b/src/compositor/compositor_api/qwaylandcompositor.cpp index e021b742b..e6402007e 100644 --- a/src/compositor/compositor_api/qwaylandcompositor.cpp +++ b/src/compositor/compositor_api/qwaylandcompositor.cpp @@ -196,11 +196,11 @@ void QWaylandCompositorPrivate::init() if (!socket_name.isEmpty()) { if (wl_display_add_socket(display, socket_name.constData())) - qFatal("Fatal: Failed to open server socket\n"); + qFatal("Fatal: Failed to open server socket: \"%s\". XDG_RUNTIME_DIR is: \"%s\"\n", socket_name.constData(), getenv("XDG_RUNTIME_DIR")); } else { const char *autoSocketName = wl_display_add_socket_auto(display); if (!autoSocketName) - qFatal("Fatal: Failed to open server socket\n"); + qFatal("Fatal: Failed to open default server socket. XDG_RUNTIME_DIR is: \"%s\"\n", getenv("XDG_RUNTIME_DIR")); socket_name = autoSocketName; emit q->socketNameChanged(socket_name); } diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp index 6c4ca8b13..357805393 100644 --- a/src/compositor/compositor_api/qwaylandquickitem.cpp +++ b/src/compositor/compositor_api/qwaylandquickitem.cpp @@ -74,7 +74,7 @@ static const struct { QSGMaterialType materialType; } bufferTypes[] = { // BufferFormatEgl_Null - { "", "", 0, 0, false, 0, {} }, + { "", "", 0, 0, false, {}, {} }, // BufferFormatEgl_RGB { @@ -289,8 +289,9 @@ public: } auto texture = buffer.toOpenGLTexture(); + GLuint textureId = texture->textureId(); auto size = surface->bufferSize(); - m_sgTex = surfaceItem->window()->createTextureFromId(texture->textureId(), size, opt); + m_sgTex = surfaceItem->window()->createTextureFromNativeObject(QQuickWindow::NativeObjectTexture, &textureId, 0, size, opt); #else qCWarning(qLcWaylandCompositor) << "Without OpenGL support only shared memory textures are supported"; #endif diff --git a/src/compositor/configure.json b/src/compositor/configure.json index 0dbb33643..42df2ddf0 100644 --- a/src/compositor/configure.json +++ b/src/compositor/configure.json @@ -9,14 +9,34 @@ "libraries": { "wayland-server": { "label": "wayland-server", - "test": "wayland", + "headers": "wayland-version.h", + "test": { + "main": [ + "#if WAYLAND_VERSION_MAJOR < 1", + "# error Wayland 1.8.0 or higher required", + "#endif", + "#if WAYLAND_VERSION_MAJOR == 1", + "# if WAYLAND_VERSION_MINOR < 8", + "# error Wayland 1.8.0 or higher required", + "# endif", + "# if WAYLAND_VERSION_MINOR == 8", + "# if WAYLAND_VERSION_MICRO < 0", + "# error Wayland 1.8.0 or higher required", + "# endif", + "# endif", + "#endif" + ] + }, "sources": [ { "type": "pkgConfig", "args": "wayland-server" }, "-lwayland-server" ] }, "wayland-egl": { - "test": "wayland_egl", + "headers": "wayland-egl.h", + "test": { + "main": "struct wl_egl_window *window = wl_egl_window_create(0, 100, 100);" + }, "sources": [ { "type": "pkgConfig", "args": "wayland-egl" }, "-lwayland-egl", @@ -45,14 +65,24 @@ ] }, "xcomposite": { - "test": "xcomposite", + "headers": "X11/extensions/Xcomposite.h", + "test": { + "main": "XCompositeRedirectWindow((Display *)0,(Window) 0, CompositeRedirectManual);" + }, "sources": [ { "type": "pkgConfig", "args": "xcomposite" }, "-lxcomposite" ] }, "glx": { - "test": "glx", + "headers": "GL/glx.h", + "test": { + "main": [ + "Display *dpy = XOpenDisplay(0);", + "int items = 0;", + "GLXFBConfig *fbc = glXChooseFBConfig(dpy, DefaultScreen(dpy), 0 , &items);" + ] + }, "sources": [ { "type": "pkgConfig", "args": "x11 gl" }, "-lX11 -lGl" @@ -68,30 +98,102 @@ }, "drm-egl-server": { "type": "compile", - "test": "drm_egl_server", + "test": { + "include": [ + "EGL/egl.h", + "EGL/eglext.h" + ], + "main": [ + "#ifdef EGL_MESA_drm_image", + "return 0;", + "#else", + "#error Requires EGL_MESA_drm_image to be defined", + "return 1;", + "#endif" + ] + }, "use": "egl" }, "libhybris-egl-server": { "type": "compile", - "test": "libhybris_egl_server", + "test": { + "include": [ + "EGL/egl.h", + "EGL/eglext.h", + "hybris/eglplatformcommon/hybris_nativebufferext.h" + ], + "main": [ + "#ifdef EGL_HYBRIS_native_buffer", + "return 0;", + "#else", + "#error Requires EGL_HYBRIS_native_buffer to be defined", + "return 1;", + "#endif" + ] + }, "use": "egl" }, "dmabuf-server-buffer": { "label": "Linux dma-buf Buffer Sharing", "type": "compile", - "test": "dmabuf_server_buffer", + "test": { + "include": [ + "EGL/egl.h", + "EGL/eglext.h", + "drm_fourcc.h" + ], + "main": [ + "#ifdef EGL_LINUX_DMA_BUF_EXT", + "return 0;", + "#else", + "#error Requires EGL_LINUX_DMA_BUF_EXT", + "return 1;", + "#endif" + ] + }, "use": "egl drm" }, "dmabuf-client-buffer": { "label": "Linux Client dma-buf Buffer Sharing", "type": "compile", - "test": "dmabuf_client_buffer", + "test": { + "include": [ + "EGL/egl.h", + "EGL/eglext.h", + "drm_mode.h", + "drm_fourcc.h" + ], + "main": [ + "// test if DMA BUF is supported", + "#ifndef EGL_LINUX_DMA_BUF_EXT", + "#error DMA BUF Extension not available", + "#endif", + "// test if DMA BUF import modifier extension is supported", + "#ifndef EGL_EXT_image_dma_buf_import_modifiers", + "#error DMA BUF Import modifier extension not available", + "#endif", + "return 0;" + ] + }, "use": "egl drm" }, "vulkan-server-buffer": { "label": "Vulkan Buffer Sharing", "type": "compile", - "test": "vulkan_server_buffer" + "test": { + "head": [ + "#define VK_USE_PLATFORM_WAYLAND_KHR 1" + ], + "include": [ + "vulkan/vulkan.h" + ], + "main": [ + "VkExportMemoryAllocateInfoKHR exportAllocInfo = {};", + "exportAllocInfo.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;", + "exportAllocInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;", + "return 0;" + ] + } } }, @@ -147,7 +249,7 @@ }, "wayland-vulkan-server-buffer": { "label": "Vulkan-based server buffer integration", - "condition": "features.wayland-server && features.opengl && features.egl && tests.vulkan-server-buffer", + "condition": "features.wayland-server && features.vulkan && features.opengl && features.egl && tests.vulkan-server-buffer", "output": [ "privateFeature" ] }, "wayland-shm-emulation-server-buffer": { diff --git a/src/compositor/extensions/qwaylandxdgshell.cpp b/src/compositor/extensions/qwaylandxdgshell.cpp index 1b8a3c2e2..6b7e86003 100644 --- a/src/compositor/extensions/qwaylandxdgshell.cpp +++ b/src/compositor/extensions/qwaylandxdgshell.cpp @@ -1725,7 +1725,7 @@ Qt::Orientations QWaylandXdgPopup::slideConstraints() const Q_D(const QWaylandXdgPopup); const uint flags = d->m_positionerData.constraintAdjustments; - Qt::Orientations constraints = 0; + Qt::Orientations constraints = {}; if (flags & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X) constraints |= Qt::Horizontal; @@ -1755,7 +1755,7 @@ Qt::Orientations QWaylandXdgPopup::flipConstraints() const Q_D(const QWaylandXdgPopup); const uint flags = d->m_positionerData.constraintAdjustments; - Qt::Orientations constraints = 0; + Qt::Orientations constraints = {}; if (flags & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X) constraints |= Qt::Horizontal; @@ -1785,7 +1785,7 @@ Qt::Orientations QWaylandXdgPopup::resizeConstraints() const Q_D(const QWaylandXdgPopup); const uint flags = d->m_positionerData.constraintAdjustments; - Qt::Orientations constraints = 0; + Qt::Orientations constraints = {}; if (flags & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X) constraints |= Qt::Horizontal; diff --git a/src/compositor/extensions/qwaylandxdgshell_p.h b/src/compositor/extensions/qwaylandxdgshell_p.h index 3223abf3a..de48f481d 100644 --- a/src/compositor/extensions/qwaylandxdgshell_p.h +++ b/src/compositor/extensions/qwaylandxdgshell_p.h @@ -63,8 +63,8 @@ QT_BEGIN_NAMESPACE struct Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgPositionerData { QSize size; QRect anchorRect; - Qt::Edges anchorEdges = 0; - Qt::Edges gravityEdges = 0; + Qt::Edges anchorEdges = {}; + Qt::Edges gravityEdges = {}; uint constraintAdjustments = XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE; QPoint offset; QWaylandXdgPositionerData(); diff --git a/src/compositor/extensions/qwaylandxdgshellv6.cpp b/src/compositor/extensions/qwaylandxdgshellv6.cpp index 934dccb06..94c430aad 100644 --- a/src/compositor/extensions/qwaylandxdgshellv6.cpp +++ b/src/compositor/extensions/qwaylandxdgshellv6.cpp @@ -1656,7 +1656,7 @@ Qt::Orientations QWaylandXdgPopupV6::slideConstraints() const Q_D(const QWaylandXdgPopupV6); const uint flags = d->m_positionerData.constraintAdjustments; - Qt::Orientations constraints = 0; + Qt::Orientations constraints = {}; if (flags & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X) constraints |= Qt::Horizontal; @@ -1686,7 +1686,7 @@ Qt::Orientations QWaylandXdgPopupV6::flipConstraints() const Q_D(const QWaylandXdgPopupV6); const uint flags = d->m_positionerData.constraintAdjustments; - Qt::Orientations constraints = 0; + Qt::Orientations constraints = {}; if (flags & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X) constraints |= Qt::Horizontal; @@ -1716,7 +1716,7 @@ Qt::Orientations QWaylandXdgPopupV6::resizeConstraints() const Q_D(const QWaylandXdgPopupV6); const uint flags = d->m_positionerData.constraintAdjustments; - Qt::Orientations constraints = 0; + Qt::Orientations constraints = {}; if (flags & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X) constraints |= Qt::Horizontal; diff --git a/src/compositor/extensions/qwaylandxdgshellv6_p.h b/src/compositor/extensions/qwaylandxdgshellv6_p.h index 457bc2201..f13e73da4 100644 --- a/src/compositor/extensions/qwaylandxdgshellv6_p.h +++ b/src/compositor/extensions/qwaylandxdgshellv6_p.h @@ -61,8 +61,8 @@ QT_BEGIN_NAMESPACE struct Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgPositionerV6Data { QSize size; QRect anchorRect; - Qt::Edges anchorEdges = 0; - Qt::Edges gravityEdges = 0; + Qt::Edges anchorEdges = {}; + Qt::Edges gravityEdges = {}; uint constraintAdjustments = ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_NONE; QPoint offset; QWaylandXdgPositionerV6Data(); diff --git a/src/compositor/extensions/qwltexturesharingextension.cpp b/src/compositor/extensions/qwltexturesharingextension.cpp index 6f801e956..bbd18e1a5 100644 --- a/src/compositor/extensions/qwltexturesharingextension.cpp +++ b/src/compositor/extensions/qwltexturesharingextension.cpp @@ -301,13 +301,13 @@ QString QWaylandTextureSharingExtension::getExistingFilePath(const QString &key) if (key.contains(QLatin1String("../"))) return QString(); - for (auto dir : m_image_dirs) { + for (auto dir : qAsConst(m_image_dirs)) { QString path = dir + key; if (QFileInfo::exists(path)) return path; } - for (auto dir : m_image_dirs) { + for (auto dir : qAsConst(m_image_dirs)) { for (auto ext : m_image_suffixes) { QString fp = dir + key + ext; //qDebug() << "trying" << fp; diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandeglclientbufferintegration.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandeglclientbufferintegration.cpp index 3a34d2561..0dc389bb8 100644 --- a/src/hardwareintegration/client/wayland-egl/qwaylandeglclientbufferintegration.cpp +++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglclientbufferintegration.cpp @@ -143,7 +143,7 @@ bool QWaylandEglClientBufferIntegration::supportsWindowDecoration() const QWaylandWindow *QWaylandEglClientBufferIntegration::createEglWindow(QWindow *window) { - return new QWaylandEglWindow(window); + return new QWaylandEglWindow(window, m_display); } QPlatformOpenGLContext *QWaylandEglClientBufferIntegration::createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp index 030422c56..e8d43fad4 100644 --- a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp +++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp @@ -54,8 +54,8 @@ QT_BEGIN_NAMESPACE namespace QtWaylandClient { -QWaylandEglWindow::QWaylandEglWindow(QWindow *window) - : QWaylandWindow(window) +QWaylandEglWindow::QWaylandEglWindow(QWindow *window, QWaylandDisplay *display) + : QWaylandWindow(window, display) , m_clientBufferIntegration(static_cast<QWaylandEglClientBufferIntegration *>(mDisplay->clientBufferIntegration())) { QSurfaceFormat fmt = window->requestedFormat(); diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h index 9e6cb876c..878532afc 100644 --- a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h +++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.h @@ -56,7 +56,7 @@ class QWaylandEglWindow : public QWaylandWindow { Q_OBJECT public: - QWaylandEglWindow(QWindow *window); + QWaylandEglWindow(QWindow *window, QWaylandDisplay *display); ~QWaylandEglWindow(); WindowType windowType() const override; void ensureSize() override; diff --git a/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglwindow.cpp b/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglwindow.cpp index 57a7ba7b6..a7377830f 100644 --- a/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglwindow.cpp +++ b/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglwindow.cpp @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE namespace QtWaylandClient { QWaylandXCompositeEGLWindow::QWaylandXCompositeEGLWindow(QWindow *window, QWaylandXCompositeEGLClientBufferIntegration *glxIntegration) - : QWaylandWindow(window) + : QWaylandWindow(window, glxIntegration->waylandDisplay()) , m_glxIntegration(glxIntegration) , m_config(q_configFromGLFormat(glxIntegration->eglDisplay(), window->format(), true, EGL_WINDOW_BIT | EGL_PIXMAP_BIT)) { diff --git a/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxwindow.cpp b/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxwindow.cpp index 2b491e24d..b0c78b631 100644 --- a/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxwindow.cpp +++ b/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxwindow.cpp @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE namespace QtWaylandClient { QWaylandXCompositeGLXWindow::QWaylandXCompositeGLXWindow(QWindow *window, QWaylandXCompositeGLXIntegration *glxIntegration) - : QWaylandWindow(window) + : QWaylandWindow(window, glxIntegration->waylandDisplay()) , m_glxIntegration(glxIntegration) , m_config(qglx_findConfig(glxIntegration->xDisplay(), glxIntegration->screen(), window->format(), GLX_WINDOW_BIT | GLX_PIXMAP_BIT)) { diff --git a/src/plugins/hardwareintegration/compositor/brcm-egl/brcm-egl.pro b/src/plugins/hardwareintegration/compositor/brcm-egl/brcm-egl.pro index 53f7af8aa..c89ecec00 100644 --- a/src/plugins/hardwareintegration/compositor/brcm-egl/brcm-egl.pro +++ b/src/plugins/hardwareintegration/compositor/brcm-egl/brcm-egl.pro @@ -5,6 +5,8 @@ OTHER_FILES += brcm-egl.json SOURCES += \ main.cpp +TARGET = qt-wayland-compositor-brcm-egl + include(../../../../hardwareintegration/compositor/brcm-egl/brcm-egl.pri) PLUGIN_TYPE = wayland-graphics-integration-server diff --git a/src/plugins/hardwareintegration/compositor/dmabuf-server/dmabuf-server.pro b/src/plugins/hardwareintegration/compositor/dmabuf-server/dmabuf-server.pro index 1601a384c..d96e58135 100644 --- a/src/plugins/hardwareintegration/compositor/dmabuf-server/dmabuf-server.pro +++ b/src/plugins/hardwareintegration/compositor/dmabuf-server/dmabuf-server.pro @@ -5,7 +5,9 @@ OTHER_FILES += dmabuf-server.json SOURCES += \ main.cpp -include($PWD/../../../../../hardwareintegration/compositor/dmabuf-server/dmabuf-server.pri) +TARGET = qt-wayland-compositor-dmabuf-server-buffer + +include(../../../../hardwareintegration/compositor/dmabuf-server/dmabuf-server.pri) PLUGIN_TYPE = wayland-graphics-integration-server PLUGIN_CLASS_NAME = DmaBufServerBufferIntegrationPlugin diff --git a/src/plugins/hardwareintegration/compositor/drm-egl-server/drm-egl-server.pro b/src/plugins/hardwareintegration/compositor/drm-egl-server/drm-egl-server.pro index 040031122..2ba17c388 100644 --- a/src/plugins/hardwareintegration/compositor/drm-egl-server/drm-egl-server.pro +++ b/src/plugins/hardwareintegration/compositor/drm-egl-server/drm-egl-server.pro @@ -5,7 +5,9 @@ OTHER_FILES += drm-egl-server.json SOURCES += \ main.cpp -include($PWD/../../../../../hardwareintegration/compositor/drm-egl-server/drm-egl-server.pri) +TARGET = qt-wayland-compositor-drm-egl-server-buffer + +include(../../../../hardwareintegration/compositor/drm-egl-server/drm-egl-server.pri) PLUGIN_TYPE = wayland-graphics-integration-server PLUGIN_CLASS_NAME = DrmEglServerBufferIntegrationPlugin diff --git a/src/plugins/hardwareintegration/compositor/hardwarelayer/vsp2/vsp2.pro b/src/plugins/hardwareintegration/compositor/hardwarelayer/vsp2/vsp2.pro index ff16b20bf..c18884a96 100644 --- a/src/plugins/hardwareintegration/compositor/hardwarelayer/vsp2/vsp2.pro +++ b/src/plugins/hardwareintegration/compositor/hardwarelayer/vsp2/vsp2.pro @@ -7,7 +7,9 @@ OTHER_FILES += vsp2.json SOURCES += \ main.cpp -include($PWD/../../../../../../hardwareintegration/compositor/hardwarelayer/vsp2/vsp2.pri) +TARGET = qt-wayland-compositor-vsp2 + +include(../../../../../hardwareintegration/compositor/hardwarelayer/vsp2/vsp2.pri) PLUGIN_TYPE = wayland-hardware-layer-integration PLUGIN_CLASS_NAME = Vsp2HardwareLayerIntegrationPlugin diff --git a/src/plugins/hardwareintegration/compositor/libhybris-egl-server/libhybris-egl-server.pro b/src/plugins/hardwareintegration/compositor/libhybris-egl-server/libhybris-egl-server.pro index 9e28c7e8c..c9c3a0daf 100644 --- a/src/plugins/hardwareintegration/compositor/libhybris-egl-server/libhybris-egl-server.pro +++ b/src/plugins/hardwareintegration/compositor/libhybris-egl-server/libhybris-egl-server.pro @@ -5,7 +5,9 @@ OTHER_FILES += libhybris-egl-server.json SOURCES += \ main.cpp -include($PWD/../../../../../hardwareintegration/compositor/libhybris-egl-server/libhybris-egl-server.pri) +TARGET = qt-wayland-compositor-libybris-egl-server.json + +include(../../../../hardwareintegration/compositor/libhybris-egl-server/libhybris-egl-server.pri) PLUGIN_TYPE = wayland-graphics-integration-server PLUGIN_CLASS_NAME = LibHybrisEglServerBufferIntegrationPlugin diff --git a/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pro b/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pro index bc4311423..1f76f9f00 100644 --- a/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pro +++ b/src/plugins/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pro @@ -5,6 +5,8 @@ OTHER_FILES += linux-dmabuf.json SOURCES += \ main.cpp \ +TARGET = qt-wayland-compositor-linux-dmabuf-unstable-v1 + include(../../../../hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pri) PLUGIN_TYPE = wayland-graphics-integration-server diff --git a/src/plugins/hardwareintegration/compositor/shm-emulation-server/shm-emulation-server.pro b/src/plugins/hardwareintegration/compositor/shm-emulation-server/shm-emulation-server.pro index 56a1bac21..865af1a7d 100644 --- a/src/plugins/hardwareintegration/compositor/shm-emulation-server/shm-emulation-server.pro +++ b/src/plugins/hardwareintegration/compositor/shm-emulation-server/shm-emulation-server.pro @@ -5,7 +5,9 @@ OTHER_FILES += shm-emulation-server.json SOURCES += \ main.cpp -include($PWD/../../../../../hardwareintegration/compositor/shm-emulation-server/shm-emulation-server.pri) +TARGET = qt-wayland-compositor-shm-emulation-server + +include(../../../../hardwareintegration/compositor/shm-emulation-server/shm-emulation-server.pri) PLUGIN_TYPE = wayland-graphics-integration-server PLUGIN_CLASS_NAME = ShmServerBufferIntegrationPlugin diff --git a/src/plugins/hardwareintegration/compositor/vulkan-server/vulkan-server.pro b/src/plugins/hardwareintegration/compositor/vulkan-server/vulkan-server.pro index 053654218..dc82c3f26 100644 --- a/src/plugins/hardwareintegration/compositor/vulkan-server/vulkan-server.pro +++ b/src/plugins/hardwareintegration/compositor/vulkan-server/vulkan-server.pro @@ -5,7 +5,9 @@ OTHER_FILES += vulkan-server.json SOURCES += \ main.cpp -include($PWD/../../../../../hardwareintegration/compositor/vulkan-server/vulkan-server.pri) +TARGET = qt-wayland-compositor-vulkan-server + +include(../../../../hardwareintegration/compositor/vulkan-server/vulkan-server.pri) PLUGIN_TYPE = wayland-graphics-integration-server PLUGIN_CLASS_NAME = VulkanServerBufferIntegrationPlugin diff --git a/src/plugins/hardwareintegration/compositor/wayland-egl/wayland-egl.pro b/src/plugins/hardwareintegration/compositor/wayland-egl/wayland-egl.pro index 6aecefffd..d452220c5 100644 --- a/src/plugins/hardwareintegration/compositor/wayland-egl/wayland-egl.pro +++ b/src/plugins/hardwareintegration/compositor/wayland-egl/wayland-egl.pro @@ -5,7 +5,7 @@ OTHER_FILES += wayland-egl.json SOURCES += \ main.cpp -TARGET = qt-plugin-wayland-egl +TARGET = qt-wayland-compositor-wayland-egl include(../../../../hardwareintegration/compositor/wayland-egl/wayland-egl.pri) diff --git a/src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/wayland-eglstream-controller.pro b/src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/wayland-eglstream-controller.pro index f1ca7183a..6d259a687 100644 --- a/src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/wayland-eglstream-controller.pro +++ b/src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/wayland-eglstream-controller.pro @@ -5,6 +5,8 @@ OTHER_FILES += wayland-eglstream-controller.json SOURCES += \ main.cpp \ +TARGET = qt-wayland-compositor-wayland-eglstream-controller + include(../../../../hardwareintegration/compositor/wayland-eglstream-controller/wayland-eglstream-controller.pri) PLUGIN_TYPE = wayland-graphics-integration-server diff --git a/src/plugins/hardwareintegration/compositor/xcomposite-egl/xcomposite-egl.pro b/src/plugins/hardwareintegration/compositor/xcomposite-egl/xcomposite-egl.pro index 7c391bd1c..298ed2fc6 100644 --- a/src/plugins/hardwareintegration/compositor/xcomposite-egl/xcomposite-egl.pro +++ b/src/plugins/hardwareintegration/compositor/xcomposite-egl/xcomposite-egl.pro @@ -5,6 +5,8 @@ OTHER_FILES += xcomposite-egl.json SOURCES += \ main.cpp +TARGET = qt-wayland-compositor-xcomposite-egl + include(../../../../hardwareintegration/compositor/xcomposite-egl/xcomposite-egl.pri) PLUGIN_TYPE = wayland-graphics-integration-server diff --git a/src/plugins/hardwareintegration/compositor/xcomposite-glx/xcomposite-glx.pro b/src/plugins/hardwareintegration/compositor/xcomposite-glx/xcomposite-glx.pro index 0f49471da..41e5c2ec5 100644 --- a/src/plugins/hardwareintegration/compositor/xcomposite-glx/xcomposite-glx.pro +++ b/src/plugins/hardwareintegration/compositor/xcomposite-glx/xcomposite-glx.pro @@ -5,6 +5,8 @@ OTHER_FILES += xcomposite-glx.json SOURCES += \ main.cpp +TARGET = qt-wayland-compositor-xcomposite-glx + include(../../../../hardwareintegration/compositor/xcomposite-glx/xcomposite-glx.pri) PLUGIN_TYPE = wayland-graphics-integration-server diff --git a/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.cpp b/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.cpp index 26f598895..636ef0807 100644 --- a/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.cpp +++ b/src/plugins/shellintegration/fullscreen-shell-v1/qwaylandfullscreenshellv1surface.cpp @@ -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 diff --git a/src/qtwaylandscanner/qtwaylandscanner.cpp b/src/qtwaylandscanner/qtwaylandscanner.cpp index 9691b857f..05f00beee 100644 --- a/src/qtwaylandscanner/qtwaylandscanner.cpp +++ b/src/qtwaylandscanner/qtwaylandscanner.cpp @@ -92,7 +92,7 @@ private: }; bool isServerSide(); - bool parseOption(const char *str); + bool parseOption(const QByteArray &str); QByteArray byteArrayValue(const QXmlStreamReader &xml, const char *name); int intValue(const QXmlStreamReader &xml, const char *name, int defaultValue = 0); @@ -123,29 +123,55 @@ private: QByteArray m_scannerName; QByteArray m_headerPath; QByteArray m_prefix; + QVector <QByteArray> m_includes; QXmlStreamReader *m_xml = nullptr; }; bool Scanner::parseArguments(int argc, char **argv) { - m_scannerName = argv[0]; + QVector<QByteArray> args; + args.reserve(argc); + for (int i = 0; i < argc; ++i) + args << QByteArray(argv[i]); - if (argc <= 2 || !parseOption(argv[1])) + m_scannerName = args[0]; + + if (argc <= 2 || !parseOption(args[1])) return false; - m_protocolFilePath = QByteArray(argv[2]); + m_protocolFilePath = args[2]; - if (argc >= 4) - m_headerPath = QByteArray(argv[3]); - if (argc == 5) - m_prefix = QByteArray(argv[4]); + if (argc > 3 && !args[3].startsWith('-')) { + // legacy positional arguments + m_headerPath = args[3]; + if (argc == 5) + m_prefix = args[4]; + } else { + // --header-path=<path> (14 characters) + // --prefix=<prefix> (9 characters) + // --add-include=<include> (14 characters) + for (int pos = 3; pos < argc; pos++) { + const QByteArray &option = args[pos]; + if (option.startsWith("--header-path=")) { + m_headerPath = option.mid(14); + } else if (option.startsWith("--prefix=")) { + m_prefix = option.mid(10); + } else if (option.startsWith("--add-include=")) { + auto include = option.mid(14); + if (!include.isEmpty()) + m_includes << include; + } else { + return false; + } + } + } return true; } void Scanner::printUsage() { - fprintf(stderr, "Usage: %s [client-header|server-header|client-code|server-code] specfile [header-path] [prefix]\n", m_scannerName.constData()); + fprintf(stderr, "Usage: %s [client-header|server-header|client-code|server-code] specfile [--header-path=<path>] [--prefix=<prefix>] [--add-include=<include>]\n", m_scannerName.constData()); } bool Scanner::isServerSide() @@ -153,15 +179,15 @@ bool Scanner::isServerSide() return m_option == ServerHeader || m_option == ServerCode; } -bool Scanner::parseOption(const char *str) +bool Scanner::parseOption(const QByteArray &str) { - if (str == QLatin1String("client-header")) + if (str == "client-header") m_option = ClientHeader; - else if (str == QLatin1String("server-header")) + else if (str == "server-header") m_option = ServerHeader; - else if (str == QLatin1String("client-code")) + else if (str == "client-code") m_option = ClientCode; - else if (str == QLatin1String("server-code")) + else if (str == "server-code") m_option = ServerCode; else return false; @@ -441,6 +467,12 @@ 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()); + if (m_option == ServerHeader) { QByteArray inclusionGuard = QByteArray("QT_WAYLAND_SERVER_") + preProcessorProtocolName.constData(); printf("#ifndef %s\n", inclusionGuard.constData()); |