From 7e0f7d3abd4a02f423a5b95616840e028a9af7fa Mon Sep 17 00:00:00 2001 From: Riteo Date: Fri, 15 Dec 2023 02:55:34 +0100 Subject: [PATCH] Add Wayland support Not everything is yet implemented, either for Godot or personal limitations (I don't have all hardware in the world). A brief list of the most important issues follows: - Single-window only: the `DisplayServer` API doesn't expose enough information for properly creating XDG shell windows. - Very dumb rendering loop: this is very complicated, just know that the low consumption mode is forced to 2000 Hz and some clever hacks are in place to overcome a specific Wayland limitation. This will be improved to the extent possible both downstream and upstream. - Features to implement yet: IME, touch input, native file dialog, drawing tablet (commented out due to a refactor), screen recording. - Mouse passthrough can't be implement through a poly API, we need a rect-based one. - The cursor doesn't yet support fractional scaling. - Auto scale is rounded up when using fractional scaling as we don't have a per-window scale query API (basically we need `DisplayServer::window_get_scale`). - Building with `x11=no wayland=yes opengl=yes openxr=yes` fails. This also adds a new project property and editor setting for selecting the default DisplayServer to start, to allow this backend to start first in exported projects (X11 is still the default for now). The editor setting always overrides the project setting. Special thanks to Drew Devault, toger5, Sebastian Krzyszkowiak, Leandro Benedet Garcia, Subhransu, Yury Zhuravlev and Mara Huldra. --- .github/workflows/linux_builds.yml | 5 + COPYRIGHT.txt | 20 + doc/classes/DisplayServer.xml | 88 +- doc/classes/EditorSettings.xml | 3 + doc/classes/ProjectSettings.xml | 18 + drivers/vulkan/SCsub | 7 +- editor/editor_settings.cpp | 10 + main/main.cpp | 96 +- modules/openxr/SCsub | 3 + .../platform/openxr_opengl_extension.cpp | 12 +- platform/linuxbsd/SCsub | 3 + platform/linuxbsd/detect.py | 44 +- platform/linuxbsd/export/export.cpp | 2 +- platform/linuxbsd/os_linuxbsd.cpp | 16 + platform/linuxbsd/os_linuxbsd.h | 2 + platform/linuxbsd/wayland/SCsub | 197 + .../linuxbsd/wayland/detect_prime_egl.cpp | 231 + platform/linuxbsd/wayland/detect_prime_egl.h | 65 + .../wayland/display_server_wayland.cpp | 1353 ++++ .../linuxbsd/wayland/display_server_wayland.h | 290 + .../wayland/dynwrappers/libdecor-so_wrap.c | 453 ++ .../wayland/dynwrappers/libdecor-so_wrap.h | 175 + .../dynwrappers/wayland-client-core-so_wrap.c | 607 ++ .../dynwrappers/wayland-client-core-so_wrap.h | 231 + .../dynwrappers/wayland-cursor-so_wrap.c | 89 + .../dynwrappers/wayland-cursor-so_wrap.h | 42 + .../dynwrappers/wayland-egl-core-so_wrap.c | 67 + .../dynwrappers/wayland-egl-core-so_wrap.h | 34 + .../linuxbsd/wayland/egl_manager_wayland.cpp | 66 + .../linuxbsd/wayland/egl_manager_wayland.h | 53 + platform/linuxbsd/wayland/key_mapping_xkb.cpp | 411 ++ platform/linuxbsd/wayland/key_mapping_xkb.h | 65 + .../wayland/vulkan_context_wayland.cpp | 59 + .../linuxbsd/wayland/vulkan_context_wayland.h | 52 + platform/linuxbsd/wayland/wayland_thread.cpp | 4004 +++++++++++ platform/linuxbsd/wayland/wayland_thread.h | 930 +++ thirdparty/README.md | 43 + thirdparty/linuxbsd_headers/README.md | 14 + .../linuxbsd_headers/libdecor-0/libdecor.h | 521 ++ .../wayland/wayland-client-core.h | 292 + .../wayland/wayland-client-protocol.h | 6106 +++++++++++++++++ .../linuxbsd_headers/wayland/wayland-client.h | 42 + .../linuxbsd_headers/wayland/wayland-cursor.h | 96 + .../wayland/wayland-egl-core.h | 59 + .../linuxbsd_headers/wayland/wayland-util.h | 765 +++ .../wayland/wayland-version.h | 34 + thirdparty/wayland-protocols/COPYING | 33 + .../stable/viewporter/README | 7 + .../stable/viewporter/viewporter.xml | 180 + .../wayland-protocols/stable/xdg-shell/README | 5 + .../stable/xdg-shell/xdg-shell.xml | 1370 ++++ .../staging/fractional-scale/README | 4 + .../fractional-scale/fractional-scale-v1.xml | 102 + .../staging/xdg-activation/README | 4 + .../xdg-activation/xdg-activation-v1.xml | 200 + .../unstable/idle-inhibit/README | 4 + .../idle-inhibit/idle-inhibit-unstable-v1.xml | 83 + .../unstable/pointer-constraints/README | 4 + .../pointer-constraints-unstable-v1.xml | 339 + .../unstable/pointer-gestures/README | 4 + .../pointer-gestures-unstable-v1.xml | 253 + .../unstable/primary-selection/README | 4 + .../primary-selection-unstable-v1.xml | 225 + .../unstable/relative-pointer/README | 4 + .../relative-pointer-unstable-v1.xml | 136 + .../wayland-protocols/unstable/tablet/README | 4 + .../unstable/tablet/tablet-unstable-v2.xml | 1178 ++++ .../unstable/xdg-decoration/README | 4 + .../xdg-decoration-unstable-v1.xml | 156 + thirdparty/wayland/COPYING | 29 + thirdparty/wayland/protocol/wayland.xml | 3058 +++++++++ 71 files changed, 25085 insertions(+), 80 deletions(-) create mode 100644 platform/linuxbsd/wayland/SCsub create mode 100644 platform/linuxbsd/wayland/detect_prime_egl.cpp create mode 100644 platform/linuxbsd/wayland/detect_prime_egl.h create mode 100644 platform/linuxbsd/wayland/display_server_wayland.cpp create mode 100644 platform/linuxbsd/wayland/display_server_wayland.h create mode 100644 platform/linuxbsd/wayland/dynwrappers/libdecor-so_wrap.c create mode 100644 platform/linuxbsd/wayland/dynwrappers/libdecor-so_wrap.h create mode 100644 platform/linuxbsd/wayland/dynwrappers/wayland-client-core-so_wrap.c create mode 100644 platform/linuxbsd/wayland/dynwrappers/wayland-client-core-so_wrap.h create mode 100644 platform/linuxbsd/wayland/dynwrappers/wayland-cursor-so_wrap.c create mode 100644 platform/linuxbsd/wayland/dynwrappers/wayland-cursor-so_wrap.h create mode 100644 platform/linuxbsd/wayland/dynwrappers/wayland-egl-core-so_wrap.c create mode 100644 platform/linuxbsd/wayland/dynwrappers/wayland-egl-core-so_wrap.h create mode 100644 platform/linuxbsd/wayland/egl_manager_wayland.cpp create mode 100644 platform/linuxbsd/wayland/egl_manager_wayland.h create mode 100644 platform/linuxbsd/wayland/key_mapping_xkb.cpp create mode 100644 platform/linuxbsd/wayland/key_mapping_xkb.h create mode 100644 platform/linuxbsd/wayland/vulkan_context_wayland.cpp create mode 100644 platform/linuxbsd/wayland/vulkan_context_wayland.h create mode 100644 platform/linuxbsd/wayland/wayland_thread.cpp create mode 100644 platform/linuxbsd/wayland/wayland_thread.h create mode 100644 thirdparty/linuxbsd_headers/libdecor-0/libdecor.h create mode 100644 thirdparty/linuxbsd_headers/wayland/wayland-client-core.h create mode 100644 thirdparty/linuxbsd_headers/wayland/wayland-client-protocol.h create mode 100644 thirdparty/linuxbsd_headers/wayland/wayland-client.h create mode 100644 thirdparty/linuxbsd_headers/wayland/wayland-cursor.h create mode 100644 thirdparty/linuxbsd_headers/wayland/wayland-egl-core.h create mode 100644 thirdparty/linuxbsd_headers/wayland/wayland-util.h create mode 100644 thirdparty/linuxbsd_headers/wayland/wayland-version.h create mode 100644 thirdparty/wayland-protocols/COPYING create mode 100644 thirdparty/wayland-protocols/stable/viewporter/README create mode 100644 thirdparty/wayland-protocols/stable/viewporter/viewporter.xml create mode 100644 thirdparty/wayland-protocols/stable/xdg-shell/README create mode 100644 thirdparty/wayland-protocols/stable/xdg-shell/xdg-shell.xml create mode 100644 thirdparty/wayland-protocols/staging/fractional-scale/README create mode 100644 thirdparty/wayland-protocols/staging/fractional-scale/fractional-scale-v1.xml create mode 100644 thirdparty/wayland-protocols/staging/xdg-activation/README create mode 100644 thirdparty/wayland-protocols/staging/xdg-activation/xdg-activation-v1.xml create mode 100644 thirdparty/wayland-protocols/unstable/idle-inhibit/README create mode 100644 thirdparty/wayland-protocols/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml create mode 100644 thirdparty/wayland-protocols/unstable/pointer-constraints/README create mode 100644 thirdparty/wayland-protocols/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml create mode 100644 thirdparty/wayland-protocols/unstable/pointer-gestures/README create mode 100644 thirdparty/wayland-protocols/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml create mode 100644 thirdparty/wayland-protocols/unstable/primary-selection/README create mode 100644 thirdparty/wayland-protocols/unstable/primary-selection/primary-selection-unstable-v1.xml create mode 100644 thirdparty/wayland-protocols/unstable/relative-pointer/README create mode 100644 thirdparty/wayland-protocols/unstable/relative-pointer/relative-pointer-unstable-v1.xml create mode 100644 thirdparty/wayland-protocols/unstable/tablet/README create mode 100644 thirdparty/wayland-protocols/unstable/tablet/tablet-unstable-v2.xml create mode 100644 thirdparty/wayland-protocols/unstable/xdg-decoration/README create mode 100644 thirdparty/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml create mode 100644 thirdparty/wayland/COPYING create mode 100644 thirdparty/wayland/protocol/wayland.xml diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml index afdb74394c7..914f0394e49 100644 --- a/.github/workflows/linux_builds.yml +++ b/.github/workflows/linux_builds.yml @@ -96,6 +96,11 @@ jobs: sudo add-apt-repository "deb https://ppa.launchpadcontent.net/kisak/turtle/ubuntu focal main" sudo apt-get install -qq mesa-vulkan-drivers + # TODO: Figure out somehow how to embed this one. + - name: wayland-scanner dependency + run: | + sudo apt-get install libwayland-bin + - name: Free disk space on runner run: | echo "Disk usage before:" && df -h diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index 125c5618c7d..d2250b76255 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -515,6 +515,26 @@ Comment: Vulkan Memory Allocator Copyright: 2017-2021, Advanced Micro Devices, Inc. License: Expat +Files: ./thirdparty/wayland/ +Comment: Wayland core protocol +Copyright: 2008-2012, Kristian Høgsberg + 2010-2012, Intel Corporation + 2011, Benjamin Franzke + 2012, Collabora, Ltd. +License: Expat + +Files: ./thirdparty/wayland-protocols/ +Comment: Wayland protocols that add functionality not available in the core protocol +Copyright: 2008-2013, Kristian Høgsberg + 2010-2013, Intel Corporation + 2013, Rafael Antognolli + 2013, Jasper St. Pierre + 2014, Jonas Ådahl + 2014, Jason Ekstrand + 2014-2015, Collabora, Ltd. + 2015, Red Hat Inc. +License: Expat + Files: ./thirdparty/wslay/ Comment: Wslay Copyright: 2011, 2012, 2015, Tatsuhiro Tsujikawa diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index eb8ed56a029..57a4aea93bd 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -26,7 +26,7 @@ Returns the user's [url=https://unix.stackexchange.com/questions/139191/whats-the-difference-between-primary-selection-and-clipboard-buffer]primary[/url] clipboard as a string if possible. This is the clipboard that is set when the user selects text in any application, rather than when pressing [kbd]Ctrl + C[/kbd]. The clipboard data can then be pasted by clicking the middle mouse button in any application that supports the primary clipboard mechanism. - [b]Note:[/b] This method is only implemented on Linux (X11). + [b]Note:[/b] This method is only implemented on Linux (X11/Wayland). @@ -53,7 +53,7 @@ Sets the user's [url=https://unix.stackexchange.com/questions/139191/whats-the-difference-between-primary-selection-and-clipboard-buffer]primary[/url] clipboard content to the given string. This is the clipboard that is set when the user selects text in any application, rather than when pressing [kbd]Ctrl + C[/kbd]. The clipboard data can then be pasted by clicking the middle mouse button in any application that supports the primary clipboard mechanism. - [b]Note:[/b] This method is only implemented on Linux (X11). + [b]Note:[/b] This method is only implemented on Linux (X11/Wayland). @@ -120,7 +120,7 @@ Displays OS native dialog for selecting files or directories in the file system. Callbacks have the following arguments: [code]status: bool, selected_paths: PackedStringArray, selected_filter_index: int[/code]. - [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG] feature, i.e. Linux, Windows, and macOS. + [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG] feature, i.e. Linux (X11), Windows, and macOS. [b]Note:[/b] [param current_directory] might be ignored. [b]Note:[/b] On Linux, [param show_hidden] is ignored. [b]Note:[/b] On macOS, native file dialogs have no title. @@ -147,7 +147,7 @@ Callbacks have the following arguments: [code]status: bool, selected_paths: PackedStringArray, selected_filter_index: int, selected_option: Dictionary[/code]. [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG] feature, i.e. Linux, Windows, and macOS. [b]Note:[/b] [param current_directory] might be ignored. - [b]Note:[/b] On Linux, [param show_hidden] is ignored. + [b]Note:[/b] On Linux (X11), [param show_hidden] is ignored. [b]Note:[/b] On macOS, native file dialogs have no title. [b]Note:[/b] On macOS, sandboxed apps will save security-scoped bookmarks to retain access to the opened folders across multiple sessions. Use [method OS.get_granted_permissions] to get a list of saved bookmarks. @@ -188,8 +188,8 @@ - Returns the name of the [DisplayServer] currently in use. Most operating systems only have a single [DisplayServer], but Linux has access to more than one [DisplayServer] (although only X11 is currently implemented in Godot). - The names of built-in display servers are [code]Windows[/code], [code]macOS[/code], [code]X11[/code] (Linux), [code]Android[/code], [code]iOS[/code], [code]web[/code] (HTML5) and [code]headless[/code] (when started with the [code]--headless[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url]). + Returns the name of the [DisplayServer] currently in use. Most operating systems only have a single [DisplayServer], but Linux has access to more than one [DisplayServer] (currently X11 and Wayland). + The names of built-in display servers are [code]Windows[/code], [code]macOS[/code], [code]X11[/code] (Linux), [code]Wayland[/code] (Linux), [code]Android[/code], [code]iOS[/code], [code]web[/code] (HTML5), and [code]headless[/code] (when started with the [code]--headless[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url]). @@ -877,14 +877,14 @@ Returns [code]true[/code] if OS is using dark mode. - [b]Note:[/b] This method is implemented on Android, iOS, macOS, Windows, and Linux (X11). + [b]Note:[/b] This method is implemented on Android, iOS, macOS, Windows, and Linux (X11/Wayland). Returns [code]true[/code] if OS supports dark mode. - [b]Note:[/b] This method is implemented on Android, iOS, macOS, Windows, and Linux (X11). + [b]Note:[/b] This method is implemented on Android, iOS, macOS, Windows, and Linux (X11/Wayland). @@ -897,7 +897,7 @@ Returns active keyboard layout index. - [b]Note:[/b] This method is implemented on Linux (X11), macOS and Windows. + [b]Note:[/b] This method is implemented on Linux (X11/Wayland), macOS, and Windows. @@ -905,7 +905,7 @@ Converts a physical (US QWERTY) [param keycode] to one in the active keyboard layout. - [b]Note:[/b] This method is implemented on Linux (X11), macOS and Windows. + [b]Note:[/b] This method is implemented on Linux (X11/Wayland), macOS and Windows. @@ -913,14 +913,14 @@ Converts a physical (US QWERTY) [param keycode] to localized label printed on the key in the active keyboard layout. - [b]Note:[/b] This method is implemented on Linux (X11), macOS and Windows. + [b]Note:[/b] This method is implemented on Linux (X11/Wayland), macOS and Windows. Returns the number of keyboard layouts. - [b]Note:[/b] This method is implemented on Linux (X11), macOS and Windows. + [b]Note:[/b] This method is implemented on Linux (X11/Wayland), macOS and Windows. @@ -928,7 +928,7 @@ Returns the ISO-639/BCP-47 language code of the keyboard layout at position [param index]. - [b]Note:[/b] This method is implemented on Linux (X11), macOS and Windows. + [b]Note:[/b] This method is implemented on Linux (X11/Wayland), macOS and Windows. @@ -936,7 +936,7 @@ Returns the localized name of the keyboard layout at position [param index]. - [b]Note:[/b] This method is implemented on Linux (X11), macOS and Windows. + [b]Note:[/b] This method is implemented on Linux (X11/Wayland), macOS and Windows. @@ -944,7 +944,7 @@ Sets the active keyboard layout. - [b]Note:[/b] This method is implemented on Linux (X11), macOS and Windows. + [b]Note:[/b] This method is implemented on Linux (X11/Wayland), macOS and Windows. @@ -993,7 +993,7 @@ xxhdpi - 480 dpi xxxhdpi - 640 dpi [/codeblock] - [b]Note:[/b] This method is implemented on Android, Linux (X11), macOS and Windows. Returns [code]72[/code] on unsupported platforms. + [b]Note:[/b] This method is implemented on Android, Linux (X11/Wayland), macOS and Windows. Returns [code]72[/code] on unsupported platforms. @@ -1044,6 +1044,7 @@ +-------------+ +-------+ [/codeblock] See also [method screen_get_size]. + [b]Note:[/b] On Linux (Wayland) this method always returns [code](0, 0)[/code]. @@ -1162,7 +1163,7 @@ - [code]id[/code] is voice identifier. - [code]language[/code] is language code in [code]lang_Variant[/code] format. The [code]lang[/code] part is a 2 or 3-letter code based on the ISO-639 standard, in lowercase. The [code skip-lint]Variant[/code] part is an engine-dependent string describing country, region or/and dialect. Note that Godot depends on system libraries for text-to-speech functionality. These libraries are installed by default on Windows and macOS, but not on all Linux distributions. If they are not present, this method will return an empty list. This applies to both Godot users on Linux, as well as end-users on Linux running Godot games that use text-to-speech. - [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), macOS, and Windows. + [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11/Wayland), macOS, and Windows. [b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be [code]true[/code] to use text-to-speech. @@ -1171,7 +1172,7 @@ Returns an [PackedStringArray] of voice identifiers for the [param language]. - [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), macOS, and Windows. + [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11/Wayland), macOS, and Windows. [b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be [code]true[/code] to use text-to-speech. @@ -1179,7 +1180,7 @@ Returns [code]true[/code] if the synthesizer is in a paused state. - [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), macOS, and Windows. + [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11/Wayland), macOS, and Windows. [b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be [code]true[/code] to use text-to-speech. @@ -1187,7 +1188,7 @@ Returns [code]true[/code] if the synthesizer is generating speech, or have utterance waiting in the queue. - [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), macOS, and Windows. + [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11/Wayland), macOS, and Windows. [b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be [code]true[/code] to use text-to-speech. @@ -1195,7 +1196,7 @@ Puts the synthesizer into a paused state. - [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), macOS, and Windows. + [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11/Wayland), macOS, and Windows. [b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be [code]true[/code] to use text-to-speech. @@ -1203,7 +1204,7 @@ Resumes the synthesizer if it was paused. - [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), macOS, and Windows. + [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11/Wayland), macOS, and Windows. [b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be [code]true[/code] to use text-to-speech. @@ -1216,7 +1217,7 @@ - [constant TTS_UTTERANCE_STARTED], [constant TTS_UTTERANCE_ENDED], and [constant TTS_UTTERANCE_CANCELED] callable's method should take one [int] parameter, the utterance ID. - [constant TTS_UTTERANCE_BOUNDARY] callable's method should take two [int] parameters, the index of the character and the utterance ID. [b]Note:[/b] The granularity of the boundary callbacks is engine dependent. - [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), macOS, and Windows. + [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11/Wayland), macOS, and Windows. [b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be [code]true[/code] to use text-to-speech. @@ -1236,9 +1237,9 @@ - [param pitch] ranges from [code]0.0[/code] (lowest) to [code]2.0[/code] (highest), [code]1.0[/code] is default pitch for the current voice. - [param rate] ranges from [code]0.1[/code] (lowest) to [code]10.0[/code] (highest), [code]1.0[/code] is a normal speaking rate. Other values act as a percentage relative. - [param utterance_id] is passed as a parameter to the callback functions. - [b]Note:[/b] On Windows and Linux (X11), utterance [param text] can use SSML markup. SSML support is engine and voice dependent. If the engine does not support SSML, you should strip out all XML markup before calling [method tts_speak]. + [b]Note:[/b] On Windows and Linux (X11/Wayland), utterance [param text] can use SSML markup. SSML support is engine and voice dependent. If the engine does not support SSML, you should strip out all XML markup before calling [method tts_speak]. [b]Note:[/b] The granularity of pitch, rate, and volume is engine and voice dependent. Values may be truncated. - [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), macOS, and Windows. + [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11/Wayland), macOS, and Windows. [b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be [code]true[/code] to use text-to-speech. @@ -1246,7 +1247,7 @@ Stops synthesis in progress and removes all utterances from the queue. - [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), macOS, and Windows. + [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11/Linux), macOS, and Windows. [b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be [code]true[/code] to use text-to-speech. @@ -1286,7 +1287,7 @@ Sets the mouse cursor position to the given [param position] relative to an origin at the upper left corner of the currently focused game Window Manager window. - [b]Note:[/b] [method warp_mouse] is only supported on Windows, macOS and Linux. It has no effect on Android, iOS and Web. + [b]Note:[/b] [method warp_mouse] is only supported on Windows, macOS, and Linux (X11/Wayland). It has no effect on Android, iOS, and Web. @@ -1351,7 +1352,7 @@ Returns internal structure pointers for use in plugins. - [b]Note:[/b] This method is implemented on Android, Linux (X11), macOS and Windows. + [b]Note:[/b] This method is implemented on Android, Linux (X11/Wayland), macOS, and Windows. @@ -1469,7 +1470,7 @@ Sets the [param callback] that should be called when files are dropped from the operating system's file manager to the window specified by [param window_id]. [b]Warning:[/b] Advanced users only! Adding such a callback to a [Window] node will override its default implementation, which can introduce bugs. - [b]Note:[/b] This method is implemented on Windows, macOS, Linux (X11) and Web. + [b]Note:[/b] This method is implemented on Windows, macOS, Linux (X11/Wayland), and Web. @@ -1612,6 +1613,7 @@ [/codeblock] See also [method window_get_position] and [method window_set_size]. [b]Note:[/b] It's recommended to change this value using [member Window.position] instead. + [b]Note:[/b] On Linux (Wayland): this method is a no-op. @@ -1693,22 +1695,22 @@ Display server supports touchscreen input. [b]Windows, Linux (X11), Android, iOS, Web[/b] - Display server supports mouse input. [b]Windows, macOS, Linux (X11), Android, Web[/b] + Display server supports mouse input. [b]Windows, macOS, Linux (X11/Wayland), Android, Web[/b] - Display server supports warping mouse coordinates to keep the mouse cursor constrained within an area, but looping when one of the edges is reached. [b]Windows, macOS, Linux (X11)[/b] + Display server supports warping mouse coordinates to keep the mouse cursor constrained within an area, but looping when one of the edges is reached. [b]Windows, macOS, Linux (X11/Wayland)[/b] - Display server supports setting and getting clipboard data. See also [constant FEATURE_CLIPBOARD_PRIMARY]. [b]Windows, macOS, Linux (X11), Android, iOS, Web[/b] + Display server supports setting and getting clipboard data. See also [constant FEATURE_CLIPBOARD_PRIMARY]. [b]Windows, macOS, Linux (X11/Wayland), Android, iOS, Web[/b] Display server supports popping up a virtual keyboard when requested to input text without a physical keyboard. [b]Android, iOS, Web[/b] - Display server supports setting the mouse cursor shape to be different from the default. [b]Windows, macOS, Linux (X11), Android, Web[/b] + Display server supports setting the mouse cursor shape to be different from the default. [b]Windows, macOS, Linux (X11/Wayland), Android, Web[/b] - Display server supports setting the mouse cursor shape to a custom image. [b]Windows, macOS, Linux (X11), Web[/b] + Display server supports setting the mouse cursor shape to a custom image. [b]Windows, macOS, Linux (X11/Wayland), Web[/b] Display server supports spawning dialogs using the operating system's native look-and-feel. [b]macOS[/b] @@ -1717,10 +1719,10 @@ Display server supports [url=https://en.wikipedia.org/wiki/Input_method]Input Method Editor[/url], which is commonly used for inputting Chinese/Japanese/Korean text. This is handled by the operating system, rather than by Godot. [b]Windows, macOS, Linux (X11)[/b] - Display server supports windows can use per-pixel transparency to make windows behind them partially or fully visible. [b]Windows, macOS, Linux (X11)[/b] + Display server supports windows can use per-pixel transparency to make windows behind them partially or fully visible. [b]Windows, macOS, Linux (X11/Wayland)[/b] - Display server supports querying the operating system's display scale factor. This allows for [i]reliable[/i] automatic hiDPI display detection, as opposed to guessing based on the screen resolution and reported display DPI (which can be unreliable due to broken monitor EDID). [b]Windows, macOS[/b] + Display server supports querying the operating system's display scale factor. This allows for [i]reliable[/i] automatic hiDPI display detection, as opposed to guessing based on the screen resolution and reported display DPI (which can be unreliable due to broken monitor EDID). [b]Windows, Linux (Wayland), macOS[/b] Display server supports changing the window icon (usually displayed in the top-left corner). [b]Windows, macOS, Linux (X11)[/b] @@ -1732,13 +1734,13 @@ Display server supports changing the screen orientation. [b]Android, iOS[/b] - Display server supports V-Sync status can be changed from the default (which is forced to be enabled platforms not supporting this feature). [b]Windows, macOS, Linux (X11)[/b] + Display server supports V-Sync status can be changed from the default (which is forced to be enabled platforms not supporting this feature). [b]Windows, macOS, Linux (X11/Wayland)[/b] - Display server supports Primary clipboard can be used. This is a different clipboard from [constant FEATURE_CLIPBOARD]. [b]Linux (X11)[/b] + Display server supports Primary clipboard can be used. This is a different clipboard from [constant FEATURE_CLIPBOARD]. [b]Linux (X11/Wayland)[/b] - Display server supports text-to-speech. See [code]tts_*[/code] methods. [b]Windows, macOS, Linux (X11), Android, iOS, Web[/b] + Display server supports text-to-speech. See [code]tts_*[/code] methods. [b]Windows, macOS, Linux (X11/Wayland), Android, iOS, Web[/b] Display server supports expanding window content to the title. See [constant WINDOW_FLAG_EXTEND_TO_TITLE]. [b]macOS[/b] @@ -1764,15 +1766,19 @@ Represents the screen containing the mouse pointer. + [b]Note:[/b] On Linux (Wayland), this constant always represents the screen at index [code]0[/code]. Represents the screen containing the window with the keyboard focus. + [b]Note:[/b] On Linux (Wayland), this constant always represents the screen at index [code]0[/code]. Represents the primary screen. + [b]Note:[/b] On Linux (Wayland), this constant always represents the screen at index [code]0[/code]. Represents the screen where the main window is located. This is usually the default value in functions that allow specifying one of several screens. + [b]Note:[/b] On Linux (Wayland), this constant always represents the screen at index [code]0[/code]. The ID of the main window spawned by the engine, which can be passed to methods expecting a [code]window_id[/code]. @@ -1931,7 +1937,7 @@ The window background can be transparent. [b]Note:[/b] This flag has no effect if [member ProjectSettings.display/window/per_pixel_transparency/allowed] is set to [code]false[/code]. - [b]Note:[/b] Transparency support is implemented on Linux (X11), macOS and Windows, but availability might vary depending on GPU driver, display manager, and compositor capabilities. + [b]Note:[/b] Transparency support is implemented on Linux (X11/Wayland), macOS, and Windows, but availability might vary depending on GPU driver, display manager, and compositor capabilities. The window can't be focused. No-focus window will ignore all input, except mouse clicks. @@ -2013,7 +2019,7 @@ OpenGL context (only with the GL Compatibility renderer): - Windows: [code]HGLRC[/code] for the window (native GL), or [code]EGLContext[/code] for the window (ANGLE). - - Linux: [code]GLXContext*[/code] for the window. + - Linux (X11): [code]GLXContext*[/code] for the window. - macOS: [code]NSOpenGLContext*[/code] for the window (native GL), or [code]EGLContext[/code] for the window (ANGLE). - Android: [code]EGLContext[/code] for the window. diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index 2f24acd684f..86ddcb6b108 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -762,6 +762,9 @@ The size of the font in the [b]Output[/b] panel at the bottom of the editor. This setting does not impact the font size of the script editor (see [member interface/editor/code_font_size]). + + If [code]true[/code], on Linux/BSD, the editor will check for Wayland first instead of X11 (if available). + The Android window to display the project on when starting the project from the editor. [b]Note:[/b] Only available in the Android editor. diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 0876261a315..aea5ef42af2 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -742,6 +742,24 @@ Line width of the curve path geometry, visible when "Visible Paths" is enabled in the Debug menu. + + Sets the driver to be used by the display server. This property can not be edited directly, instead, set the driver using the platform-specific overrides. + + + Android override for [member display/display_server/driver]. + + + iOS override for [member display/display_server/driver]. + + + LinuxBSD override for [member display/display_server/driver]. + + + MacOS override for [member display/display_server/driver]. + + + Windows override for [member display/display_server/driver]. + Custom image for the mouse cursor (limited to 256×256). diff --git a/drivers/vulkan/SCsub b/drivers/vulkan/SCsub index a076c0ac548..80d5f35305a 100644 --- a/drivers/vulkan/SCsub +++ b/drivers/vulkan/SCsub @@ -17,8 +17,11 @@ if env["platform"] == "android": env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_ANDROID_KHR"]) elif env["platform"] == "ios": env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_IOS_MVK"]) -elif env["platform"] == "linuxbsd" and env["x11"]: - env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_XLIB_KHR"]) +elif env["platform"] == "linuxbsd": + if env["x11"]: + env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_XLIB_KHR"]) + if env["wayland"]: + env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_WAYLAND_KHR"]) elif env["platform"] == "macos": env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_MACOS_MVK"]) elif env["platform"] == "windows": diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 3b1a69459d4..5a197134778 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -764,6 +764,10 @@ void EditorSettings::_load_defaults(Ref p_extra_config) { _initial_set("run/output/always_open_output_on_play", true); _initial_set("run/output/always_close_output_on_stop", false); + // Platform + _initial_set("run/platforms/linuxbsd/prefer_wayland", false); + set_restart_if_changed("run/platforms/linuxbsd/prefer_wayland", true); + /* Network */ // Debug @@ -1419,6 +1423,12 @@ String EditorSettings::get_editor_layouts_config() const { } float EditorSettings::get_auto_display_scale() const { +#ifdef LINUXBSD_ENABLED + if (DisplayServer::get_singleton()->get_name() == "Wayland") { + return DisplayServer::get_singleton()->screen_get_max_scale(); + } +#endif + #if defined(MACOS_ENABLED) || defined(ANDROID_ENABLED) return DisplayServer::get_singleton()->screen_get_max_scale(); #else diff --git a/main/main.cpp b/main/main.cpp index 49cb1ca24dd..06258745200 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -157,12 +157,12 @@ static bool _start_success = false; // Drivers +String display_driver = ""; String tablet_driver = ""; String text_driver = ""; String rendering_driver = ""; String rendering_method = ""; static int text_driver_idx = -1; -static int display_driver_idx = -1; static int audio_driver_idx = -1; // Engine config/tools @@ -824,7 +824,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph I = I->next(); } - String display_driver = ""; String audio_driver = ""; String project_path = "."; bool upwards = false; @@ -2122,23 +2121,13 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph // Display driver, e.g. X11, Wayland. // Make sure that headless is the last one, which it is assumed to be by design. DEV_ASSERT(NULL_DISPLAY_DRIVER == DisplayServer::get_create_function_name(DisplayServer::get_create_function_count() - 1)); - for (int i = 0; i < DisplayServer::get_create_function_count(); i++) { - String name = DisplayServer::get_create_function_name(i); - if (display_driver == name) { - display_driver_idx = i; - break; - } - } - if (display_driver_idx < 0) { - // If the requested driver wasn't found, pick the first entry. - // If all else failed it would be the headless server. - display_driver_idx = 0; - } - - // Store this in a globally accessible place, so we can retrieve the rendering drivers - // list from the display driver for the editor UI. - OS::get_singleton()->set_display_driver_id(display_driver_idx); + GLOBAL_DEF_RST_NOVAL("display/display_server/driver", "default"); + GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "display/display_server/driver.windows", PROPERTY_HINT_ENUM_SUGGESTION, "default,windows,headless"), "default"); + GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "display/display_server/driver.linuxbsd", PROPERTY_HINT_ENUM_SUGGESTION, "default,x11,wayland,headless"), "default"); + GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "display/display_server/driver.android", PROPERTY_HINT_ENUM_SUGGESTION, "default,android,headless"), "default"); + GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "display/display_server/driver.ios", PROPERTY_HINT_ENUM_SUGGESTION, "default,iOS,headless"), "default"); + GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "display/display_server/driver.macos", PROPERTY_HINT_ENUM_SUGGESTION, "default,macos,headless"), "default"); GLOBAL_DEF_RST_NOVAL("audio/driver/driver", AudioDriverManager::get_driver(0)->get_name()); if (audio_driver.is_empty()) { // Specified in project.godot. @@ -2382,7 +2371,26 @@ Error Main::setup2() { rp_new.ext_func = _parse_resource_dummy; rp_new.sub_func = _parse_resource_dummy; - while (true) { + bool screen_found = false; + String screen_property; + + bool prefer_wayland_found = false; + + if (editor) { + screen_property = "interface/editor/editor_screen"; + } else if (project_manager) { + screen_property = "interface/editor/project_manager_screen"; + } else { + // Skip. + screen_found = true; + } + + if (!display_driver.is_empty()) { + // Skip. + prefer_wayland_found = true; + } + + while (!screen_found || !prefer_wayland_found) { assign = Variant(); next_tag.fields.clear(); next_tag.name = String(); @@ -2391,17 +2399,21 @@ Error Main::setup2() { if (err == ERR_FILE_EOF) { break; } + if (err == OK && !assign.is_empty()) { - if (project_manager) { - if (assign == "interface/editor/project_manager_screen") { - init_screen = value; - break; - } - } else if (editor) { - if (assign == "interface/editor/editor_screen") { - init_screen = value; - break; + if (!screen_found && assign == screen_property) { + init_screen = value; + screen_found = true; + } + + if (!prefer_wayland_found && assign == "run/platforms/linuxbsd/prefer_wayland") { + if (value) { + display_driver = "wayland"; + } else { + display_driver = "default"; } + + prefer_wayland_found = true; } } } @@ -2459,7 +2471,33 @@ Error Main::setup2() { { OS::get_singleton()->benchmark_begin_measure("Servers", "Display"); - String display_driver = DisplayServer::get_create_function_name(display_driver_idx); + if (display_driver.is_empty()) { + display_driver = GLOBAL_GET("display/display_server/driver"); + } + + int display_driver_idx = -1; + + if (display_driver.is_empty() || display_driver == "default") { + display_driver_idx = 0; + } else { + for (int i = 0; i < DisplayServer::get_create_function_count(); i++) { + String name = DisplayServer::get_create_function_name(i); + if (display_driver == name) { + display_driver_idx = i; + break; + } + } + + if (display_driver_idx < 0) { + // If the requested driver wasn't found, pick the first entry. + // If all else failed it would be the headless server. + display_driver_idx = 0; + } + } + + // Store this in a globally accessible place, so we can retrieve the rendering drivers + // list from the display driver for the editor UI. + OS::get_singleton()->set_display_driver_id(display_driver_idx); Vector2i *window_position = nullptr; Vector2i position = init_custom_pos; diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub index 285c58a96e8..77922045ebb 100644 --- a/modules/openxr/SCsub +++ b/modules/openxr/SCsub @@ -24,6 +24,9 @@ elif env["platform"] == "linuxbsd": if env["x11"]: env_openxr.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_XLIB"]) + if env["wayland"]: + env_openxr.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_WAYLAND"]) + # FIXME: Review what needs to be set for Android and macOS. env_openxr.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"]) elif env["platform"] == "windows": diff --git a/modules/openxr/extensions/platform/openxr_opengl_extension.cpp b/modules/openxr/extensions/platform/openxr_opengl_extension.cpp index a9d970bbb9d..d92084a220d 100644 --- a/modules/openxr/extensions/platform/openxr_opengl_extension.cpp +++ b/modules/openxr/extensions/platform/openxr_opengl_extension.cpp @@ -131,9 +131,9 @@ bool OpenXROpenGLExtension::check_graphics_api_support(XrVersion p_desired_versi #ifdef WIN32 XrGraphicsBindingOpenGLWin32KHR OpenXROpenGLExtension::graphics_binding_gl; -#elif ANDROID_ENABLED +#elif defined(ANDROID_ENABLED) XrGraphicsBindingOpenGLESAndroidKHR OpenXROpenGLExtension::graphics_binding_gl; -#else +#elif defined(X11_ENABLED) XrGraphicsBindingOpenGLXlibKHR OpenXROpenGLExtension::graphics_binding_gl; #endif @@ -147,20 +147,24 @@ void *OpenXROpenGLExtension::set_session_create_and_get_next_pointer(void *p_nex DisplayServer *display_server = DisplayServer::get_singleton(); +#ifdef WAYLAND_ENABLED + ERR_FAIL_COND_V_MSG(display_server->get_name() == "Wayland", p_next_pointer, "OpenXR is not yet supported on OpenGL Wayland."); +#endif + #ifdef WIN32 graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR, graphics_binding_gl.next = p_next_pointer; graphics_binding_gl.hDC = (HDC)display_server->window_get_native_handle(DisplayServer::WINDOW_VIEW); graphics_binding_gl.hGLRC = (HGLRC)display_server->window_get_native_handle(DisplayServer::OPENGL_CONTEXT); -#elif ANDROID_ENABLED +#elif defined(ANDROID_ENABLED) graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR; graphics_binding_gl.next = p_next_pointer; graphics_binding_gl.display = (void *)display_server->window_get_native_handle(DisplayServer::DISPLAY_HANDLE); graphics_binding_gl.config = (EGLConfig)0; // https://github.com/KhronosGroup/OpenXR-SDK-Source/blob/master/src/tests/hello_xr/graphicsplugin_opengles.cpp#L122 graphics_binding_gl.context = (void *)display_server->window_get_native_handle(DisplayServer::OPENGL_CONTEXT); -#else +#elif defined(X11_ENABLED) graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR; graphics_binding_gl.next = p_next_pointer; diff --git a/platform/linuxbsd/SCsub b/platform/linuxbsd/SCsub index 4dd74ff9d09..a3ce773ac2f 100644 --- a/platform/linuxbsd/SCsub +++ b/platform/linuxbsd/SCsub @@ -19,6 +19,9 @@ if env["use_sowrap"]: if env["x11"]: common_linuxbsd += SConscript("x11/SCsub") +if env["wayland"]: + common_linuxbsd += SConscript("wayland/SCsub") + if env["speechd"]: common_linuxbsd.append("tts_linux.cpp") if env["use_sowrap"]: diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index eaaaad82b9a..e6a47f556d0 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -47,6 +47,8 @@ def get_opts(): BoolVariable("fontconfig", "Use fontconfig for system fonts support", True), BoolVariable("udev", "Use udev for gamepad connection callbacks", True), BoolVariable("x11", "Enable X11 display", True), + BoolVariable("wayland", "Enable Wayland display", True), + BoolVariable("libdecor", "Enable libdecor support", True), BoolVariable("touch", "Enable touch events", True), BoolVariable("execinfo", "Use libexecinfo on systems where glibc is not available", False), ] @@ -204,6 +206,11 @@ def configure(env: "Environment"): if env["use_sowrap"]: env.Append(CPPDEFINES=["SOWRAP_ENABLED"]) + if env["wayland"]: + if os.system("wayland-scanner -v") != 0: + print("wayland-scanner not found. Aborting.") + sys.exit(255) + if env["touch"]: env.Append(CPPDEFINES=["TOUCH_ENABLED"]) @@ -364,9 +371,13 @@ def configure(env: "Environment"): env.ParseConfig("pkg-config xkbcommon --cflags --libs") env.Append(CPPDEFINES=["XKB_ENABLED"]) else: - print( - "Warning: libxkbcommon development libraries not found. Disabling dead key composition and key label support." - ) + if env["wayland"]: + print("Error: libxkbcommon development libraries required by Wayland not found. Aborting.") + sys.exit(255) + else: + print( + "Warning: libxkbcommon development libraries not found. Disabling dead key composition and key label support." + ) else: env.Append(CPPDEFINES=["XKB_ENABLED"]) @@ -433,6 +444,33 @@ def configure(env: "Environment"): env.ParseConfig("pkg-config xi --cflags --libs") env.Append(CPPDEFINES=["X11_ENABLED"]) + if env["wayland"]: + if not env["use_sowrap"]: + if os.system("pkg-config --exists libdecor-0"): + print("Warning: libdecor development libraries not found. Disabling client-side decorations.") + env["libdecor"] = False + else: + env.ParseConfig("pkg-config libdecor-0 --cflags --libs") + if os.system("pkg-config --exists wayland-client"): + print("Error: Wayland client library not found. Aborting.") + sys.exit(255) + env.ParseConfig("pkg-config wayland-client --cflags --libs") + if os.system("pkg-config --exists wayland-cursor"): + print("Error: Wayland cursor library not found. Aborting.") + sys.exit(255) + env.ParseConfig("pkg-config wayland-cursor --cflags --libs") + if os.system("pkg-config --exists wayland-egl"): + print("Error: Wayland EGL library not found. Aborting.") + sys.exit(255) + env.ParseConfig("pkg-config wayland-egl --cflags --libs") + + if env["libdecor"]: + env.Append(CPPDEFINES=["LIBDECOR_ENABLED"]) + + env.Prepend(CPPPATH=["#platform/linuxbsd", "#thirdparty/linuxbsd_headers/wayland/"]) + env.Append(CPPDEFINES=["WAYLAND_ENABLED"]) + env.Append(LIBS=["rt"]) # Needed by glibc, used by _allocate_shm_file + if env["vulkan"]: env.Append(CPPDEFINES=["VULKAN_ENABLED", "RD_ENABLED"]) if not env["use_volk"]: diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp index f72c079d1d6..a5127147581 100644 --- a/platform/linuxbsd/export/export.cpp +++ b/platform/linuxbsd/export/export.cpp @@ -41,7 +41,7 @@ void register_linuxbsd_exporter_types() { void register_linuxbsd_exporter() { Ref platform; platform.instantiate(); - platform->set_name("Linux/X11"); + platform->set_name("Linux"); platform->set_os_name("Linux"); platform->set_chmod_flags(0755); diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index aed8574902b..f9e1aca7428 100644 --- a/platform/linuxbsd/os_linuxbsd.cpp +++ b/platform/linuxbsd/os_linuxbsd.cpp @@ -39,6 +39,10 @@ #include "x11/display_server_x11.h" #endif +#ifdef WAYLAND_ENABLED +#include "wayland/display_server_wayland.h" +#endif + #include "modules/modules_enabled.gen.h" // For regex. #ifdef MODULE_REGEX_ENABLED #include "modules/regex/regex.h" @@ -123,6 +127,14 @@ void OS_LinuxBSD::alert(const String &p_alert, const String &p_title) { } } +int OS_LinuxBSD::get_low_processor_usage_mode_sleep_usec() const { + if (DisplayServer::get_singleton() == nullptr || DisplayServer::get_singleton()->get_name() != "Wayland" || is_in_low_processor_usage_mode()) { + return OS::get_low_processor_usage_mode_sleep_usec(); + } + + return 500; // Roughly 2000 FPS, improves frame time when emulating VSync. +} + void OS_LinuxBSD::initialize() { crash_handler.initialize(); @@ -1166,6 +1178,10 @@ OS_LinuxBSD::OS_LinuxBSD() { DisplayServerX11::register_x11_driver(); #endif +#ifdef WAYLAND_ENABLED + DisplayServerWayland::register_wayland_driver(); +#endif + #ifdef FONTCONFIG_ENABLED #ifdef SOWRAP_ENABLED #ifdef DEBUG_ENABLED diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h index 6917ea5ae79..6ea2fc8e94b 100644 --- a/platform/linuxbsd/os_linuxbsd.h +++ b/platform/linuxbsd/os_linuxbsd.h @@ -127,6 +127,8 @@ public: virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override; + virtual int get_low_processor_usage_mode_sleep_usec() const override; + virtual bool _check_internal_feature_support(const String &p_feature) override; void run(); diff --git a/platform/linuxbsd/wayland/SCsub b/platform/linuxbsd/wayland/SCsub new file mode 100644 index 00000000000..dbb3c026906 --- /dev/null +++ b/platform/linuxbsd/wayland/SCsub @@ -0,0 +1,197 @@ +#!/usr/bin/env python + +Import("env") + +# TODO: Add warning to headers and code about their autogenerated status. +if env["use_sowrap"]: + # We have to implement separate builders for so wrappers as the + # autogenerated Wayland protocol wrapper must include them instead of the + # native libraries. + + WAYLAND_BUILDERS_SOWRAP = { + "WAYLAND_API_HEADER": Builder( + action=Action( + "wayland-scanner -c client-header < ${SOURCE} | sed 's:wayland-client-core\.h:../dynwrappers/wayland-client-core-so_wrap\.h:' > ${TARGET}", + 'Generating Wayland client header: "${TARGET}"', + ), + single_source=True, + ), + "WAYLAND_API_CODE": Builder( + action=Action( + "wayland-scanner -c private-code < ${SOURCE} | sed 's:wayland-util\.h:../dynwrappers/wayland-client-core-so_wrap\.h:' > ${TARGET}", + 'Generating Wayland protocol marshalling code: "${TARGET}"', + ), + single_source=True, + ), + } + env.Append(BUILDERS=WAYLAND_BUILDERS_SOWRAP) +else: + WAYLAND_BUILDERS = { + "WAYLAND_API_HEADER": Builder( + action=Action( + "wayland-scanner -c client-header < ${SOURCE} > ${TARGET}", + 'Generating Wayland client header: "${TARGET}"', + ), + single_source=True, + ), + "WAYLAND_API_CODE": Builder( + action=Action( + "wayland-scanner -c private-code < ${SOURCE} > ${TARGET}", + 'Generating Wayland protocol marshalling code: "${TARGET}"', + ), + single_source=True, + ), + } + env.Append(BUILDERS=WAYLAND_BUILDERS) + +env.WAYLAND_API_HEADER(target="protocol/wayland.gen.h", source="#thirdparty/wayland/protocol/wayland.xml") +env.WAYLAND_API_CODE(target="protocol/wayland.gen.c", source="#thirdparty/wayland/protocol/wayland.xml") + +env.WAYLAND_API_HEADER( + target="protocol/viewporter.gen.h", source="#thirdparty/wayland-protocols/stable/viewporter/viewporter.xml" +) +env.WAYLAND_API_CODE( + target="protocol/viewporter.gen.c", source="#thirdparty/wayland-protocols/stable/viewporter/viewporter.xml" +) + +env.WAYLAND_API_HEADER( + target="protocol/fractional_scale.gen.h", + source="#thirdparty/wayland-protocols/staging/fractional-scale/fractional-scale-v1.xml", +) +env.WAYLAND_API_CODE( + target="protocol/fractional_scale.gen.c", + source="#thirdparty/wayland-protocols/staging/fractional-scale/fractional-scale-v1.xml", +) + +env.WAYLAND_API_HEADER( + target="protocol/xdg_shell.gen.h", source="#thirdparty/wayland-protocols/stable/xdg-shell/xdg-shell.xml" +) + +env.WAYLAND_API_CODE( + target="protocol/xdg_shell.gen.c", source="#thirdparty/wayland-protocols/stable/xdg-shell/xdg-shell.xml" +) + +env.WAYLAND_API_HEADER( + target="protocol/xdg_decoration.gen.h", + source="#thirdparty/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml", +) + +env.WAYLAND_API_CODE( + target="protocol/xdg_decoration.gen.c", + source="#thirdparty/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml", +) + +env.WAYLAND_API_HEADER( + target="protocol/xdg_activation.gen.h", + source="#thirdparty/wayland-protocols/staging/xdg-activation/xdg-activation-v1.xml", +) + +env.WAYLAND_API_CODE( + target="protocol/xdg_activation.gen.c", + source="#thirdparty/wayland-protocols/staging/xdg-activation/xdg-activation-v1.xml", +) + +env.WAYLAND_API_HEADER( + target="protocol/relative_pointer.gen.h", + source="#thirdparty/wayland-protocols/unstable/relative-pointer/relative-pointer-unstable-v1.xml", +) + +env.WAYLAND_API_CODE( + target="protocol/relative_pointer.gen.c", + source="#thirdparty/wayland-protocols/unstable/relative-pointer/relative-pointer-unstable-v1.xml", +) + +env.WAYLAND_API_HEADER( + target="protocol/pointer_constraints.gen.h", + source="#thirdparty/wayland-protocols/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml", +) + +env.WAYLAND_API_CODE( + target="protocol/pointer_constraints.gen.c", + source="#thirdparty/wayland-protocols/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml", +) + +env.WAYLAND_API_HEADER( + target="protocol/pointer_gestures.gen.h", + source="#thirdparty/wayland-protocols/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml", +) + +env.WAYLAND_API_CODE( + target="protocol/pointer_gestures.gen.c", + source="#thirdparty/wayland-protocols/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml", +) + +env.WAYLAND_API_HEADER( + target="protocol/primary_selection.gen.h", + source="#thirdparty/wayland-protocols/unstable/primary-selection/primary-selection-unstable-v1.xml", +) + +env.WAYLAND_API_CODE( + target="protocol/primary_selection.gen.c", + source="#thirdparty/wayland-protocols/unstable/primary-selection/primary-selection-unstable-v1.xml", +) + +env.WAYLAND_API_HEADER( + target="protocol/idle_inhibit.gen.h", + source="#thirdparty/wayland-protocols/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml", +) + +env.WAYLAND_API_CODE( + target="protocol/idle_inhibit.gen.c", + source="#thirdparty/wayland-protocols/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml", +) + +env.WAYLAND_API_HEADER( + target="protocol/tablet.gen.h", + source="#thirdparty/wayland-protocols/unstable/tablet/tablet-unstable-v2.xml", +) + +env.WAYLAND_API_CODE( + target="protocol/tablet.gen.c", + source="#thirdparty/wayland-protocols/unstable/tablet/tablet-unstable-v2.xml", +) + +source_files = [ + "protocol/wayland.gen.c", + "protocol/viewporter.gen.c", + "protocol/fractional_scale.gen.c", + "protocol/xdg_shell.gen.c", + "protocol/xdg_decoration.gen.c", + "protocol/xdg_activation.gen.c", + "protocol/relative_pointer.gen.c", + "protocol/pointer_constraints.gen.c", + "protocol/pointer_gestures.gen.c", + "protocol/primary_selection.gen.c", + "protocol/idle_inhibit.gen.c", + "protocol/tablet.gen.c", + "display_server_wayland.cpp", + "wayland_thread.cpp", + "key_mapping_xkb.cpp", + "detect_prime_egl.cpp", +] + +if env["use_sowrap"]: + source_files.append( + [ + "dynwrappers/wayland-cursor-so_wrap.c", + "dynwrappers/wayland-client-core-so_wrap.c", + "dynwrappers/wayland-egl-core-so_wrap.c", + ] + ) + + if env["libdecor"]: + source_files.append("dynwrappers/libdecor-so_wrap.c") + + +if env["vulkan"]: + source_files.append("vulkan_context_wayland.cpp") + +if env["opengl3"]: + source_files.append("egl_manager_wayland.cpp") + +objects = [] + +for source_file in source_files: + objects.append(env.Object(source_file)) + +Return("objects") diff --git a/platform/linuxbsd/wayland/detect_prime_egl.cpp b/platform/linuxbsd/wayland/detect_prime_egl.cpp new file mode 100644 index 00000000000..4bee32ae3ad --- /dev/null +++ b/platform/linuxbsd/wayland/detect_prime_egl.cpp @@ -0,0 +1,231 @@ +/**************************************************************************/ +/* detect_prime_egl.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 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. */ +/**************************************************************************/ + +#ifdef GLES3_ENABLED +#ifdef EGL_ENABLED + +#include "detect_prime_egl.h" + +#include "core/string/print_string.h" +#include "core/string/ustring.h" + +#include + +#ifdef GLAD_ENABLED +#include "thirdparty/glad/glad/egl.h" +#include "thirdparty/glad/glad/gl.h" +#else +#include +#include +#include +#endif // GLAD_ENABLED + +#include + +#include +#include +#include + +// To prevent shadowing warnings. +#undef glGetString + +// Runs inside a child. Exiting will not quit the engine. +void DetectPrimeEGL::create_context() { +#if defined(GLAD_ENABLED) + if (!gladLoaderLoadEGL(nullptr)) { + print_verbose("Unable to load EGL, GPU detection skipped."); + quick_exit(1); + } +#endif + + EGLDisplay egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + EGLConfig egl_config; + EGLContext egl_context = EGL_NO_CONTEXT; + + eglInitialize(egl_display, NULL, NULL); + +#if defined(GLAD_ENABLED) + if (!gladLoaderLoadEGL(egl_display)) { + print_verbose("Unable to load EGL, GPU detection skipped."); + quick_exit(1); + } +#endif + + eglBindAPI(EGL_OPENGL_API); + + EGLint attribs[] = { + EGL_RED_SIZE, + 1, + EGL_BLUE_SIZE, + 1, + EGL_GREEN_SIZE, + 1, + EGL_DEPTH_SIZE, + 24, + EGL_NONE, + }; + + EGLint config_count = 0; + eglChooseConfig(egl_display, attribs, &egl_config, 1, &config_count); + + EGLint context_attribs[] = { + EGL_CONTEXT_MAJOR_VERSION, 3, + EGL_CONTEXT_MINOR_VERSION, 3, + EGL_NONE + }; + + egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, context_attribs); + if (egl_context == EGL_NO_CONTEXT) { + print_verbose("Unable to create an EGL context, GPU detection skipped."); + quick_exit(1); + } + + eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl_context); +} + +int DetectPrimeEGL::detect_prime() { + pid_t p; + int priorities[4] = {}; + String vendors[4]; + String renderers[4]; + + for (int i = 0; i < 4; ++i) { + vendors[i] = "Unknown"; + renderers[i] = "Unknown"; + } + + for (int i = 0; i < 4; ++i) { + int fdset[2]; + + if (pipe(fdset) == -1) { + print_verbose("Failed to pipe(), using default GPU"); + return 0; + } + + // Fork so the driver initialization can crash without taking down the engine. + p = fork(); + + if (p > 0) { + // Main thread + + int stat_loc = 0; + char string[201]; + string[200] = '\0'; + + close(fdset[1]); + + waitpid(p, &stat_loc, 0); + + if (!stat_loc) { + // No need to do anything complicated here. Anything less than + // PIPE_BUF will be delivered in one read() call. + // Leave it 'Unknown' otherwise. + if (read(fdset[0], string, sizeof(string) - 1) > 0) { + vendors[i] = string; + renderers[i] = string + strlen(string) + 1; + } + } + + close(fdset[0]); + } else { + // In child, exit() here will not quit the engine. + + // Prevent false leak reports as we will not be properly + // cleaning up these processes, and fork() makes a copy + // of all globals. + CoreGlobals::leak_reporting_enabled = false; + + char string[201]; + + close(fdset[0]); + + setenv("DRI_PRIME", itos(i).utf8().ptr(), 1); + + create_context(); + + PFNGLGETSTRINGPROC glGetString = (PFNGLGETSTRINGPROC)eglGetProcAddress("glGetString"); + const char *vendor = (const char *)glGetString(GL_VENDOR); + const char *renderer = (const char *)glGetString(GL_RENDERER); + + unsigned int vendor_len = strlen(vendor) + 1; + unsigned int renderer_len = strlen(renderer) + 1; + + if (vendor_len + renderer_len >= sizeof(string)) { + renderer_len = 200 - vendor_len; + } + + memcpy(&string, vendor, vendor_len); + memcpy(&string[vendor_len], renderer, renderer_len); + + if (write(fdset[1], string, vendor_len + renderer_len) == -1) { + print_verbose("Couldn't write vendor/renderer string."); + } + close(fdset[1]); + + // The function quick_exit() is used because exit() will call destructors on static objects copied by fork(). + // These objects will be freed anyway when the process finishes execution. + quick_exit(0); + } + } + + int preferred = 0; + int priority = 0; + + if (vendors[0] == vendors[1]) { + print_verbose("Only one GPU found, using default."); + return 0; + } + + for (int i = 3; i >= 0; --i) { + const Vendor *v = vendor_map; + while (v->glxvendor) { + if (v->glxvendor == vendors[i]) { + priorities[i] = v->priority; + + if (v->priority >= priority) { + priority = v->priority; + preferred = i; + } + } + ++v; + } + } + + print_verbose("Found renderers:"); + for (int i = 0; i < 4; ++i) { + print_verbose("Renderer " + itos(i) + ": " + renderers[i] + " with priority: " + itos(priorities[i])); + } + + print_verbose("Using renderer: " + renderers[preferred]); + return preferred; +} + +#endif // EGL_ENABLED +#endif // GLES3_ENABLED diff --git a/platform/linuxbsd/wayland/detect_prime_egl.h b/platform/linuxbsd/wayland/detect_prime_egl.h new file mode 100644 index 00000000000..26351b0dce2 --- /dev/null +++ b/platform/linuxbsd/wayland/detect_prime_egl.h @@ -0,0 +1,65 @@ +/**************************************************************************/ +/* detect_prime_egl.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 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. */ +/**************************************************************************/ + +#ifndef DETECT_PRIME_EGL_H +#define DETECT_PRIME_EGL_H + +#ifdef GLES3_ENABLED +#ifdef EGL_ENABLED + +class DetectPrimeEGL { +private: + struct Vendor { + const char *glxvendor = nullptr; + int priority = 0; + }; + + static constexpr Vendor vendor_map[] = { + { "Advanced Micro Devices, Inc.", 30 }, + { "AMD", 30 }, + { "NVIDIA Corporation", 30 }, + { "X.Org", 30 }, + { "Intel Open Source Technology Center", 20 }, + { "Intel", 20 }, + { "nouveau", 10 }, + { "Mesa Project", 0 }, + { nullptr, 0 } + }; + + static void create_context(); + +public: + static int detect_prime(); +}; + +#endif // GLES3_ENABLED +#endif // EGL_ENABLED + +#endif // DETECT_PRIME_EGL_H diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp new file mode 100644 index 00000000000..e22eddd08e5 --- /dev/null +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -0,0 +1,1353 @@ +/**************************************************************************/ +/* display_server_wayland.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 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. */ +/**************************************************************************/ + +#include "display_server_wayland.h" + +#ifdef WAYLAND_ENABLED + +#define WAYLAND_DISPLAY_SERVER_DEBUG_LOGS_ENABLED +#ifdef WAYLAND_DISPLAY_SERVER_DEBUG_LOGS_ENABLED +#define DEBUG_LOG_WAYLAND(...) print_verbose(__VA_ARGS__) +#else +#define DEBUG_LOG_WAYLAND(...) +#endif + +#ifdef VULKAN_ENABLED +#include "servers/rendering/renderer_rd/renderer_compositor_rd.h" +#endif + +#ifdef GLES3_ENABLED +#include "detect_prime_egl.h" +#include "drivers/gles3/rasterizer_gles3.h" +#endif + +String DisplayServerWayland::_get_app_id_from_context(Context p_context) { + String app_id; + + switch (p_context) { + case CONTEXT_EDITOR: { + app_id = "org.godotengine.Editor"; + } break; + + case CONTEXT_PROJECTMAN: { + app_id = "org.godotengine.ProjectManager"; + } break; + + case CONTEXT_ENGINE: + default: { + String config_name = GLOBAL_GET("application/config/name"); + if (config_name.length() != 0) { + app_id = config_name; + } else { + app_id = "org.godotengine.Godot"; + } + } + } + + return app_id; +} + +void DisplayServerWayland::_send_window_event(WindowEvent p_event) { + WindowData &wd = main_window; + + if (wd.window_event_callback.is_valid()) { + Variant event = int(p_event); + wd.window_event_callback.call(event); + } +} + +void DisplayServerWayland::dispatch_input_events(const Ref &p_event) { + ((DisplayServerWayland *)(get_singleton()))->_dispatch_input_event(p_event); +} + +void DisplayServerWayland::_dispatch_input_event(const Ref &p_event) { + Callable callable = main_window.input_event_callback; + if (callable.is_valid()) { + callable.call(p_event); + } +} + +void DisplayServerWayland::_resize_window(const Size2i &p_size) { + WindowData &wd = main_window; + + wd.rect.size = p_size; + +#ifdef RD_ENABLED + if (wd.visible && context_rd) { + context_rd->window_resize(MAIN_WINDOW_ID, wd.rect.size.width, wd.rect.size.height); + } +#endif + +#ifdef GLES3_ENABLED + if (wd.visible && egl_manager) { + wl_egl_window_resize(wd.wl_egl_window, wd.rect.size.width, wd.rect.size.height, 0, 0); + } +#endif + + if (wd.rect_changed_callback.is_valid()) { + wd.rect_changed_callback.call(wd.rect); + } +} + +void DisplayServerWayland::_show_window() { + MutexLock mutex_lock(wayland_thread.mutex); + + WindowData &wd = main_window; + + if (!wd.visible) { + DEBUG_LOG_WAYLAND("Showing window."); + + // Showing this window will reset its mode with whatever the compositor + // reports. We'll save the mode beforehand so that we can reapply it later. + // TODO: Fix/Port/Move/Whatever to `WaylandThread` APIs. + WindowMode setup_mode = wd.mode; + + wayland_thread.window_create(MAIN_WINDOW_ID, wd.rect.size.width, wd.rect.size.height); + wayland_thread.window_set_min_size(MAIN_WINDOW_ID, wd.min_size); + wayland_thread.window_set_max_size(MAIN_WINDOW_ID, wd.max_size); + wayland_thread.window_set_app_id(MAIN_WINDOW_ID, _get_app_id_from_context(context)); + wayland_thread.window_set_borderless(MAIN_WINDOW_ID, window_get_flag(WINDOW_FLAG_BORDERLESS)); + + // NOTE: The XDG shell protocol is built in a way that causes the window to + // be immediately shown as soon as a valid buffer is assigned to it. Hence, + // the only acceptable way of implementing window showing is to move the + // graphics context window creation logic here. +#ifdef RD_ENABLED + if (context_rd) { + union { +#ifdef VULKAN_ENABLED + VulkanContextWayland::WindowPlatformData vulkan; +#endif + } wpd; +#ifdef VULKAN_ENABLED + if (rendering_driver == "vulkan") { + wpd.vulkan.surface = wayland_thread.window_get_wl_surface(wd.id); + wpd.vulkan.display = wayland_thread.get_wl_display(); + } +#endif + Error err = context_rd->window_create(wd.id, wd.vsync_mode, wd.rect.size.width, wd.rect.size.height, &wpd); + ERR_FAIL_COND_MSG(err != OK, vformat("Can't create a %s window", context_rd->get_api_name())); + + emulate_vsync = (context_rd->get_vsync_mode(wd.id) == DisplayServer::VSYNC_ENABLED); + + if (emulate_vsync) { + print_verbose("VSYNC: manually throttling frames using MAILBOX."); + context_rd->set_vsync_mode(wd.id, DisplayServer::VSYNC_MAILBOX); + } + } +#endif + +#ifdef GLES3_ENABLED + if (egl_manager) { + struct wl_surface *wl_surface = wayland_thread.window_get_wl_surface(wd.id); + wd.wl_egl_window = wl_egl_window_create(wl_surface, wd.rect.size.width, wd.rect.size.height); + + Error err = egl_manager->window_create(MAIN_WINDOW_ID, wayland_thread.get_wl_display(), wd.wl_egl_window, wd.rect.size.width, wd.rect.size.height); + ERR_FAIL_COND_MSG(err == ERR_CANT_CREATE, "Can't show a GLES3 window."); + + window_set_vsync_mode(wd.vsync_mode, MAIN_WINDOW_ID); + } +#endif + // NOTE: The public window-handling methods might depend on this flag being + // set. Ensure to not make any of these calls before this assignment. + wd.visible = true; + + // Actually try to apply the window's mode now that it's visible. + window_set_mode(setup_mode); + + wayland_thread.window_set_title(MAIN_WINDOW_ID, wd.title); + } +} +// Interface methods. + +bool DisplayServerWayland::has_feature(Feature p_feature) const { + switch (p_feature) { + case FEATURE_MOUSE: + case FEATURE_CLIPBOARD: + case FEATURE_CURSOR_SHAPE: + case FEATURE_WINDOW_TRANSPARENCY: + case FEATURE_SWAP_BUFFERS: + case FEATURE_KEEP_SCREEN_ON: + case FEATURE_CLIPBOARD_PRIMARY: + case FEATURE_HIDPI: { + return true; + } break; + + default: { + return false; + } + } +} + +String DisplayServerWayland::get_name() const { + return "Wayland"; +} + +#ifdef SPEECHD_ENABLED + +bool DisplayServerWayland::tts_is_speaking() const { + ERR_FAIL_NULL_V(tts, false); + return tts->is_speaking(); +} + +bool DisplayServerWayland::tts_is_paused() const { + ERR_FAIL_NULL_V(tts, false); + return tts->is_paused(); +} + +TypedArray DisplayServerWayland::tts_get_voices() const { + ERR_FAIL_NULL_V(tts, TypedArray()); + return tts->get_voices(); +} + +void DisplayServerWayland::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) { + ERR_FAIL_NULL(tts); + tts->speak(p_text, p_voice, p_volume, p_pitch, p_rate, p_utterance_id, p_interrupt); +} + +void DisplayServerWayland::tts_pause() { + ERR_FAIL_NULL(tts); + tts->pause(); +} + +void DisplayServerWayland::tts_resume() { + ERR_FAIL_NULL(tts); + tts->resume(); +} + +void DisplayServerWayland::tts_stop() { + ERR_FAIL_NULL(tts); + tts->stop(); +} + +#endif + +#ifdef DBUS_ENABLED + +bool DisplayServerWayland::is_dark_mode_supported() const { + return portal_desktop->is_supported(); +} + +bool DisplayServerWayland::is_dark_mode() const { + switch (portal_desktop->get_appearance_color_scheme()) { + case 1: + // Prefers dark theme. + return true; + case 2: + // Prefers light theme. + return false; + default: + // Preference unknown. + return false; + } +} + +#endif + +void DisplayServerWayland::mouse_set_mode(MouseMode p_mode) { + if (p_mode == mouse_mode) { + return; + } + + MutexLock mutex_lock(wayland_thread.mutex); + + bool show_cursor = (p_mode == MOUSE_MODE_VISIBLE || p_mode == MOUSE_MODE_CONFINED); + + if (show_cursor) { + if (custom_cursors.has(cursor_shape)) { + wayland_thread.cursor_set_custom_shape(cursor_shape); + } else { + wayland_thread.cursor_set_shape(cursor_shape); + } + } else { + wayland_thread.cursor_hide(); + } + + WaylandThread::PointerConstraint constraint = WaylandThread::PointerConstraint::NONE; + + switch (p_mode) { + case DisplayServer::MOUSE_MODE_CAPTURED: { + constraint = WaylandThread::PointerConstraint::LOCKED; + } break; + + case DisplayServer::MOUSE_MODE_CONFINED: + case DisplayServer::MOUSE_MODE_CONFINED_HIDDEN: { + constraint = WaylandThread::PointerConstraint::CONFINED; + } break; + + default: { + } + } + + wayland_thread.pointer_set_constraint(constraint); + + mouse_mode = p_mode; +} + +DisplayServerWayland::MouseMode DisplayServerWayland::mouse_get_mode() const { + return mouse_mode; +} + +// NOTE: This is hacked together (and not guaranteed to work in the first place) +// as for some reason the there's no proper way to ask the compositor to warp +// the pointer, although, at the time of writing, there's a proposal for a +// proper protocol for this. See: +// https://gitlab.freedesktop.org/wayland/wayland-protocols/-/issues/158 +void DisplayServerWayland::warp_mouse(const Point2i &p_to) { + MutexLock mutex_lock(wayland_thread.mutex); + + WaylandThread::PointerConstraint old_constraint = wayland_thread.pointer_get_constraint(); + + wayland_thread.pointer_set_constraint(WaylandThread::PointerConstraint::LOCKED); + wayland_thread.pointer_set_hint(p_to); + + wayland_thread.pointer_set_constraint(old_constraint); +} + +Point2i DisplayServerWayland::mouse_get_position() const { + MutexLock mutex_lock(wayland_thread.mutex); + + // We can't properly implement this method by design. + // This is the best we can do unfortunately. + return Input::get_singleton()->get_mouse_position(); + + return Point2i(); +} + +BitField DisplayServerWayland::mouse_get_button_state() const { + MutexLock mutex_lock(wayland_thread.mutex); + + // Are we sure this is the only way? This seems sus. + // TODO: Handle tablets properly. + //mouse_button_mask.set_flag(MouseButtonMask((int64_t)wls.current_seat->tablet_tool_data.pressed_button_mask)); + + return wayland_thread.pointer_get_button_mask(); +} + +// NOTE: According to the Wayland specification, this method will only do +// anything if the user has interacted with the application by sending a +// "recent enough" input event. +// TODO: Add this limitation to the documentation. +void DisplayServerWayland::clipboard_set(const String &p_text) { + MutexLock mutex_lock(wayland_thread.mutex); + + wayland_thread.selection_set_text(p_text); +} + +String DisplayServerWayland::clipboard_get() const { + MutexLock mutex_lock(wayland_thread.mutex); + + Vector data; + + const String text_mimes[] = { + "text/plain;charset=utf-8", + "text/plain", + }; + + for (String mime : text_mimes) { + if (wayland_thread.selection_has_mime(mime)) { + print_verbose(vformat("Selecting media type \"%s\" from offered types.", mime)); + data = wayland_thread.selection_get_mime(mime); + break; + } + } + + return String::utf8((const char *)data.ptr(), data.size()); +} + +Ref DisplayServerWayland::clipboard_get_image() const { + MutexLock mutex_lock(wayland_thread.mutex); + + Ref image; + image.instantiate(); + + Error err = OK; + + // TODO: Fallback to next media type on missing module or parse error. + if (wayland_thread.selection_has_mime("image/png")) { + err = image->load_png_from_buffer(wayland_thread.selection_get_mime("image/png")); + } else if (wayland_thread.selection_has_mime("image/jpeg")) { + err = image->load_jpg_from_buffer(wayland_thread.selection_get_mime("image/jpeg")); + } else if (wayland_thread.selection_has_mime("image/webp")) { + err = image->load_webp_from_buffer(wayland_thread.selection_get_mime("image/webp")); + } else if (wayland_thread.selection_has_mime("image/svg+xml")) { + err = image->load_svg_from_buffer(wayland_thread.selection_get_mime("image/svg+xml")); + } else if (wayland_thread.selection_has_mime("image/bmp")) { + err = image->load_bmp_from_buffer(wayland_thread.selection_get_mime("image/bmp")); + } else if (wayland_thread.selection_has_mime("image/x-tga")) { + err = image->load_tga_from_buffer(wayland_thread.selection_get_mime("image/x-tga")); + } else if (wayland_thread.selection_has_mime("image/x-targa")) { + err = image->load_tga_from_buffer(wayland_thread.selection_get_mime("image/x-targa")); + } else if (wayland_thread.selection_has_mime("image/ktx")) { + err = image->load_ktx_from_buffer(wayland_thread.selection_get_mime("image/ktx")); + } + + ERR_FAIL_COND_V(err != OK, Ref()); + + return image; +} + +void DisplayServerWayland::clipboard_set_primary(const String &p_text) { + MutexLock mutex_lock(wayland_thread.mutex); + + wayland_thread.primary_set_text(p_text); +} + +String DisplayServerWayland::clipboard_get_primary() const { + MutexLock mutex_lock(wayland_thread.mutex); + + Vector data; + + const String text_mimes[] = { + "text/plain;charset=utf-8", + "text/plain", + }; + + for (String mime : text_mimes) { + if (wayland_thread.primary_has_mime(mime)) { + print_verbose(vformat("Selecting media type \"%s\" from offered types.", mime)); + wayland_thread.primary_get_mime(mime); + break; + } + } + + return String::utf8((const char *)data.ptr(), data.size()); +} + +int DisplayServerWayland::get_screen_count() const { + MutexLock mutex_lock(wayland_thread.mutex); + return wayland_thread.get_screen_count(); +} + +int DisplayServerWayland::get_primary_screen() const { + // AFAIK Wayland doesn't allow knowing (nor we care) about which screen is + // primary. + return 0; +} + +Point2i DisplayServerWayland::screen_get_position(int p_screen) const { + MutexLock mutex_lock(wayland_thread.mutex); + + if (p_screen == SCREEN_OF_MAIN_WINDOW) { + p_screen = window_get_current_screen(); + } + + return wayland_thread.screen_get_data(p_screen).position; +} + +Size2i DisplayServerWayland::screen_get_size(int p_screen) const { + MutexLock mutex_lock(wayland_thread.mutex); + + if (p_screen == SCREEN_OF_MAIN_WINDOW) { + p_screen = window_get_current_screen(); + } + + return wayland_thread.screen_get_data(p_screen).size; +} + +Rect2i DisplayServerWayland::screen_get_usable_rect(int p_screen) const { + // Unsupported on wayland. + return Rect2i(Point2i(), screen_get_size(p_screen)); +} + +int DisplayServerWayland::screen_get_dpi(int p_screen) const { + MutexLock mutex_lock(wayland_thread.mutex); + + if (p_screen == SCREEN_OF_MAIN_WINDOW) { + p_screen = window_get_current_screen(); + } + + const WaylandThread::ScreenData &data = wayland_thread.screen_get_data(p_screen); + + int width_mm = data.physical_size.width; + int height_mm = data.physical_size.height; + + double xdpi = (width_mm ? data.size.width / (double)width_mm * 25.4 : 0); + double ydpi = (height_mm ? data.size.height / (double)height_mm * 25.4 : 0); + + if (xdpi || ydpi) { + return (xdpi + ydpi) / (xdpi && ydpi ? 2 : 1); + } + + // Could not get DPI. + return 96; +} + +float DisplayServerWayland::screen_get_scale(int p_screen) const { + MutexLock mutex_lock(wayland_thread.mutex); + + if (p_screen == SCREEN_OF_MAIN_WINDOW) { + p_screen = window_get_current_screen(); + } + + return wayland_thread.screen_get_data(p_screen).scale; +} + +float DisplayServerWayland::screen_get_refresh_rate(int p_screen) const { + MutexLock mutex_lock(wayland_thread.mutex); + + if (p_screen == SCREEN_OF_MAIN_WINDOW) { + p_screen = window_get_current_screen(); + } + + return wayland_thread.screen_get_data(p_screen).refresh_rate; +} + +void DisplayServerWayland::screen_set_keep_on(bool p_enable) { + MutexLock mutex_lock(wayland_thread.mutex); + + if (screen_is_kept_on() == p_enable) { + return; + } + +#ifdef DBUS_ENABLED + if (screensaver) { + if (p_enable) { + screensaver->inhibit(); + } else { + screensaver->uninhibit(); + } + + screensaver_inhibited = p_enable; + } +#endif +} + +bool DisplayServerWayland::screen_is_kept_on() const { +#ifdef DBUS_ENABLED + return wayland_thread.window_get_idle_inhibition(MAIN_WINDOW_ID) || screensaver_inhibited; +#endif + + return wayland_thread.window_get_idle_inhibition(MAIN_WINDOW_ID); +} + +Vector DisplayServerWayland::get_window_list() const { + MutexLock mutex_lock(wayland_thread.mutex); + + Vector ret; + ret.push_back(MAIN_WINDOW_ID); + + return ret; +} + +DisplayServer::WindowID DisplayServerWayland::get_window_at_screen_position(const Point2i &p_position) const { + // Standard Wayland APIs don't support this. + return MAIN_WINDOW_ID; +} + +void DisplayServerWayland::window_attach_instance_id(ObjectID p_instance, WindowID p_window_id) { + MutexLock mutex_lock(wayland_thread.mutex); + + main_window.instance_id = p_instance; +} + +ObjectID DisplayServerWayland::window_get_attached_instance_id(WindowID p_window_id) const { + MutexLock mutex_lock(wayland_thread.mutex); + + return main_window.instance_id; +} + +void DisplayServerWayland::window_set_title(const String &p_title, DisplayServer::WindowID p_window_id) { + MutexLock mutex_lock(wayland_thread.mutex); + + WindowData &wd = main_window; + + wd.title = p_title; + + wayland_thread.window_set_title(MAIN_WINDOW_ID, wd.title); +} + +void DisplayServerWayland::window_set_mouse_passthrough(const Vector &p_region, DisplayServer::WindowID p_window_id) { + // TODO + DEBUG_LOG_WAYLAND(vformat("wayland stub window_set_mouse_passthrough region %s", p_region)); +} + +void DisplayServerWayland::window_set_rect_changed_callback(const Callable &p_callable, DisplayServer::WindowID p_window_id) { + MutexLock mutex_lock(wayland_thread.mutex); + + main_window.rect_changed_callback = p_callable; +} + +void DisplayServerWayland::window_set_window_event_callback(const Callable &p_callable, DisplayServer::WindowID p_window_id) { + MutexLock mutex_lock(wayland_thread.mutex); + + main_window.window_event_callback = p_callable; +} + +void DisplayServerWayland::window_set_input_event_callback(const Callable &p_callable, DisplayServer::WindowID p_window_id) { + MutexLock mutex_lock(wayland_thread.mutex); + + main_window.input_event_callback = p_callable; +} + +void DisplayServerWayland::window_set_input_text_callback(const Callable &p_callable, WindowID p_window_id) { + MutexLock mutex_lock(wayland_thread.mutex); + + main_window.input_text_callback = p_callable; +} + +void DisplayServerWayland::window_set_drop_files_callback(const Callable &p_callable, DisplayServer::WindowID p_window_id) { + MutexLock mutex_lock(wayland_thread.mutex); + + main_window.drop_files_callback = p_callable; +} + +int DisplayServerWayland::window_get_current_screen(DisplayServer::WindowID p_window_id) const { + // Standard Wayland APIs don't support getting the screen of a window. + return 0; +} + +void DisplayServerWayland::window_set_current_screen(int p_screen, DisplayServer::WindowID p_window_id) { + // Standard Wayland APIs don't support setting the screen of a window. +} + +Point2i DisplayServerWayland::window_get_position(DisplayServer::WindowID p_window_id) const { + MutexLock mutex_lock(wayland_thread.mutex); + + // We can't know the position of toplevels with the standard protocol. + return Point2i(); +} + +Point2i DisplayServerWayland::window_get_position_with_decorations(DisplayServer::WindowID p_window_id) const { + MutexLock mutex_lock(wayland_thread.mutex); + + // We can't know the position of toplevels with the standard protocol, nor can + // we get information about the decorations, at least with SSDs. + return Point2i(); +} + +void DisplayServerWayland::window_set_position(const Point2i &p_position, DisplayServer::WindowID p_window_id) { + // Unsupported with toplevels. +} + +void DisplayServerWayland::window_set_max_size(const Size2i p_size, DisplayServer::WindowID p_window_id) { + MutexLock mutex_lock(wayland_thread.mutex); + + DEBUG_LOG_WAYLAND(vformat("window max size set to %s", p_size)); + + if (p_size.x < 0 || p_size.y < 0) { + ERR_FAIL_MSG("Maximum window size can't be negative!"); + } + + WindowData &wd = main_window; + + // FIXME: Is `p_size.x < wd.min_size.x || p_size.y < wd.min_size.y` == `p_size < wd.min_size`? + if ((p_size != Size2i()) && ((p_size.x < wd.min_size.x) || (p_size.y < wd.min_size.y))) { + ERR_PRINT("Maximum window size can't be smaller than minimum window size!"); + return; + } + + wd.max_size = p_size; + + wayland_thread.window_set_max_size(MAIN_WINDOW_ID, p_size); +} + +Size2i DisplayServerWayland::window_get_max_size(DisplayServer::WindowID p_window_id) const { + MutexLock mutex_lock(wayland_thread.mutex); + + return main_window.max_size; +} + +void DisplayServerWayland::gl_window_make_current(DisplayServer::WindowID p_window_id) { +#ifdef GLES3_ENABLED + if (egl_manager) { + egl_manager->window_make_current(MAIN_WINDOW_ID); + } +#endif +} + +void DisplayServerWayland::window_set_transient(WindowID p_window_id, WindowID p_parent) { + // Currently unsupported. +} + +void DisplayServerWayland::window_set_min_size(const Size2i p_size, DisplayServer::WindowID p_window_id) { + MutexLock mutex_lock(wayland_thread.mutex); + + DEBUG_LOG_WAYLAND(vformat("window minsize set to %s", p_size)); + + WindowData &wd = main_window; + + if (p_size.x < 0 || p_size.y < 0) { + ERR_FAIL_MSG("Minimum window size can't be negative!"); + } + + // FIXME: Is `p_size.x > wd.max_size.x || p_size.y > wd.max_size.y` == `p_size > wd.max_size`? + if ((p_size != Size2i()) && (wd.max_size != Size2i()) && ((p_size.x > wd.max_size.x) || (p_size.y > wd.max_size.y))) { + ERR_PRINT("Minimum window size can't be larger than maximum window size!"); + return; + } + + wd.min_size = p_size; + + wayland_thread.window_set_min_size(MAIN_WINDOW_ID, p_size); +} + +Size2i DisplayServerWayland::window_get_min_size(DisplayServer::WindowID p_window_id) const { + MutexLock mutex_lock(wayland_thread.mutex); + + return main_window.min_size; +} + +void DisplayServerWayland::window_set_size(const Size2i p_size, DisplayServer::WindowID p_window_id) { + // The XDG spec doesn't allow non-interactive resizes. +} + +Size2i DisplayServerWayland::window_get_size(DisplayServer::WindowID p_window_id) const { + MutexLock mutex_lock(wayland_thread.mutex); + + return main_window.rect.size; +} + +Size2i DisplayServerWayland::window_get_size_with_decorations(DisplayServer::WindowID p_window_id) const { + MutexLock mutex_lock(wayland_thread.mutex); + + // I don't think there's a way of actually knowing the size of the window + // decoration in Wayland, at least in the case of SSDs, nor that it would be + // that useful in this case. We'll just return the main window's size. + return main_window.rect.size; +} + +void DisplayServerWayland::window_set_mode(WindowMode p_mode, DisplayServer::WindowID p_window_id) { + MutexLock mutex_lock(wayland_thread.mutex); + + WindowData &wd = main_window; + + if (!wd.visible) { + return; + } + + wayland_thread.window_try_set_mode(p_window_id, p_mode); +} + +DisplayServer::WindowMode DisplayServerWayland::window_get_mode(DisplayServer::WindowID p_window_id) const { + MutexLock mutex_lock(wayland_thread.mutex); + + const WindowData &wd = main_window; + + if (!wd.visible) { + return WINDOW_MODE_WINDOWED; + } + + return wayland_thread.window_get_mode(p_window_id); +} + +bool DisplayServerWayland::window_is_maximize_allowed(DisplayServer::WindowID p_window_id) const { + MutexLock mutex_lock(wayland_thread.mutex); + + return wayland_thread.window_can_set_mode(p_window_id, WINDOW_MODE_MAXIMIZED); +} + +void DisplayServerWayland::window_set_flag(WindowFlags p_flag, bool p_enabled, DisplayServer::WindowID p_window_id) { + MutexLock mutex_lock(wayland_thread.mutex); + + WindowData &wd = main_window; + + DEBUG_LOG_WAYLAND(vformat("Window set flag %d", p_flag)); + + switch (p_flag) { + case WINDOW_FLAG_BORDERLESS: { + wayland_thread.window_set_borderless(MAIN_WINDOW_ID, p_enabled); + } break; + + default: { + } + } + + if (p_enabled) { + wd.flags |= 1 << p_flag; + } else { + wd.flags &= ~(1 << p_flag); + } +} + +bool DisplayServerWayland::window_get_flag(WindowFlags p_flag, DisplayServer::WindowID p_window_id) const { + MutexLock mutex_lock(wayland_thread.mutex); + + return main_window.flags & (1 << p_flag); +} + +void DisplayServerWayland::window_request_attention(DisplayServer::WindowID p_window_id) { + MutexLock mutex_lock(wayland_thread.mutex); + + DEBUG_LOG_WAYLAND("Requested attention."); + + wayland_thread.window_request_attention(MAIN_WINDOW_ID); +} + +void DisplayServerWayland::window_move_to_foreground(DisplayServer::WindowID p_window_id) { + // Standard Wayland APIs don't support this. +} + +bool DisplayServerWayland::window_is_focused(WindowID p_window_id) const { + return wayland_thread.pointer_get_pointed_window_id() == p_window_id; +} + +bool DisplayServerWayland::window_can_draw(DisplayServer::WindowID p_window_id) const { + return frame; +} + +bool DisplayServerWayland::can_any_window_draw() const { + return frame; +} + +void DisplayServerWayland::window_set_ime_active(const bool p_active, DisplayServer::WindowID p_window_id) { + // TODO + DEBUG_LOG_WAYLAND(vformat("wayland stub window_set_ime_active active %s", p_active ? "true" : "false")); +} + +void DisplayServerWayland::window_set_ime_position(const Point2i &p_pos, DisplayServer::WindowID p_window_id) { + // TODO + DEBUG_LOG_WAYLAND(vformat("wayland stub window_set_ime_position pos %s window %d", p_pos, p_window_id)); +} + +// NOTE: While Wayland is supposed to be tear-free, wayland-protocols version +// 1.30 added a protocol for allowing async flips which is supposed to be +// handled by drivers such as Vulkan. We can then just ask to disable v-sync and +// hope for the best. See: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/commit/6394f0b4f3be151076f10a845a2fb131eeb56706 +void DisplayServerWayland::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, DisplayServer::WindowID p_window_id) { + MutexLock mutex_lock(wayland_thread.mutex); + +#ifdef RD_ENABLED + if (context_rd) { + context_rd->set_vsync_mode(p_window_id, p_vsync_mode); + + emulate_vsync = (context_rd->get_vsync_mode(p_window_id) == DisplayServer::VSYNC_ENABLED); + + if (emulate_vsync) { + print_verbose("VSYNC: manually throttling frames using MAILBOX."); + context_rd->set_vsync_mode(p_window_id, DisplayServer::VSYNC_MAILBOX); + } + } +#endif // VULKAN_ENABLED + +#ifdef GLES3_ENABLED + if (egl_manager) { + egl_manager->set_use_vsync(p_vsync_mode != DisplayServer::VSYNC_DISABLED); + + emulate_vsync = egl_manager->is_using_vsync(); + + if (emulate_vsync) { + print_verbose("VSYNC: manually throttling frames with swap delay 0."); + egl_manager->set_use_vsync(false); + } + } +#endif // GLES3_ENABLED +} + +DisplayServer::VSyncMode DisplayServerWayland::window_get_vsync_mode(DisplayServer::WindowID p_window_id) const { + if (emulate_vsync) { + return DisplayServer::VSYNC_ENABLED; + } + +#ifdef VULKAN_ENABLED + if (context_rd) { + return context_rd->get_vsync_mode(p_window_id); + } +#endif // VULKAN_ENABLED + +#ifdef GLES3_ENABLED + if (egl_manager) { + return egl_manager->is_using_vsync() ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED; + } +#endif // GLES3_ENABLED + + return DisplayServer::VSYNC_ENABLED; +} + +void DisplayServerWayland::cursor_set_shape(CursorShape p_shape) { + ERR_FAIL_INDEX(p_shape, CURSOR_MAX); + + MutexLock mutex_lock(wayland_thread.mutex); + + if (p_shape == cursor_shape) { + return; + } + + cursor_shape = p_shape; + + if (mouse_mode != MOUSE_MODE_VISIBLE && mouse_mode != MOUSE_MODE_CONFINED) { + // Hidden. + return; + } + + if (custom_cursors.has(p_shape)) { + wayland_thread.cursor_set_custom_shape(p_shape); + } else { + wayland_thread.cursor_set_shape(p_shape); + } +} + +DisplayServerWayland::CursorShape DisplayServerWayland::cursor_get_shape() const { + MutexLock mutex_lock(wayland_thread.mutex); + + return cursor_shape; +} + +void DisplayServerWayland::cursor_set_custom_image(const Ref &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { + MutexLock mutex_lock(wayland_thread.mutex); + + bool visible = (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED); + + if (p_cursor.is_valid()) { + HashMap::Iterator cursor_c = custom_cursors.find(p_shape); + + if (cursor_c) { + if (cursor_c->value.rid == p_cursor->get_rid() && cursor_c->value.hotspot == p_hotspot) { + // We have a cached cursor. Nice. + if (visible) { + wayland_thread.cursor_set_custom_shape(p_shape); + } + + return; + } + + // We're changing this cursor; we'll have to rebuild it. + custom_cursors.erase(p_shape); + wayland_thread.cursor_shape_clear_custom_image(p_shape); + } + + Ref texture = p_cursor; + ERR_FAIL_COND(!texture.is_valid()); + Size2i texture_size; + + Ref atlas_texture = texture; + + if (atlas_texture.is_valid()) { + texture_size.width = atlas_texture->get_region().size.x; + texture_size.height = atlas_texture->get_region().size.y; + } else { + texture_size.width = texture->get_width(); + texture_size.height = texture->get_height(); + } + + ERR_FAIL_COND(p_hotspot.x < 0 || p_hotspot.y < 0); + + // NOTE: The Wayland protocol says nothing about cursor size limits, yet if + // the texture is larger than 256x256 it won't show at least on sway. + ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256); + ERR_FAIL_COND(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height); + ERR_FAIL_COND(texture_size.height == 0 || texture_size.width == 0); + + Ref image = texture->get_image(); + ERR_FAIL_COND(!image.is_valid()); + + if (image->is_compressed()) { + image = image->duplicate(true); + Error err = image->decompress(); + ERR_FAIL_COND_MSG(err != OK, "Couldn't decompress VRAM-compressed custom mouse cursor image. Switch to a lossless compression mode in the Import dock."); + } + + CustomCursor &cursor = custom_cursors[p_shape]; + + cursor.rid = p_cursor->get_rid(); + cursor.hotspot = p_hotspot; + + wayland_thread.cursor_shape_set_custom_image(p_shape, image, p_hotspot); + + if (visible) { + wayland_thread.cursor_set_custom_shape(p_shape); + } + } else { + // Clear cache and reset to default system cursor. + if (cursor_shape == p_shape && visible) { + wayland_thread.cursor_set_shape(p_shape); + } + + if (custom_cursors.has(p_shape)) { + custom_cursors.erase(p_shape); + } + + wayland_thread.cursor_shape_clear_custom_image(p_shape); + } +} + +int DisplayServerWayland::keyboard_get_layout_count() const { + MutexLock mutex_lock(wayland_thread.mutex); + + return wayland_thread.keyboard_get_layout_count(); +} + +int DisplayServerWayland::keyboard_get_current_layout() const { + MutexLock mutex_lock(wayland_thread.mutex); + + return wayland_thread.keyboard_get_current_layout_index(); +} + +void DisplayServerWayland::keyboard_set_current_layout(int p_index) { + MutexLock mutex_lock(wayland_thread.mutex); + + wayland_thread.keyboard_set_current_layout_index(p_index); +} + +String DisplayServerWayland::keyboard_get_layout_language(int p_index) const { + MutexLock mutex_lock(wayland_thread.mutex); + + // xkbcommon exposes only the layout's name, which looks like it overlaps with + // its language. + return wayland_thread.keyboard_get_layout_name(p_index); +} + +String DisplayServerWayland::keyboard_get_layout_name(int p_index) const { + MutexLock mutex_lock(wayland_thread.mutex); + + return wayland_thread.keyboard_get_layout_name(p_index); +} + +Key DisplayServerWayland::keyboard_get_keycode_from_physical(Key p_keycode) const { + MutexLock mutex_lock(wayland_thread.mutex); + + Key key = wayland_thread.keyboard_get_key_from_physical(p_keycode); + + // If not found, fallback to QWERTY. + // This should match the behavior of the event pump. + if (key == Key::NONE) { + return p_keycode; + } + + if (key >= Key::A + 32 && key <= Key::Z + 32) { + key -= 'a' - 'A'; + } + + // Make it consistent with the keys returned by `Input`. + if (key == Key::BACKTAB) { + key = Key::TAB; + } + + return key; +} + +void DisplayServerWayland::process_events() { + wayland_thread.mutex.lock(); + + while (wayland_thread.has_message()) { + Ref msg = wayland_thread.pop_message(); + + Ref winrect_msg = msg; + if (winrect_msg.is_valid()) { + _resize_window(winrect_msg->rect.size); + } + + Ref winev_msg = msg; + if (winev_msg.is_valid()) { + _send_window_event(winev_msg->event); + + if (winev_msg->event == WINDOW_EVENT_FOCUS_IN) { + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN); + } + } else if (winev_msg->event == WINDOW_EVENT_FOCUS_OUT) { + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT); + } + } + } + + Ref inputev_msg = msg; + if (inputev_msg.is_valid()) { + Input::get_singleton()->parse_input_event(inputev_msg->event); + } + + Ref dropfiles_msg = msg; + if (dropfiles_msg.is_valid()) { + WindowData wd = main_window; + + if (wd.drop_files_callback.is_valid()) { + wd.drop_files_callback.call(dropfiles_msg->files); + } + } + } + + wayland_thread.keyboard_echo_keys(); + + frame = wayland_thread.get_reset_frame(); + + wayland_thread.mutex.unlock(); + + Input::get_singleton()->flush_buffered_events(); +} + +void DisplayServerWayland::release_rendering_thread() { +#ifdef GLES3_ENABLED + if (egl_manager) { + egl_manager->release_current(); + } +#endif +} + +void DisplayServerWayland::make_rendering_thread() { +#ifdef GLES3_ENABLED + if (egl_manager) { + egl_manager->make_current(); + } +#endif +} + +void DisplayServerWayland::swap_buffers() { +#ifdef GLES3_ENABLED + if (egl_manager) { + egl_manager->swap_buffers(); + } +#endif +} + +void DisplayServerWayland::set_context(Context p_context) { + MutexLock mutex_lock(wayland_thread.mutex); + + DEBUG_LOG_WAYLAND(vformat("Setting context %d.", p_context)); + + context = p_context; + + String app_id = _get_app_id_from_context(p_context); + wayland_thread.window_set_app_id(MAIN_WINDOW_ID, app_id); +} + +Vector DisplayServerWayland::get_rendering_drivers_func() { + Vector drivers; + +#ifdef VULKAN_ENABLED + drivers.push_back("vulkan"); +#endif + +#ifdef GLES3_ENABLED + drivers.push_back("opengl3"); +#endif + + return drivers; +} + +DisplayServer *DisplayServerWayland::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, int p_screen, Error &r_error) { + DisplayServer *ds = memnew(DisplayServerWayland(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); + if (r_error != OK) { + ERR_PRINT("Can't create the Wayland display server."); + memdelete(ds); + + return nullptr; + } + return ds; +} + +DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { +#ifdef GLES3_ENABLED +#ifdef SOWRAP_ENABLED +#ifdef DEBUG_ENABLED + int dylibloader_verbose = 1; +#else + int dylibloader_verbose = 0; +#endif // DEBUG_ENABLED +#endif // SOWRAP_ENABLED +#endif // GLES3_ENABLED + + r_error = ERR_UNAVAILABLE; + + Error thread_err = wayland_thread.init(); + + if (thread_err != OK) { + r_error = thread_err; + ERR_FAIL_MSG("Could not initialize the Wayland thread."); + } + + // Input. + Input::get_singleton()->set_event_dispatch_function(dispatch_input_events); + +#ifdef SPEECHD_ENABLED + // Init TTS + tts = memnew(TTS_Linux); +#endif + + rendering_driver = p_rendering_driver; + +#ifdef RD_ENABLED +#ifdef VULKAN_ENABLED + if (p_rendering_driver == "vulkan") { + context_rd = memnew(VulkanContextWayland); + } +#endif + + if (context_rd) { + if (context_rd->initialize() != OK) { + memdelete(context_rd); + context_rd = nullptr; + r_error = ERR_CANT_CREATE; + ERR_FAIL_MSG(vformat("Could not initialize %s", context_rd->get_api_name())); + } + } +#endif + +#ifdef GLES3_ENABLED + if (p_rendering_driver == "opengl3") { + if (getenv("DRI_PRIME") == nullptr) { + int prime_idx = -1; + + if (getenv("PRIMUS_DISPLAY") || + getenv("PRIMUS_libGLd") || + getenv("PRIMUS_libGLa") || + getenv("PRIMUS_libGL") || + getenv("PRIMUS_LOAD_GLOBAL") || + getenv("BUMBLEBEE_SOCKET") || + getenv("__NV_PRIME_RENDER_OFFLOAD")) { + print_verbose("Optirun/primusrun detected. Skipping GPU detection"); + prime_idx = 0; + } + + // Some tools use fake libGL libraries and have them override the real one using + // LD_LIBRARY_PATH, so we skip them. *But* Steam also sets LD_LIBRARY_PATH for its + // runtime and includes system `/lib` and `/lib64`... so ignore Steam. + if (prime_idx == -1 && getenv("LD_LIBRARY_PATH") && !getenv("STEAM_RUNTIME_LIBRARY_PATH")) { + String ld_library_path(getenv("LD_LIBRARY_PATH")); + Vector libraries = ld_library_path.split(":"); + + for (int i = 0; i < libraries.size(); ++i) { + if (FileAccess::exists(libraries[i] + "/libGL.so.1") || + FileAccess::exists(libraries[i] + "/libGL.so")) { + print_verbose("Custom libGL override detected. Skipping GPU detection"); + prime_idx = 0; + } + } + } + + if (prime_idx == -1) { + print_verbose("Detecting GPUs, set DRI_PRIME in the environment to override GPU detection logic."); + prime_idx = DetectPrimeEGL::detect_prime(); + } + + if (prime_idx) { + print_line(vformat("Found discrete GPU, setting DRI_PRIME=%d to use it.", prime_idx)); + print_line("Note: Set DRI_PRIME=0 in the environment to disable Godot from using the discrete GPU."); + setenv("DRI_PRIME", itos(prime_idx).utf8().ptr(), 1); + } + } + + egl_manager = memnew(EGLManagerWayland); + +#ifdef SOWRAP_ENABLED + if (initialize_wayland_egl(dylibloader_verbose) != 0) { + WARN_PRINT("Can't load the Wayland EGL library."); + return; + } +#endif // SOWRAP_ENABLED + + if (egl_manager->initialize() != OK) { + memdelete(egl_manager); + egl_manager = nullptr; + r_error = ERR_CANT_CREATE; + ERR_FAIL_MSG("Could not initialize GLES3."); + } + + RasterizerGLES3::make_current(true); + } +#endif // GLES3_ENABLED + + cursor_set_shape(CURSOR_BUSY); + + WindowData &wd = main_window; + + wd.id = MAIN_WINDOW_ID; + wd.mode = p_mode; + wd.flags = p_flags; + wd.vsync_mode = p_vsync_mode; + wd.rect.size = p_resolution; + wd.title = "Godot"; + + _show_window(); + +#ifdef RD_ENABLED + if (context_rd) { + rendering_device = memnew(RenderingDevice); + rendering_device->initialize(context_rd); + + RendererCompositorRD::make_current(); + } +#endif + +#ifdef DBUS_ENABLED + portal_desktop = memnew(FreeDesktopPortalDesktop); + screensaver = memnew(FreeDesktopScreenSaver); +#endif + + screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on")); + + r_error = OK; +} + +DisplayServerWayland::~DisplayServerWayland() { + // TODO: Multiwindow support. + if (main_window.visible) { +#ifdef VULKAN_ENABLED + if (context_rd) { + context_rd->window_destroy(MAIN_WINDOW_ID); + } +#endif + +#ifdef GLES3_ENABLED + if (egl_manager) { + egl_manager->window_destroy(MAIN_WINDOW_ID); + } +#endif + } + +#ifdef GLES3_ENABLED + if (main_window.wl_egl_window) { + wl_egl_window_destroy(main_window.wl_egl_window); + } +#endif + + wayland_thread.destroy(); + + // Destroy all drivers. +#ifdef RD_ENABLED + if (rendering_device) { + rendering_device->finalize(); + memdelete(rendering_device); + } + + if (context_rd) { + memdelete(context_rd); + } +#endif + +#ifdef SPEECHD_ENABLED + if (tts) { + memdelete(tts); + } +#endif + +#ifdef DBUS_ENABLED + if (portal_desktop) { + memdelete(portal_desktop); + memdelete(screensaver); + } +#endif +} + +void DisplayServerWayland::register_wayland_driver() { + register_create_function("wayland", create_func, get_rendering_drivers_func); +} + +#endif //WAYLAND_ENABLED diff --git a/platform/linuxbsd/wayland/display_server_wayland.h b/platform/linuxbsd/wayland/display_server_wayland.h new file mode 100644 index 00000000000..f0aabb8c52d --- /dev/null +++ b/platform/linuxbsd/wayland/display_server_wayland.h @@ -0,0 +1,290 @@ +/**************************************************************************/ +/* display_server_wayland.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 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. */ +/**************************************************************************/ + +#ifndef DISPLAY_SERVER_WAYLAND_H +#define DISPLAY_SERVER_WAYLAND_H + +#ifdef WAYLAND_ENABLED + +#include "wayland/wayland_thread.h" + +#ifdef RD_ENABLED +#include "servers/rendering/rendering_device.h" + +#ifdef VULKAN_ENABLED +#include "wayland/vulkan_context_wayland.h" +#endif + +#endif //RD_ENABLED + +#ifdef GLES3_ENABLED +#include "wayland/egl_manager_wayland.h" +#endif + +#if defined(SPEECHD_ENABLED) +#include "tts_linux.h" +#endif + +#ifdef DBUS_ENABLED +#include "freedesktop_portal_desktop.h" +#include "freedesktop_screensaver.h" +#endif + +#include "core/config/project_settings.h" +#include "core/input/input.h" +#include "scene/resources/atlas_texture.h" +#include "scene/resources/texture.h" +#include "servers/display_server.h" + +#include +#include + +#undef CursorShape + +class DisplayServerWayland : public DisplayServer { + // No need to register with GDCLASS, it's platform-specific and nothing is added. + struct WindowData { + WindowID id; + + Rect2i rect; + Size2i max_size; + Size2i min_size; + + Rect2i safe_rect; + +#ifdef GLES3_ENABLED + struct wl_egl_window *wl_egl_window = nullptr; +#endif + + // Flags whether we have allocated a buffer through the video drivers. + bool visible = false; + + DisplayServer::VSyncMode vsync_mode = VSYNC_ENABLED; + + uint32_t flags = 0; + + DisplayServer::WindowMode mode = WINDOW_MODE_WINDOWED; + + Callable rect_changed_callback; + Callable window_event_callback; + Callable input_event_callback; + Callable drop_files_callback; + Callable input_text_callback; + + String title; + ObjectID instance_id; + }; + + struct CustomCursor { + RID rid; + Point2i hotspot; + }; + + CursorShape cursor_shape = CURSOR_ARROW; + DisplayServer::MouseMode mouse_mode = DisplayServer::MOUSE_MODE_VISIBLE; + + HashMap custom_cursors; + + WindowData main_window; + WaylandThread wayland_thread; + + Context context; + + bool frame = false; + bool emulate_vsync = false; + + String rendering_driver; + +#ifdef RD_ENABLED + ApiContextRD *context_rd = nullptr; + RenderingDevice *rendering_device = nullptr; +#endif + +#ifdef GLES3_ENABLED + EGLManagerWayland *egl_manager = nullptr; +#endif + +#ifdef SPEECHD_ENABLED + TTS_Linux *tts = nullptr; +#endif + +#if DBUS_ENABLED + FreeDesktopPortalDesktop *portal_desktop = nullptr; + + FreeDesktopScreenSaver *screensaver = nullptr; + bool screensaver_inhibited = false; +#endif + static String _get_app_id_from_context(Context p_context); + + void _send_window_event(WindowEvent p_event); + + static void dispatch_input_events(const Ref &p_event); + void _dispatch_input_event(const Ref &p_event); + + void _resize_window(const Size2i &p_size); + + virtual void _show_window(); + +public: + virtual bool has_feature(Feature p_feature) const override; + + virtual String get_name() const override; + +#ifdef SPEECHD_ENABLED + virtual bool tts_is_speaking() const override; + virtual bool tts_is_paused() const override; + virtual TypedArray tts_get_voices() const override; + + virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override; + virtual void tts_pause() override; + virtual void tts_resume() override; + virtual void tts_stop() override; +#endif + +#ifdef DBUS_ENABLED + virtual bool is_dark_mode_supported() const override; + virtual bool is_dark_mode() const override; +#endif + + virtual void mouse_set_mode(MouseMode p_mode) override; + virtual MouseMode mouse_get_mode() const override; + + virtual void warp_mouse(const Point2i &p_to) override; + virtual Point2i mouse_get_position() const override; + virtual BitField mouse_get_button_state() const override; + + virtual void clipboard_set(const String &p_text) override; + virtual String clipboard_get() const override; + virtual Ref clipboard_get_image() const override; + virtual void clipboard_set_primary(const String &p_text) override; + virtual String clipboard_get_primary() const override; + + virtual int get_screen_count() const override; + virtual int get_primary_screen() const override; + virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + + virtual void screen_set_keep_on(bool p_enable) override; + virtual bool screen_is_kept_on() const override; + + virtual Vector get_window_list() const override; + + virtual WindowID get_window_at_screen_position(const Point2i &p_position) const override; + + virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window_id = MAIN_WINDOW_ID) override; + virtual ObjectID window_get_attached_instance_id(WindowID p_window_id = MAIN_WINDOW_ID) const override; + + virtual void window_set_title(const String &p_title, WindowID p_window_id = MAIN_WINDOW_ID) override; + virtual void window_set_mouse_passthrough(const Vector &p_region, WindowID p_window_id = MAIN_WINDOW_ID) override; + + virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window_id = MAIN_WINDOW_ID) override; + virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window_id = MAIN_WINDOW_ID) override; + virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window_id = MAIN_WINDOW_ID) override; + virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window_id = MAIN_WINDOW_ID) override; + virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window_id = MAIN_WINDOW_ID) override; + + virtual int window_get_current_screen(WindowID p_window_id = MAIN_WINDOW_ID) const override; + virtual void window_set_current_screen(int p_screen, WindowID p_window_id = MAIN_WINDOW_ID) override; + + virtual Point2i window_get_position(WindowID p_window_id = MAIN_WINDOW_ID) const override; + virtual Point2i window_get_position_with_decorations(WindowID p_window_id = MAIN_WINDOW_ID) const override; + virtual void window_set_position(const Point2i &p_position, WindowID p_window_id = MAIN_WINDOW_ID) override; + + virtual void window_set_max_size(const Size2i p_size, WindowID p_window_id = MAIN_WINDOW_ID) override; + virtual Size2i window_get_max_size(WindowID p_window_id = MAIN_WINDOW_ID) const override; + virtual void gl_window_make_current(DisplayServer::WindowID p_window_id) override; + + virtual void window_set_transient(WindowID p_window_id, WindowID p_parent) override; + + virtual void window_set_min_size(const Size2i p_size, WindowID p_window_id = MAIN_WINDOW_ID) override; + virtual Size2i window_get_min_size(WindowID p_window_id = MAIN_WINDOW_ID) const override; + + virtual void window_set_size(const Size2i p_size, WindowID p_window_id = MAIN_WINDOW_ID) override; + virtual Size2i window_get_size(WindowID p_window_id = MAIN_WINDOW_ID) const override; + virtual Size2i window_get_size_with_decorations(WindowID p_window_id = MAIN_WINDOW_ID) const override; + + virtual void window_set_mode(WindowMode p_mode, WindowID p_window_id = MAIN_WINDOW_ID) override; + virtual WindowMode window_get_mode(WindowID p_window_id = MAIN_WINDOW_ID) const override; + + virtual bool window_is_maximize_allowed(WindowID p_window_id = MAIN_WINDOW_ID) const override; + + virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window_id = MAIN_WINDOW_ID) override; + virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window_id = MAIN_WINDOW_ID) const override; + + virtual void window_request_attention(WindowID p_window_id = MAIN_WINDOW_ID) override; + + virtual void window_move_to_foreground(WindowID p_window_id = MAIN_WINDOW_ID) override; + virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override; + + virtual bool window_can_draw(WindowID p_window_id = MAIN_WINDOW_ID) const override; + + virtual bool can_any_window_draw() const override; + + virtual void window_set_ime_active(const bool p_active, WindowID p_window_id = MAIN_WINDOW_ID) override; + virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window_id = MAIN_WINDOW_ID) override; + + virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window_id = MAIN_WINDOW_ID) override; + virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_window_id) const override; + + virtual void cursor_set_shape(CursorShape p_shape) override; + virtual CursorShape cursor_get_shape() const override; + virtual void cursor_set_custom_image(const Ref &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) override; + + virtual int keyboard_get_layout_count() const override; + virtual int keyboard_get_current_layout() const override; + virtual void keyboard_set_current_layout(int p_index) override; + virtual String keyboard_get_layout_language(int p_index) const override; + virtual String keyboard_get_layout_name(int p_index) const override; + virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const override; + + virtual void process_events() override; + + virtual void release_rendering_thread() override; + virtual void make_rendering_thread() override; + virtual void swap_buffers() override; + + virtual void set_context(Context p_context) override; + + static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, int p_screen, Error &r_error); + static Vector get_rendering_drivers_func(); + + static void register_wayland_driver(); + + DisplayServerWayland(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + ~DisplayServerWayland(); +}; + +#endif // WAYLAND_ENABLED + +#endif // DISPLAY_SERVER_WAYLAND_H diff --git a/platform/linuxbsd/wayland/dynwrappers/libdecor-so_wrap.c b/platform/linuxbsd/wayland/dynwrappers/libdecor-so_wrap.c new file mode 100644 index 00000000000..eaf43215cec --- /dev/null +++ b/platform/linuxbsd/wayland/dynwrappers/libdecor-so_wrap.c @@ -0,0 +1,453 @@ +// This file is generated. Do not edit! +// see https://github.com/hpvb/dynload-wrapper for details +// generated by ./generate-wrapper.py 0.3 on 2022-12-12 10:55:19 +// flags: ./generate-wrapper.py --include /usr/include/libdecor-0/libdecor.h --sys-include --soname libdecor-0.so.0 --init-name libdecor --output-header libdecor-so_wrap.h --output-implementation libdecor-so_wrap.c --omit-prefix wl_ +// +// EDIT: This has been handpatched to properly report the pointer type of the window_state argument of libdecor_configuration_get_window_state. +#include + +#define libdecor_unref libdecor_unref_dylibloader_orig_libdecor +#define libdecor_new libdecor_new_dylibloader_orig_libdecor +#define libdecor_get_fd libdecor_get_fd_dylibloader_orig_libdecor +#define libdecor_dispatch libdecor_dispatch_dylibloader_orig_libdecor +#define libdecor_decorate libdecor_decorate_dylibloader_orig_libdecor +#define libdecor_frame_ref libdecor_frame_ref_dylibloader_orig_libdecor +#define libdecor_frame_unref libdecor_frame_unref_dylibloader_orig_libdecor +#define libdecor_frame_set_visibility libdecor_frame_set_visibility_dylibloader_orig_libdecor +#define libdecor_frame_is_visible libdecor_frame_is_visible_dylibloader_orig_libdecor +#define libdecor_frame_set_parent libdecor_frame_set_parent_dylibloader_orig_libdecor +#define libdecor_frame_set_title libdecor_frame_set_title_dylibloader_orig_libdecor +#define libdecor_frame_get_title libdecor_frame_get_title_dylibloader_orig_libdecor +#define libdecor_frame_set_app_id libdecor_frame_set_app_id_dylibloader_orig_libdecor +#define libdecor_frame_set_capabilities libdecor_frame_set_capabilities_dylibloader_orig_libdecor +#define libdecor_frame_unset_capabilities libdecor_frame_unset_capabilities_dylibloader_orig_libdecor +#define libdecor_frame_has_capability libdecor_frame_has_capability_dylibloader_orig_libdecor +#define libdecor_frame_show_window_menu libdecor_frame_show_window_menu_dylibloader_orig_libdecor +#define libdecor_frame_popup_grab libdecor_frame_popup_grab_dylibloader_orig_libdecor +#define libdecor_frame_popup_ungrab libdecor_frame_popup_ungrab_dylibloader_orig_libdecor +#define libdecor_frame_translate_coordinate libdecor_frame_translate_coordinate_dylibloader_orig_libdecor +#define libdecor_frame_set_min_content_size libdecor_frame_set_min_content_size_dylibloader_orig_libdecor +#define libdecor_frame_set_max_content_size libdecor_frame_set_max_content_size_dylibloader_orig_libdecor +#define libdecor_frame_resize libdecor_frame_resize_dylibloader_orig_libdecor +#define libdecor_frame_move libdecor_frame_move_dylibloader_orig_libdecor +#define libdecor_frame_commit libdecor_frame_commit_dylibloader_orig_libdecor +#define libdecor_frame_set_minimized libdecor_frame_set_minimized_dylibloader_orig_libdecor +#define libdecor_frame_set_maximized libdecor_frame_set_maximized_dylibloader_orig_libdecor +#define libdecor_frame_unset_maximized libdecor_frame_unset_maximized_dylibloader_orig_libdecor +#define libdecor_frame_set_fullscreen libdecor_frame_set_fullscreen_dylibloader_orig_libdecor +#define libdecor_frame_unset_fullscreen libdecor_frame_unset_fullscreen_dylibloader_orig_libdecor +#define libdecor_frame_is_floating libdecor_frame_is_floating_dylibloader_orig_libdecor +#define libdecor_frame_close libdecor_frame_close_dylibloader_orig_libdecor +#define libdecor_frame_map libdecor_frame_map_dylibloader_orig_libdecor +#define libdecor_frame_get_xdg_surface libdecor_frame_get_xdg_surface_dylibloader_orig_libdecor +#define libdecor_frame_get_xdg_toplevel libdecor_frame_get_xdg_toplevel_dylibloader_orig_libdecor +#define libdecor_state_new libdecor_state_new_dylibloader_orig_libdecor +#define libdecor_state_free libdecor_state_free_dylibloader_orig_libdecor +#define libdecor_configuration_get_content_size libdecor_configuration_get_content_size_dylibloader_orig_libdecor +#define libdecor_configuration_get_window_state libdecor_configuration_get_window_state_dylibloader_orig_libdecor +#include +#undef libdecor_unref +#undef libdecor_new +#undef libdecor_get_fd +#undef libdecor_dispatch +#undef libdecor_decorate +#undef libdecor_frame_ref +#undef libdecor_frame_unref +#undef libdecor_frame_set_visibility +#undef libdecor_frame_is_visible +#undef libdecor_frame_set_parent +#undef libdecor_frame_set_title +#undef libdecor_frame_get_title +#undef libdecor_frame_set_app_id +#undef libdecor_frame_set_capabilities +#undef libdecor_frame_unset_capabilities +#undef libdecor_frame_has_capability +#undef libdecor_frame_show_window_menu +#undef libdecor_frame_popup_grab +#undef libdecor_frame_popup_ungrab +#undef libdecor_frame_translate_coordinate +#undef libdecor_frame_set_min_content_size +#undef libdecor_frame_set_max_content_size +#undef libdecor_frame_resize +#undef libdecor_frame_move +#undef libdecor_frame_commit +#undef libdecor_frame_set_minimized +#undef libdecor_frame_set_maximized +#undef libdecor_frame_unset_maximized +#undef libdecor_frame_set_fullscreen +#undef libdecor_frame_unset_fullscreen +#undef libdecor_frame_is_floating +#undef libdecor_frame_close +#undef libdecor_frame_map +#undef libdecor_frame_get_xdg_surface +#undef libdecor_frame_get_xdg_toplevel +#undef libdecor_state_new +#undef libdecor_state_free +#undef libdecor_configuration_get_content_size +#undef libdecor_configuration_get_window_state +#include +#include +void (*libdecor_unref_dylibloader_wrapper_libdecor)(struct libdecor*); +struct libdecor* (*libdecor_new_dylibloader_wrapper_libdecor)(struct wl_display*,struct libdecor_interface*); +int (*libdecor_get_fd_dylibloader_wrapper_libdecor)(struct libdecor*); +int (*libdecor_dispatch_dylibloader_wrapper_libdecor)(struct libdecor*, int); +struct libdecor_frame* (*libdecor_decorate_dylibloader_wrapper_libdecor)(struct libdecor*,struct wl_surface*,struct libdecor_frame_interface*, void*); +void (*libdecor_frame_ref_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +void (*libdecor_frame_unref_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +void (*libdecor_frame_set_visibility_dylibloader_wrapper_libdecor)(struct libdecor_frame*, bool); +bool (*libdecor_frame_is_visible_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +void (*libdecor_frame_set_parent_dylibloader_wrapper_libdecor)(struct libdecor_frame*,struct libdecor_frame*); +void (*libdecor_frame_set_title_dylibloader_wrapper_libdecor)(struct libdecor_frame*,const char*); +const char* (*libdecor_frame_get_title_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +void (*libdecor_frame_set_app_id_dylibloader_wrapper_libdecor)(struct libdecor_frame*,const char*); +void (*libdecor_frame_set_capabilities_dylibloader_wrapper_libdecor)(struct libdecor_frame*,enum libdecor_capabilities); +void (*libdecor_frame_unset_capabilities_dylibloader_wrapper_libdecor)(struct libdecor_frame*,enum libdecor_capabilities); +bool (*libdecor_frame_has_capability_dylibloader_wrapper_libdecor)(struct libdecor_frame*,enum libdecor_capabilities); +void (*libdecor_frame_show_window_menu_dylibloader_wrapper_libdecor)(struct libdecor_frame*,struct wl_seat*, uint32_t, int, int); +void (*libdecor_frame_popup_grab_dylibloader_wrapper_libdecor)(struct libdecor_frame*,const char*); +void (*libdecor_frame_popup_ungrab_dylibloader_wrapper_libdecor)(struct libdecor_frame*,const char*); +void (*libdecor_frame_translate_coordinate_dylibloader_wrapper_libdecor)(struct libdecor_frame*, int, int, int*, int*); +void (*libdecor_frame_set_min_content_size_dylibloader_wrapper_libdecor)(struct libdecor_frame*, int, int); +void (*libdecor_frame_set_max_content_size_dylibloader_wrapper_libdecor)(struct libdecor_frame*, int, int); +void (*libdecor_frame_resize_dylibloader_wrapper_libdecor)(struct libdecor_frame*,struct wl_seat*, uint32_t,enum libdecor_resize_edge); +void (*libdecor_frame_move_dylibloader_wrapper_libdecor)(struct libdecor_frame*,struct wl_seat*, uint32_t); +void (*libdecor_frame_commit_dylibloader_wrapper_libdecor)(struct libdecor_frame*,struct libdecor_state*,struct libdecor_configuration*); +void (*libdecor_frame_set_minimized_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +void (*libdecor_frame_set_maximized_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +void (*libdecor_frame_unset_maximized_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +void (*libdecor_frame_set_fullscreen_dylibloader_wrapper_libdecor)(struct libdecor_frame*,struct wl_output*); +void (*libdecor_frame_unset_fullscreen_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +bool (*libdecor_frame_is_floating_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +void (*libdecor_frame_close_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +void (*libdecor_frame_map_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +struct xdg_surface* (*libdecor_frame_get_xdg_surface_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +struct xdg_toplevel* (*libdecor_frame_get_xdg_toplevel_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +struct libdecor_state* (*libdecor_state_new_dylibloader_wrapper_libdecor)( int, int); +void (*libdecor_state_free_dylibloader_wrapper_libdecor)(struct libdecor_state*); +bool (*libdecor_configuration_get_content_size_dylibloader_wrapper_libdecor)(struct libdecor_configuration*,struct libdecor_frame*, int*, int*); +bool (*libdecor_configuration_get_window_state_dylibloader_wrapper_libdecor)(struct libdecor_configuration*,enum libdecor_window_state*); +int initialize_libdecor(int verbose) { + void *handle; + char *error; + handle = dlopen("libdecor-0.so.0", RTLD_LAZY); + if (!handle) { + if (verbose) { + fprintf(stderr, "%s\n", dlerror()); + } + return(1); + } + dlerror(); +// libdecor_unref + *(void **) (&libdecor_unref_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_unref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_new + *(void **) (&libdecor_new_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_new"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_get_fd + *(void **) (&libdecor_get_fd_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_get_fd"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_dispatch + *(void **) (&libdecor_dispatch_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_dispatch"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_decorate + *(void **) (&libdecor_decorate_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_decorate"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_ref + *(void **) (&libdecor_frame_ref_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_ref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_unref + *(void **) (&libdecor_frame_unref_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_unref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_set_visibility + *(void **) (&libdecor_frame_set_visibility_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_set_visibility"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_is_visible + *(void **) (&libdecor_frame_is_visible_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_is_visible"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_set_parent + *(void **) (&libdecor_frame_set_parent_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_set_parent"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_set_title + *(void **) (&libdecor_frame_set_title_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_set_title"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_get_title + *(void **) (&libdecor_frame_get_title_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_get_title"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_set_app_id + *(void **) (&libdecor_frame_set_app_id_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_set_app_id"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_set_capabilities + *(void **) (&libdecor_frame_set_capabilities_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_set_capabilities"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_unset_capabilities + *(void **) (&libdecor_frame_unset_capabilities_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_unset_capabilities"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_has_capability + *(void **) (&libdecor_frame_has_capability_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_has_capability"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_show_window_menu + *(void **) (&libdecor_frame_show_window_menu_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_show_window_menu"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_popup_grab + *(void **) (&libdecor_frame_popup_grab_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_popup_grab"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_popup_ungrab + *(void **) (&libdecor_frame_popup_ungrab_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_popup_ungrab"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_translate_coordinate + *(void **) (&libdecor_frame_translate_coordinate_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_translate_coordinate"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_set_min_content_size + *(void **) (&libdecor_frame_set_min_content_size_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_set_min_content_size"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_set_max_content_size + *(void **) (&libdecor_frame_set_max_content_size_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_set_max_content_size"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_resize + *(void **) (&libdecor_frame_resize_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_resize"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_move + *(void **) (&libdecor_frame_move_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_move"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_commit + *(void **) (&libdecor_frame_commit_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_commit"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_set_minimized + *(void **) (&libdecor_frame_set_minimized_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_set_minimized"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_set_maximized + *(void **) (&libdecor_frame_set_maximized_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_set_maximized"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_unset_maximized + *(void **) (&libdecor_frame_unset_maximized_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_unset_maximized"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_set_fullscreen + *(void **) (&libdecor_frame_set_fullscreen_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_set_fullscreen"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_unset_fullscreen + *(void **) (&libdecor_frame_unset_fullscreen_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_unset_fullscreen"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_is_floating + *(void **) (&libdecor_frame_is_floating_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_is_floating"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_close + *(void **) (&libdecor_frame_close_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_close"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_map + *(void **) (&libdecor_frame_map_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_map"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_get_xdg_surface + *(void **) (&libdecor_frame_get_xdg_surface_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_get_xdg_surface"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_frame_get_xdg_toplevel + *(void **) (&libdecor_frame_get_xdg_toplevel_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_frame_get_xdg_toplevel"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_state_new + *(void **) (&libdecor_state_new_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_state_new"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_state_free + *(void **) (&libdecor_state_free_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_state_free"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_configuration_get_content_size + *(void **) (&libdecor_configuration_get_content_size_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_configuration_get_content_size"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// libdecor_configuration_get_window_state + *(void **) (&libdecor_configuration_get_window_state_dylibloader_wrapper_libdecor) = dlsym(handle, "libdecor_configuration_get_window_state"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +return 0; +} diff --git a/platform/linuxbsd/wayland/dynwrappers/libdecor-so_wrap.h b/platform/linuxbsd/wayland/dynwrappers/libdecor-so_wrap.h new file mode 100644 index 00000000000..bf3f5200086 --- /dev/null +++ b/platform/linuxbsd/wayland/dynwrappers/libdecor-so_wrap.h @@ -0,0 +1,175 @@ +#ifndef DYLIBLOAD_WRAPPER_LIBDECOR +#define DYLIBLOAD_WRAPPER_LIBDECOR +// This file is generated. Do not edit! +// see https://github.com/hpvb/dynload-wrapper for details +// generated by ./generate-wrapper.py 0.3 on 2022-12-12 10:55:19 +// flags: ./generate-wrapper.py --include /usr/include/libdecor-0/libdecor.h --sys-include --soname libdecor-0.so.0 --init-name libdecor --output-header libdecor-so_wrap.h --output-implementation libdecor-so_wrap.c --omit-prefix wl_ +// +// EDIT: This has been handpatched to properly report the pointer type of the window_state argument of libdecor_configuration_get_window_state. +#include + +#define libdecor_unref libdecor_unref_dylibloader_orig_libdecor +#define libdecor_new libdecor_new_dylibloader_orig_libdecor +#define libdecor_get_fd libdecor_get_fd_dylibloader_orig_libdecor +#define libdecor_dispatch libdecor_dispatch_dylibloader_orig_libdecor +#define libdecor_decorate libdecor_decorate_dylibloader_orig_libdecor +#define libdecor_frame_ref libdecor_frame_ref_dylibloader_orig_libdecor +#define libdecor_frame_unref libdecor_frame_unref_dylibloader_orig_libdecor +#define libdecor_frame_set_visibility libdecor_frame_set_visibility_dylibloader_orig_libdecor +#define libdecor_frame_is_visible libdecor_frame_is_visible_dylibloader_orig_libdecor +#define libdecor_frame_set_parent libdecor_frame_set_parent_dylibloader_orig_libdecor +#define libdecor_frame_set_title libdecor_frame_set_title_dylibloader_orig_libdecor +#define libdecor_frame_get_title libdecor_frame_get_title_dylibloader_orig_libdecor +#define libdecor_frame_set_app_id libdecor_frame_set_app_id_dylibloader_orig_libdecor +#define libdecor_frame_set_capabilities libdecor_frame_set_capabilities_dylibloader_orig_libdecor +#define libdecor_frame_unset_capabilities libdecor_frame_unset_capabilities_dylibloader_orig_libdecor +#define libdecor_frame_has_capability libdecor_frame_has_capability_dylibloader_orig_libdecor +#define libdecor_frame_show_window_menu libdecor_frame_show_window_menu_dylibloader_orig_libdecor +#define libdecor_frame_popup_grab libdecor_frame_popup_grab_dylibloader_orig_libdecor +#define libdecor_frame_popup_ungrab libdecor_frame_popup_ungrab_dylibloader_orig_libdecor +#define libdecor_frame_translate_coordinate libdecor_frame_translate_coordinate_dylibloader_orig_libdecor +#define libdecor_frame_set_min_content_size libdecor_frame_set_min_content_size_dylibloader_orig_libdecor +#define libdecor_frame_set_max_content_size libdecor_frame_set_max_content_size_dylibloader_orig_libdecor +#define libdecor_frame_resize libdecor_frame_resize_dylibloader_orig_libdecor +#define libdecor_frame_move libdecor_frame_move_dylibloader_orig_libdecor +#define libdecor_frame_commit libdecor_frame_commit_dylibloader_orig_libdecor +#define libdecor_frame_set_minimized libdecor_frame_set_minimized_dylibloader_orig_libdecor +#define libdecor_frame_set_maximized libdecor_frame_set_maximized_dylibloader_orig_libdecor +#define libdecor_frame_unset_maximized libdecor_frame_unset_maximized_dylibloader_orig_libdecor +#define libdecor_frame_set_fullscreen libdecor_frame_set_fullscreen_dylibloader_orig_libdecor +#define libdecor_frame_unset_fullscreen libdecor_frame_unset_fullscreen_dylibloader_orig_libdecor +#define libdecor_frame_is_floating libdecor_frame_is_floating_dylibloader_orig_libdecor +#define libdecor_frame_close libdecor_frame_close_dylibloader_orig_libdecor +#define libdecor_frame_map libdecor_frame_map_dylibloader_orig_libdecor +#define libdecor_frame_get_xdg_surface libdecor_frame_get_xdg_surface_dylibloader_orig_libdecor +#define libdecor_frame_get_xdg_toplevel libdecor_frame_get_xdg_toplevel_dylibloader_orig_libdecor +#define libdecor_state_new libdecor_state_new_dylibloader_orig_libdecor +#define libdecor_state_free libdecor_state_free_dylibloader_orig_libdecor +#define libdecor_configuration_get_content_size libdecor_configuration_get_content_size_dylibloader_orig_libdecor +#define libdecor_configuration_get_window_state libdecor_configuration_get_window_state_dylibloader_orig_libdecor +#include +#undef libdecor_unref +#undef libdecor_new +#undef libdecor_get_fd +#undef libdecor_dispatch +#undef libdecor_decorate +#undef libdecor_frame_ref +#undef libdecor_frame_unref +#undef libdecor_frame_set_visibility +#undef libdecor_frame_is_visible +#undef libdecor_frame_set_parent +#undef libdecor_frame_set_title +#undef libdecor_frame_get_title +#undef libdecor_frame_set_app_id +#undef libdecor_frame_set_capabilities +#undef libdecor_frame_unset_capabilities +#undef libdecor_frame_has_capability +#undef libdecor_frame_show_window_menu +#undef libdecor_frame_popup_grab +#undef libdecor_frame_popup_ungrab +#undef libdecor_frame_translate_coordinate +#undef libdecor_frame_set_min_content_size +#undef libdecor_frame_set_max_content_size +#undef libdecor_frame_resize +#undef libdecor_frame_move +#undef libdecor_frame_commit +#undef libdecor_frame_set_minimized +#undef libdecor_frame_set_maximized +#undef libdecor_frame_unset_maximized +#undef libdecor_frame_set_fullscreen +#undef libdecor_frame_unset_fullscreen +#undef libdecor_frame_is_floating +#undef libdecor_frame_close +#undef libdecor_frame_map +#undef libdecor_frame_get_xdg_surface +#undef libdecor_frame_get_xdg_toplevel +#undef libdecor_state_new +#undef libdecor_state_free +#undef libdecor_configuration_get_content_size +#undef libdecor_configuration_get_window_state +#ifdef __cplusplus +extern "C" { +#endif +#define libdecor_unref libdecor_unref_dylibloader_wrapper_libdecor +#define libdecor_new libdecor_new_dylibloader_wrapper_libdecor +#define libdecor_get_fd libdecor_get_fd_dylibloader_wrapper_libdecor +#define libdecor_dispatch libdecor_dispatch_dylibloader_wrapper_libdecor +#define libdecor_decorate libdecor_decorate_dylibloader_wrapper_libdecor +#define libdecor_frame_ref libdecor_frame_ref_dylibloader_wrapper_libdecor +#define libdecor_frame_unref libdecor_frame_unref_dylibloader_wrapper_libdecor +#define libdecor_frame_set_visibility libdecor_frame_set_visibility_dylibloader_wrapper_libdecor +#define libdecor_frame_is_visible libdecor_frame_is_visible_dylibloader_wrapper_libdecor +#define libdecor_frame_set_parent libdecor_frame_set_parent_dylibloader_wrapper_libdecor +#define libdecor_frame_set_title libdecor_frame_set_title_dylibloader_wrapper_libdecor +#define libdecor_frame_get_title libdecor_frame_get_title_dylibloader_wrapper_libdecor +#define libdecor_frame_set_app_id libdecor_frame_set_app_id_dylibloader_wrapper_libdecor +#define libdecor_frame_set_capabilities libdecor_frame_set_capabilities_dylibloader_wrapper_libdecor +#define libdecor_frame_unset_capabilities libdecor_frame_unset_capabilities_dylibloader_wrapper_libdecor +#define libdecor_frame_has_capability libdecor_frame_has_capability_dylibloader_wrapper_libdecor +#define libdecor_frame_show_window_menu libdecor_frame_show_window_menu_dylibloader_wrapper_libdecor +#define libdecor_frame_popup_grab libdecor_frame_popup_grab_dylibloader_wrapper_libdecor +#define libdecor_frame_popup_ungrab libdecor_frame_popup_ungrab_dylibloader_wrapper_libdecor +#define libdecor_frame_translate_coordinate libdecor_frame_translate_coordinate_dylibloader_wrapper_libdecor +#define libdecor_frame_set_min_content_size libdecor_frame_set_min_content_size_dylibloader_wrapper_libdecor +#define libdecor_frame_set_max_content_size libdecor_frame_set_max_content_size_dylibloader_wrapper_libdecor +#define libdecor_frame_resize libdecor_frame_resize_dylibloader_wrapper_libdecor +#define libdecor_frame_move libdecor_frame_move_dylibloader_wrapper_libdecor +#define libdecor_frame_commit libdecor_frame_commit_dylibloader_wrapper_libdecor +#define libdecor_frame_set_minimized libdecor_frame_set_minimized_dylibloader_wrapper_libdecor +#define libdecor_frame_set_maximized libdecor_frame_set_maximized_dylibloader_wrapper_libdecor +#define libdecor_frame_unset_maximized libdecor_frame_unset_maximized_dylibloader_wrapper_libdecor +#define libdecor_frame_set_fullscreen libdecor_frame_set_fullscreen_dylibloader_wrapper_libdecor +#define libdecor_frame_unset_fullscreen libdecor_frame_unset_fullscreen_dylibloader_wrapper_libdecor +#define libdecor_frame_is_floating libdecor_frame_is_floating_dylibloader_wrapper_libdecor +#define libdecor_frame_close libdecor_frame_close_dylibloader_wrapper_libdecor +#define libdecor_frame_map libdecor_frame_map_dylibloader_wrapper_libdecor +#define libdecor_frame_get_xdg_surface libdecor_frame_get_xdg_surface_dylibloader_wrapper_libdecor +#define libdecor_frame_get_xdg_toplevel libdecor_frame_get_xdg_toplevel_dylibloader_wrapper_libdecor +#define libdecor_state_new libdecor_state_new_dylibloader_wrapper_libdecor +#define libdecor_state_free libdecor_state_free_dylibloader_wrapper_libdecor +#define libdecor_configuration_get_content_size libdecor_configuration_get_content_size_dylibloader_wrapper_libdecor +#define libdecor_configuration_get_window_state libdecor_configuration_get_window_state_dylibloader_wrapper_libdecor +extern void (*libdecor_unref_dylibloader_wrapper_libdecor)(struct libdecor*); +extern struct libdecor* (*libdecor_new_dylibloader_wrapper_libdecor)(struct wl_display*,struct libdecor_interface*); +extern int (*libdecor_get_fd_dylibloader_wrapper_libdecor)(struct libdecor*); +extern int (*libdecor_dispatch_dylibloader_wrapper_libdecor)(struct libdecor*, int); +extern struct libdecor_frame* (*libdecor_decorate_dylibloader_wrapper_libdecor)(struct libdecor*,struct wl_surface*,struct libdecor_frame_interface*, void*); +extern void (*libdecor_frame_ref_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +extern void (*libdecor_frame_unref_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +extern void (*libdecor_frame_set_visibility_dylibloader_wrapper_libdecor)(struct libdecor_frame*, bool); +extern bool (*libdecor_frame_is_visible_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +extern void (*libdecor_frame_set_parent_dylibloader_wrapper_libdecor)(struct libdecor_frame*,struct libdecor_frame*); +extern void (*libdecor_frame_set_title_dylibloader_wrapper_libdecor)(struct libdecor_frame*,const char*); +extern const char* (*libdecor_frame_get_title_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +extern void (*libdecor_frame_set_app_id_dylibloader_wrapper_libdecor)(struct libdecor_frame*,const char*); +extern void (*libdecor_frame_set_capabilities_dylibloader_wrapper_libdecor)(struct libdecor_frame*,enum libdecor_capabilities); +extern void (*libdecor_frame_unset_capabilities_dylibloader_wrapper_libdecor)(struct libdecor_frame*,enum libdecor_capabilities); +extern bool (*libdecor_frame_has_capability_dylibloader_wrapper_libdecor)(struct libdecor_frame*,enum libdecor_capabilities); +extern void (*libdecor_frame_show_window_menu_dylibloader_wrapper_libdecor)(struct libdecor_frame*,struct wl_seat*, uint32_t, int, int); +extern void (*libdecor_frame_popup_grab_dylibloader_wrapper_libdecor)(struct libdecor_frame*,const char*); +extern void (*libdecor_frame_popup_ungrab_dylibloader_wrapper_libdecor)(struct libdecor_frame*,const char*); +extern void (*libdecor_frame_translate_coordinate_dylibloader_wrapper_libdecor)(struct libdecor_frame*, int, int, int*, int*); +extern void (*libdecor_frame_set_min_content_size_dylibloader_wrapper_libdecor)(struct libdecor_frame*, int, int); +extern void (*libdecor_frame_set_max_content_size_dylibloader_wrapper_libdecor)(struct libdecor_frame*, int, int); +extern void (*libdecor_frame_resize_dylibloader_wrapper_libdecor)(struct libdecor_frame*,struct wl_seat*, uint32_t,enum libdecor_resize_edge); +extern void (*libdecor_frame_move_dylibloader_wrapper_libdecor)(struct libdecor_frame*,struct wl_seat*, uint32_t); +extern void (*libdecor_frame_commit_dylibloader_wrapper_libdecor)(struct libdecor_frame*,struct libdecor_state*,struct libdecor_configuration*); +extern void (*libdecor_frame_set_minimized_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +extern void (*libdecor_frame_set_maximized_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +extern void (*libdecor_frame_unset_maximized_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +extern void (*libdecor_frame_set_fullscreen_dylibloader_wrapper_libdecor)(struct libdecor_frame*,struct wl_output*); +extern void (*libdecor_frame_unset_fullscreen_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +extern bool (*libdecor_frame_is_floating_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +extern void (*libdecor_frame_close_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +extern void (*libdecor_frame_map_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +extern struct xdg_surface* (*libdecor_frame_get_xdg_surface_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +extern struct xdg_toplevel* (*libdecor_frame_get_xdg_toplevel_dylibloader_wrapper_libdecor)(struct libdecor_frame*); +extern struct libdecor_state* (*libdecor_state_new_dylibloader_wrapper_libdecor)( int, int); +extern void (*libdecor_state_free_dylibloader_wrapper_libdecor)(struct libdecor_state*); +extern bool (*libdecor_configuration_get_content_size_dylibloader_wrapper_libdecor)(struct libdecor_configuration*,struct libdecor_frame*, int*, int*); +extern bool (*libdecor_configuration_get_window_state_dylibloader_wrapper_libdecor)(struct libdecor_configuration*,enum libdecor_window_state*); +int initialize_libdecor(int verbose); +#ifdef __cplusplus +} +#endif +#endif diff --git a/platform/linuxbsd/wayland/dynwrappers/wayland-client-core-so_wrap.c b/platform/linuxbsd/wayland/dynwrappers/wayland-client-core-so_wrap.c new file mode 100644 index 00000000000..0cd8e56a776 --- /dev/null +++ b/platform/linuxbsd/wayland/dynwrappers/wayland-client-core-so_wrap.c @@ -0,0 +1,607 @@ +// This file is generated. Do not edit! +// see https://github.com/hpvb/dynload-wrapper for details +// generated by ../dynload-wrapper/generate-wrapper.py 0.3 on 2023-01-25 17:36:12 +// flags: ../dynload-wrapper/generate-wrapper.py --include ./thirdparty/linuxbsd_headers/wayland/wayland-client-core.h --sys-include "./thirdparty/linuxbsd_headers/wayland/wayland-client-core.h" --soname libwayland-client.so.0 --init-name wayland_client --output-header platform/linuxbsd/wayland/dynwrappers/wayland-client-core-so_wrap.h --output-implementation platform/linuxbsd/wayland/dynwrappers/wayland-client-core-so_wrap.c +// +// NOTE: This has been hand-patched to workaround some issues. +#include + +#define wl_list_init wl_list_init_dylibloader_orig_wayland_client +#define wl_list_insert wl_list_insert_dylibloader_orig_wayland_client +#define wl_list_remove wl_list_remove_dylibloader_orig_wayland_client +#define wl_list_length wl_list_length_dylibloader_orig_wayland_client +#define wl_list_empty wl_list_empty_dylibloader_orig_wayland_client +#define wl_list_insert_list wl_list_insert_list_dylibloader_orig_wayland_client +#define wl_array_init wl_array_init_dylibloader_orig_wayland_client +#define wl_array_release wl_array_release_dylibloader_orig_wayland_client +#define wl_array_add wl_array_add_dylibloader_orig_wayland_client +#define wl_array_copy wl_array_copy_dylibloader_orig_wayland_client +#define wl_event_queue_destroy wl_event_queue_destroy_dylibloader_orig_wayland_client +#define wl_proxy_marshal_flags wl_proxy_marshal_flags_dylibloader_orig_wayland_client +#define wl_proxy_marshal_array_flags wl_proxy_marshal_array_flags_dylibloader_orig_wayland_client +#define wl_proxy_marshal wl_proxy_marshal_dylibloader_orig_wayland_client +#define wl_proxy_marshal_array wl_proxy_marshal_array_dylibloader_orig_wayland_client +#define wl_proxy_create wl_proxy_create_dylibloader_orig_wayland_client +#define wl_proxy_create_wrapper wl_proxy_create_wrapper_dylibloader_orig_wayland_client +#define wl_proxy_wrapper_destroy wl_proxy_wrapper_destroy_dylibloader_orig_wayland_client +#define wl_proxy_marshal_constructor wl_proxy_marshal_constructor_dylibloader_orig_wayland_client +#define wl_proxy_marshal_constructor_versioned wl_proxy_marshal_constructor_versioned_dylibloader_orig_wayland_client +#define wl_proxy_marshal_array_constructor wl_proxy_marshal_array_constructor_dylibloader_orig_wayland_client +#define wl_proxy_marshal_array_constructor_versioned wl_proxy_marshal_array_constructor_versioned_dylibloader_orig_wayland_client +#define wl_proxy_destroy wl_proxy_destroy_dylibloader_orig_wayland_client +#define wl_proxy_add_listener wl_proxy_add_listener_dylibloader_orig_wayland_client +#define wl_proxy_get_listener wl_proxy_get_listener_dylibloader_orig_wayland_client +#define wl_proxy_add_dispatcher wl_proxy_add_dispatcher_dylibloader_orig_wayland_client +#define wl_proxy_set_user_data wl_proxy_set_user_data_dylibloader_orig_wayland_client +#define wl_proxy_get_user_data wl_proxy_get_user_data_dylibloader_orig_wayland_client +#define wl_proxy_get_version wl_proxy_get_version_dylibloader_orig_wayland_client +#define wl_proxy_get_id wl_proxy_get_id_dylibloader_orig_wayland_client +#define wl_proxy_set_tag wl_proxy_set_tag_dylibloader_orig_wayland_client +#define wl_proxy_get_tag wl_proxy_get_tag_dylibloader_orig_wayland_client +#define wl_proxy_get_class wl_proxy_get_class_dylibloader_orig_wayland_client +#define wl_proxy_set_queue wl_proxy_set_queue_dylibloader_orig_wayland_client +#define wl_display_connect wl_display_connect_dylibloader_orig_wayland_client +#define wl_display_connect_to_fd wl_display_connect_to_fd_dylibloader_orig_wayland_client +#define wl_display_disconnect wl_display_disconnect_dylibloader_orig_wayland_client +#define wl_display_get_fd wl_display_get_fd_dylibloader_orig_wayland_client +#define wl_display_dispatch wl_display_dispatch_dylibloader_orig_wayland_client +#define wl_display_dispatch_queue wl_display_dispatch_queue_dylibloader_orig_wayland_client +#define wl_display_dispatch_queue_pending wl_display_dispatch_queue_pending_dylibloader_orig_wayland_client +#define wl_display_dispatch_pending wl_display_dispatch_pending_dylibloader_orig_wayland_client +#define wl_display_get_error wl_display_get_error_dylibloader_orig_wayland_client +#define wl_display_get_protocol_error wl_display_get_protocol_error_dylibloader_orig_wayland_client +#define wl_display_flush wl_display_flush_dylibloader_orig_wayland_client +#define wl_display_roundtrip_queue wl_display_roundtrip_queue_dylibloader_orig_wayland_client +#define wl_display_roundtrip wl_display_roundtrip_dylibloader_orig_wayland_client +#define wl_display_create_queue wl_display_create_queue_dylibloader_orig_wayland_client +#define wl_display_prepare_read_queue wl_display_prepare_read_queue_dylibloader_orig_wayland_client +#define wl_display_prepare_read wl_display_prepare_read_dylibloader_orig_wayland_client +#define wl_display_cancel_read wl_display_cancel_read_dylibloader_orig_wayland_client +#define wl_display_read_events wl_display_read_events_dylibloader_orig_wayland_client +#define wl_log_set_handler_client wl_log_set_handler_client_dylibloader_orig_wayland_client +#include "./thirdparty/linuxbsd_headers/wayland/wayland-client-core.h" +#undef wl_list_init +#undef wl_list_insert +#undef wl_list_remove +#undef wl_list_length +#undef wl_list_empty +#undef wl_list_insert_list +#undef wl_array_init +#undef wl_array_release +#undef wl_array_add +#undef wl_array_copy +#undef wl_event_queue_destroy +#undef wl_proxy_marshal_flags +#undef wl_proxy_marshal_array_flags +#undef wl_proxy_marshal +#undef wl_proxy_marshal_array +#undef wl_proxy_create +#undef wl_proxy_create_wrapper +#undef wl_proxy_wrapper_destroy +#undef wl_proxy_marshal_constructor +#undef wl_proxy_marshal_constructor_versioned +#undef wl_proxy_marshal_array_constructor +#undef wl_proxy_marshal_array_constructor_versioned +#undef wl_proxy_destroy +#undef wl_proxy_add_listener +#undef wl_proxy_get_listener +#undef wl_proxy_add_dispatcher +#undef wl_proxy_set_user_data +#undef wl_proxy_get_user_data +#undef wl_proxy_get_version +#undef wl_proxy_get_id +#undef wl_proxy_set_tag +#undef wl_proxy_get_tag +#undef wl_proxy_get_class +#undef wl_proxy_set_queue +#undef wl_display_connect +#undef wl_display_connect_to_fd +#undef wl_display_disconnect +#undef wl_display_get_fd +#undef wl_display_dispatch +#undef wl_display_dispatch_queue +#undef wl_display_dispatch_queue_pending +#undef wl_display_dispatch_pending +#undef wl_display_get_error +#undef wl_display_get_protocol_error +#undef wl_display_flush +#undef wl_display_roundtrip_queue +#undef wl_display_roundtrip +#undef wl_display_create_queue +#undef wl_display_prepare_read_queue +#undef wl_display_prepare_read +#undef wl_display_cancel_read +#undef wl_display_read_events +#undef wl_log_set_handler_client +#include +#include +void (*wl_list_init_dylibloader_wrapper_wayland_client)(struct wl_list*); +void (*wl_list_insert_dylibloader_wrapper_wayland_client)(struct wl_list*,struct wl_list*); +void (*wl_list_remove_dylibloader_wrapper_wayland_client)(struct wl_list*); +int (*wl_list_length_dylibloader_wrapper_wayland_client)(struct wl_list*); +int (*wl_list_empty_dylibloader_wrapper_wayland_client)(struct wl_list*); +void (*wl_list_insert_list_dylibloader_wrapper_wayland_client)(struct wl_list*,struct wl_list*); +void (*wl_array_init_dylibloader_wrapper_wayland_client)(struct wl_array*); +void (*wl_array_release_dylibloader_wrapper_wayland_client)(struct wl_array*); +void* (*wl_array_add_dylibloader_wrapper_wayland_client)(struct wl_array*, size_t); +int (*wl_array_copy_dylibloader_wrapper_wayland_client)(struct wl_array*,struct wl_array*); +void (*wl_event_queue_destroy_dylibloader_wrapper_wayland_client)(struct wl_event_queue*); +struct wl_proxy* (*wl_proxy_marshal_flags_dylibloader_wrapper_wayland_client)(struct wl_proxy*, uint32_t,const struct wl_interface*, uint32_t, uint32_t,...); +struct wl_proxy* (*wl_proxy_marshal_array_flags_dylibloader_wrapper_wayland_client)(struct wl_proxy*, uint32_t,const struct wl_interface*, uint32_t, uint32_t,union wl_argument); +void (*wl_proxy_marshal_dylibloader_wrapper_wayland_client)(struct wl_proxy*, uint32_t,...); +void (*wl_proxy_marshal_array_dylibloader_wrapper_wayland_client)(struct wl_proxy*, uint32_t,union wl_argument); +struct wl_proxy* (*wl_proxy_create_dylibloader_wrapper_wayland_client)(struct wl_proxy*,const struct wl_interface*); +void* (*wl_proxy_create_wrapper_dylibloader_wrapper_wayland_client)( void*); +void (*wl_proxy_wrapper_destroy_dylibloader_wrapper_wayland_client)( void*); +struct wl_proxy* (*wl_proxy_marshal_constructor_dylibloader_wrapper_wayland_client)(struct wl_proxy*, uint32_t,const struct wl_interface*,...); +struct wl_proxy* (*wl_proxy_marshal_constructor_versioned_dylibloader_wrapper_wayland_client)(struct wl_proxy*, uint32_t,const struct wl_interface*, uint32_t,...); +struct wl_proxy* (*wl_proxy_marshal_array_constructor_dylibloader_wrapper_wayland_client)(struct wl_proxy*, uint32_t,union wl_argument,const struct wl_interface*); +struct wl_proxy* (*wl_proxy_marshal_array_constructor_versioned_dylibloader_wrapper_wayland_client)(struct wl_proxy*, uint32_t,union wl_argument,const struct wl_interface*, uint32_t); +void (*wl_proxy_destroy_dylibloader_wrapper_wayland_client)(struct wl_proxy*); +int (*wl_proxy_add_listener_dylibloader_wrapper_wayland_client)(struct wl_proxy*, void(**)(void), void*); +const void* (*wl_proxy_get_listener_dylibloader_wrapper_wayland_client)(struct wl_proxy*); +int (*wl_proxy_add_dispatcher_dylibloader_wrapper_wayland_client)(struct wl_proxy*, wl_dispatcher_func_t,const void*, void*); +void (*wl_proxy_set_user_data_dylibloader_wrapper_wayland_client)(struct wl_proxy*, void*); +void* (*wl_proxy_get_user_data_dylibloader_wrapper_wayland_client)(struct wl_proxy*); +uint32_t (*wl_proxy_get_version_dylibloader_wrapper_wayland_client)(struct wl_proxy*); +uint32_t (*wl_proxy_get_id_dylibloader_wrapper_wayland_client)(struct wl_proxy*); +void (*wl_proxy_set_tag_dylibloader_wrapper_wayland_client)(struct wl_proxy*,const char**); +const char** (*wl_proxy_get_tag_dylibloader_wrapper_wayland_client)(struct wl_proxy*); +const char* (*wl_proxy_get_class_dylibloader_wrapper_wayland_client)(struct wl_proxy*); +void (*wl_proxy_set_queue_dylibloader_wrapper_wayland_client)(struct wl_proxy*,struct wl_event_queue*); +struct wl_display* (*wl_display_connect_dylibloader_wrapper_wayland_client)(const char*); +struct wl_display* (*wl_display_connect_to_fd_dylibloader_wrapper_wayland_client)( int); +void (*wl_display_disconnect_dylibloader_wrapper_wayland_client)(struct wl_display*); +int (*wl_display_get_fd_dylibloader_wrapper_wayland_client)(struct wl_display*); +int (*wl_display_dispatch_dylibloader_wrapper_wayland_client)(struct wl_display*); +int (*wl_display_dispatch_queue_dylibloader_wrapper_wayland_client)(struct wl_display*,struct wl_event_queue*); +int (*wl_display_dispatch_queue_pending_dylibloader_wrapper_wayland_client)(struct wl_display*,struct wl_event_queue*); +int (*wl_display_dispatch_pending_dylibloader_wrapper_wayland_client)(struct wl_display*); +int (*wl_display_get_error_dylibloader_wrapper_wayland_client)(struct wl_display*); +uint32_t (*wl_display_get_protocol_error_dylibloader_wrapper_wayland_client)(struct wl_display*,const struct wl_interface**, uint32_t*); +int (*wl_display_flush_dylibloader_wrapper_wayland_client)(struct wl_display*); +int (*wl_display_roundtrip_queue_dylibloader_wrapper_wayland_client)(struct wl_display*,struct wl_event_queue*); +int (*wl_display_roundtrip_dylibloader_wrapper_wayland_client)(struct wl_display*); +struct wl_event_queue* (*wl_display_create_queue_dylibloader_wrapper_wayland_client)(struct wl_display*); +int (*wl_display_prepare_read_queue_dylibloader_wrapper_wayland_client)(struct wl_display*,struct wl_event_queue*); +int (*wl_display_prepare_read_dylibloader_wrapper_wayland_client)(struct wl_display*); +void (*wl_display_cancel_read_dylibloader_wrapper_wayland_client)(struct wl_display*); +int (*wl_display_read_events_dylibloader_wrapper_wayland_client)(struct wl_display*); +void (*wl_log_set_handler_client_dylibloader_wrapper_wayland_client)( wl_log_func_t); +int initialize_wayland_client(int verbose) { + void *handle; + char *error; + handle = dlopen("libwayland-client.so.0", RTLD_LAZY); + if (!handle) { + if (verbose) { + fprintf(stderr, "%s\n", dlerror()); + } + return(1); + } + dlerror(); +// wl_list_init + *(void **) (&wl_list_init_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_list_init"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_list_insert + *(void **) (&wl_list_insert_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_list_insert"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_list_remove + *(void **) (&wl_list_remove_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_list_remove"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_list_length + *(void **) (&wl_list_length_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_list_length"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_list_empty + *(void **) (&wl_list_empty_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_list_empty"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_list_insert_list + *(void **) (&wl_list_insert_list_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_list_insert_list"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_array_init + *(void **) (&wl_array_init_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_array_init"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_array_release + *(void **) (&wl_array_release_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_array_release"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_array_add + *(void **) (&wl_array_add_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_array_add"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_array_copy + *(void **) (&wl_array_copy_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_array_copy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_event_queue_destroy + *(void **) (&wl_event_queue_destroy_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_event_queue_destroy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_marshal_flags + *(void **) (&wl_proxy_marshal_flags_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_marshal_flags"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_marshal_array_flags + *(void **) (&wl_proxy_marshal_array_flags_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_marshal_array_flags"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_marshal + *(void **) (&wl_proxy_marshal_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_marshal"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_marshal_array + *(void **) (&wl_proxy_marshal_array_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_marshal_array"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_create + *(void **) (&wl_proxy_create_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_create"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_create_wrapper + *(void **) (&wl_proxy_create_wrapper_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_create_wrapper"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_wrapper_destroy + *(void **) (&wl_proxy_wrapper_destroy_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_wrapper_destroy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_marshal_constructor + *(void **) (&wl_proxy_marshal_constructor_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_marshal_constructor"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_marshal_constructor_versioned + *(void **) (&wl_proxy_marshal_constructor_versioned_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_marshal_constructor_versioned"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_marshal_array_constructor + *(void **) (&wl_proxy_marshal_array_constructor_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_marshal_array_constructor"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_marshal_array_constructor_versioned + *(void **) (&wl_proxy_marshal_array_constructor_versioned_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_marshal_array_constructor_versioned"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_destroy + *(void **) (&wl_proxy_destroy_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_destroy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_add_listener + *(void **) (&wl_proxy_add_listener_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_add_listener"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_get_listener + *(void **) (&wl_proxy_get_listener_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_get_listener"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_add_dispatcher + *(void **) (&wl_proxy_add_dispatcher_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_add_dispatcher"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_set_user_data + *(void **) (&wl_proxy_set_user_data_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_set_user_data"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_get_user_data + *(void **) (&wl_proxy_get_user_data_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_get_user_data"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_get_version + *(void **) (&wl_proxy_get_version_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_get_version"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_get_id + *(void **) (&wl_proxy_get_id_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_get_id"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_set_tag + *(void **) (&wl_proxy_set_tag_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_set_tag"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_get_tag + *(void **) (&wl_proxy_get_tag_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_get_tag"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_get_class + *(void **) (&wl_proxy_get_class_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_get_class"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_proxy_set_queue + *(void **) (&wl_proxy_set_queue_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_proxy_set_queue"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_display_connect + *(void **) (&wl_display_connect_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_display_connect"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_display_connect_to_fd + *(void **) (&wl_display_connect_to_fd_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_display_connect_to_fd"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_display_disconnect + *(void **) (&wl_display_disconnect_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_display_disconnect"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_display_get_fd + *(void **) (&wl_display_get_fd_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_display_get_fd"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_display_dispatch + *(void **) (&wl_display_dispatch_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_display_dispatch"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_display_dispatch_queue + *(void **) (&wl_display_dispatch_queue_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_display_dispatch_queue"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_display_dispatch_queue_pending + *(void **) (&wl_display_dispatch_queue_pending_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_display_dispatch_queue_pending"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_display_dispatch_pending + *(void **) (&wl_display_dispatch_pending_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_display_dispatch_pending"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_display_get_error + *(void **) (&wl_display_get_error_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_display_get_error"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_display_get_protocol_error + *(void **) (&wl_display_get_protocol_error_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_display_get_protocol_error"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_display_flush + *(void **) (&wl_display_flush_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_display_flush"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_display_roundtrip_queue + *(void **) (&wl_display_roundtrip_queue_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_display_roundtrip_queue"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_display_roundtrip + *(void **) (&wl_display_roundtrip_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_display_roundtrip"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_display_create_queue + *(void **) (&wl_display_create_queue_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_display_create_queue"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_display_prepare_read_queue + *(void **) (&wl_display_prepare_read_queue_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_display_prepare_read_queue"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_display_prepare_read + *(void **) (&wl_display_prepare_read_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_display_prepare_read"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_display_cancel_read + *(void **) (&wl_display_cancel_read_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_display_cancel_read"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_display_read_events + *(void **) (&wl_display_read_events_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_display_read_events"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_log_set_handler_client + *(void **) (&wl_log_set_handler_client_dylibloader_wrapper_wayland_client) = dlsym(handle, "wl_log_set_handler_client"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +return 0; +} diff --git a/platform/linuxbsd/wayland/dynwrappers/wayland-client-core-so_wrap.h b/platform/linuxbsd/wayland/dynwrappers/wayland-client-core-so_wrap.h new file mode 100644 index 00000000000..86c51573a54 --- /dev/null +++ b/platform/linuxbsd/wayland/dynwrappers/wayland-client-core-so_wrap.h @@ -0,0 +1,231 @@ +#ifndef DYLIBLOAD_WRAPPER_WAYLAND_CLIENT +#define DYLIBLOAD_WRAPPER_WAYLAND_CLIENT +// This file is generated. Do not edit! +// see https://github.com/hpvb/dynload-wrapper for details +// generated by ../dynload-wrapper/generate-wrapper.py 0.3 on 2023-01-25 17:36:12 +// flags: ../dynload-wrapper/generate-wrapper.py --include ./thirdparty/linuxbsd_headers/wayland/wayland-client-core.h --sys-include "./thirdparty/linuxbsd_headers/wayland/wayland-client-core.h" --soname libwayland-client.so.0 --init-name wayland_client --output-header platform/linuxbsd/wayland/dynwrappers/wayland-client-core-so_wrap.h --output-implementation platform/linuxbsd/wayland/dynwrappers/wayland-client-core-so_wrap.c +// +// NOTE: This has been hand-patched to workaround some issues. +#include + +#define wl_list_init wl_list_init_dylibloader_orig_wayland_client +#define wl_list_insert wl_list_insert_dylibloader_orig_wayland_client +#define wl_list_remove wl_list_remove_dylibloader_orig_wayland_client +#define wl_list_length wl_list_length_dylibloader_orig_wayland_client +#define wl_list_empty wl_list_empty_dylibloader_orig_wayland_client +#define wl_list_insert_list wl_list_insert_list_dylibloader_orig_wayland_client +#define wl_array_init wl_array_init_dylibloader_orig_wayland_client +#define wl_array_release wl_array_release_dylibloader_orig_wayland_client +#define wl_array_add wl_array_add_dylibloader_orig_wayland_client +#define wl_array_copy wl_array_copy_dylibloader_orig_wayland_client +#define wl_event_queue_destroy wl_event_queue_destroy_dylibloader_orig_wayland_client +#define wl_proxy_marshal_flags wl_proxy_marshal_flags_dylibloader_orig_wayland_client +#define wl_proxy_marshal_array_flags wl_proxy_marshal_array_flags_dylibloader_orig_wayland_client +#define wl_proxy_marshal wl_proxy_marshal_dylibloader_orig_wayland_client +#define wl_proxy_marshal_array wl_proxy_marshal_array_dylibloader_orig_wayland_client +#define wl_proxy_create wl_proxy_create_dylibloader_orig_wayland_client +#define wl_proxy_create_wrapper wl_proxy_create_wrapper_dylibloader_orig_wayland_client +#define wl_proxy_wrapper_destroy wl_proxy_wrapper_destroy_dylibloader_orig_wayland_client +#define wl_proxy_marshal_constructor wl_proxy_marshal_constructor_dylibloader_orig_wayland_client +#define wl_proxy_marshal_constructor_versioned wl_proxy_marshal_constructor_versioned_dylibloader_orig_wayland_client +#define wl_proxy_marshal_array_constructor wl_proxy_marshal_array_constructor_dylibloader_orig_wayland_client +#define wl_proxy_marshal_array_constructor_versioned wl_proxy_marshal_array_constructor_versioned_dylibloader_orig_wayland_client +#define wl_proxy_destroy wl_proxy_destroy_dylibloader_orig_wayland_client +#define wl_proxy_add_listener wl_proxy_add_listener_dylibloader_orig_wayland_client +#define wl_proxy_get_listener wl_proxy_get_listener_dylibloader_orig_wayland_client +#define wl_proxy_add_dispatcher wl_proxy_add_dispatcher_dylibloader_orig_wayland_client +#define wl_proxy_set_user_data wl_proxy_set_user_data_dylibloader_orig_wayland_client +#define wl_proxy_get_user_data wl_proxy_get_user_data_dylibloader_orig_wayland_client +#define wl_proxy_get_version wl_proxy_get_version_dylibloader_orig_wayland_client +#define wl_proxy_get_id wl_proxy_get_id_dylibloader_orig_wayland_client +#define wl_proxy_set_tag wl_proxy_set_tag_dylibloader_orig_wayland_client +#define wl_proxy_get_tag wl_proxy_get_tag_dylibloader_orig_wayland_client +#define wl_proxy_get_class wl_proxy_get_class_dylibloader_orig_wayland_client +#define wl_proxy_set_queue wl_proxy_set_queue_dylibloader_orig_wayland_client +#define wl_display_connect wl_display_connect_dylibloader_orig_wayland_client +#define wl_display_connect_to_fd wl_display_connect_to_fd_dylibloader_orig_wayland_client +#define wl_display_disconnect wl_display_disconnect_dylibloader_orig_wayland_client +#define wl_display_get_fd wl_display_get_fd_dylibloader_orig_wayland_client +#define wl_display_dispatch wl_display_dispatch_dylibloader_orig_wayland_client +#define wl_display_dispatch_queue wl_display_dispatch_queue_dylibloader_orig_wayland_client +#define wl_display_dispatch_queue_pending wl_display_dispatch_queue_pending_dylibloader_orig_wayland_client +#define wl_display_dispatch_pending wl_display_dispatch_pending_dylibloader_orig_wayland_client +#define wl_display_get_error wl_display_get_error_dylibloader_orig_wayland_client +#define wl_display_get_protocol_error wl_display_get_protocol_error_dylibloader_orig_wayland_client +#define wl_display_flush wl_display_flush_dylibloader_orig_wayland_client +#define wl_display_roundtrip_queue wl_display_roundtrip_queue_dylibloader_orig_wayland_client +#define wl_display_roundtrip wl_display_roundtrip_dylibloader_orig_wayland_client +#define wl_display_create_queue wl_display_create_queue_dylibloader_orig_wayland_client +#define wl_display_prepare_read_queue wl_display_prepare_read_queue_dylibloader_orig_wayland_client +#define wl_display_prepare_read wl_display_prepare_read_dylibloader_orig_wayland_client +#define wl_display_cancel_read wl_display_cancel_read_dylibloader_orig_wayland_client +#define wl_display_read_events wl_display_read_events_dylibloader_orig_wayland_client +#define wl_log_set_handler_client wl_log_set_handler_client_dylibloader_orig_wayland_client +#include "./thirdparty/linuxbsd_headers/wayland/wayland-client-core.h" +#undef wl_list_init +#undef wl_list_insert +#undef wl_list_remove +#undef wl_list_length +#undef wl_list_empty +#undef wl_list_insert_list +#undef wl_array_init +#undef wl_array_release +#undef wl_array_add +#undef wl_array_copy +#undef wl_event_queue_destroy +#undef wl_proxy_marshal_flags +#undef wl_proxy_marshal_array_flags +#undef wl_proxy_marshal +#undef wl_proxy_marshal_array +#undef wl_proxy_create +#undef wl_proxy_create_wrapper +#undef wl_proxy_wrapper_destroy +#undef wl_proxy_marshal_constructor +#undef wl_proxy_marshal_constructor_versioned +#undef wl_proxy_marshal_array_constructor +#undef wl_proxy_marshal_array_constructor_versioned +#undef wl_proxy_destroy +#undef wl_proxy_add_listener +#undef wl_proxy_get_listener +#undef wl_proxy_add_dispatcher +#undef wl_proxy_set_user_data +#undef wl_proxy_get_user_data +#undef wl_proxy_get_version +#undef wl_proxy_get_id +#undef wl_proxy_set_tag +#undef wl_proxy_get_tag +#undef wl_proxy_get_class +#undef wl_proxy_set_queue +#undef wl_display_connect +#undef wl_display_connect_to_fd +#undef wl_display_disconnect +#undef wl_display_get_fd +#undef wl_display_dispatch +#undef wl_display_dispatch_queue +#undef wl_display_dispatch_queue_pending +#undef wl_display_dispatch_pending +#undef wl_display_get_error +#undef wl_display_get_protocol_error +#undef wl_display_flush +#undef wl_display_roundtrip_queue +#undef wl_display_roundtrip +#undef wl_display_create_queue +#undef wl_display_prepare_read_queue +#undef wl_display_prepare_read +#undef wl_display_cancel_read +#undef wl_display_read_events +#undef wl_log_set_handler_client +#ifdef __cplusplus +extern "C" { +#endif +#define wl_list_init wl_list_init_dylibloader_wrapper_wayland_client +#define wl_list_insert wl_list_insert_dylibloader_wrapper_wayland_client +#define wl_list_remove wl_list_remove_dylibloader_wrapper_wayland_client +#define wl_list_length wl_list_length_dylibloader_wrapper_wayland_client +#define wl_list_empty wl_list_empty_dylibloader_wrapper_wayland_client +#define wl_list_insert_list wl_list_insert_list_dylibloader_wrapper_wayland_client +#define wl_array_init wl_array_init_dylibloader_wrapper_wayland_client +#define wl_array_release wl_array_release_dylibloader_wrapper_wayland_client +#define wl_array_add wl_array_add_dylibloader_wrapper_wayland_client +#define wl_array_copy wl_array_copy_dylibloader_wrapper_wayland_client +#define wl_event_queue_destroy wl_event_queue_destroy_dylibloader_wrapper_wayland_client +#define wl_proxy_marshal_flags wl_proxy_marshal_flags_dylibloader_wrapper_wayland_client +#define wl_proxy_marshal_array_flags wl_proxy_marshal_array_flags_dylibloader_wrapper_wayland_client +#define wl_proxy_marshal wl_proxy_marshal_dylibloader_wrapper_wayland_client +#define wl_proxy_marshal_array wl_proxy_marshal_array_dylibloader_wrapper_wayland_client +#define wl_proxy_create wl_proxy_create_dylibloader_wrapper_wayland_client +#define wl_proxy_create_wrapper wl_proxy_create_wrapper_dylibloader_wrapper_wayland_client +#define wl_proxy_wrapper_destroy wl_proxy_wrapper_destroy_dylibloader_wrapper_wayland_client +#define wl_proxy_marshal_constructor wl_proxy_marshal_constructor_dylibloader_wrapper_wayland_client +#define wl_proxy_marshal_constructor_versioned wl_proxy_marshal_constructor_versioned_dylibloader_wrapper_wayland_client +#define wl_proxy_marshal_array_constructor wl_proxy_marshal_array_constructor_dylibloader_wrapper_wayland_client +#define wl_proxy_marshal_array_constructor_versioned wl_proxy_marshal_array_constructor_versioned_dylibloader_wrapper_wayland_client +#define wl_proxy_destroy wl_proxy_destroy_dylibloader_wrapper_wayland_client +#define wl_proxy_add_listener wl_proxy_add_listener_dylibloader_wrapper_wayland_client +#define wl_proxy_get_listener wl_proxy_get_listener_dylibloader_wrapper_wayland_client +#define wl_proxy_add_dispatcher wl_proxy_add_dispatcher_dylibloader_wrapper_wayland_client +#define wl_proxy_set_user_data wl_proxy_set_user_data_dylibloader_wrapper_wayland_client +#define wl_proxy_get_user_data wl_proxy_get_user_data_dylibloader_wrapper_wayland_client +#define wl_proxy_get_version wl_proxy_get_version_dylibloader_wrapper_wayland_client +#define wl_proxy_get_id wl_proxy_get_id_dylibloader_wrapper_wayland_client +#define wl_proxy_set_tag wl_proxy_set_tag_dylibloader_wrapper_wayland_client +#define wl_proxy_get_tag wl_proxy_get_tag_dylibloader_wrapper_wayland_client +#define wl_proxy_get_class wl_proxy_get_class_dylibloader_wrapper_wayland_client +#define wl_proxy_set_queue wl_proxy_set_queue_dylibloader_wrapper_wayland_client +#define wl_display_connect wl_display_connect_dylibloader_wrapper_wayland_client +#define wl_display_connect_to_fd wl_display_connect_to_fd_dylibloader_wrapper_wayland_client +#define wl_display_disconnect wl_display_disconnect_dylibloader_wrapper_wayland_client +#define wl_display_get_fd wl_display_get_fd_dylibloader_wrapper_wayland_client +#define wl_display_dispatch wl_display_dispatch_dylibloader_wrapper_wayland_client +#define wl_display_dispatch_queue wl_display_dispatch_queue_dylibloader_wrapper_wayland_client +#define wl_display_dispatch_queue_pending wl_display_dispatch_queue_pending_dylibloader_wrapper_wayland_client +#define wl_display_dispatch_pending wl_display_dispatch_pending_dylibloader_wrapper_wayland_client +#define wl_display_get_error wl_display_get_error_dylibloader_wrapper_wayland_client +#define wl_display_get_protocol_error wl_display_get_protocol_error_dylibloader_wrapper_wayland_client +#define wl_display_flush wl_display_flush_dylibloader_wrapper_wayland_client +#define wl_display_roundtrip_queue wl_display_roundtrip_queue_dylibloader_wrapper_wayland_client +#define wl_display_roundtrip wl_display_roundtrip_dylibloader_wrapper_wayland_client +#define wl_display_create_queue wl_display_create_queue_dylibloader_wrapper_wayland_client +#define wl_display_prepare_read_queue wl_display_prepare_read_queue_dylibloader_wrapper_wayland_client +#define wl_display_prepare_read wl_display_prepare_read_dylibloader_wrapper_wayland_client +#define wl_display_cancel_read wl_display_cancel_read_dylibloader_wrapper_wayland_client +#define wl_display_read_events wl_display_read_events_dylibloader_wrapper_wayland_client +#define wl_log_set_handler_client wl_log_set_handler_client_dylibloader_wrapper_wayland_client +extern void (*wl_list_init_dylibloader_wrapper_wayland_client)(struct wl_list*); +extern void (*wl_list_insert_dylibloader_wrapper_wayland_client)(struct wl_list*,struct wl_list*); +extern void (*wl_list_remove_dylibloader_wrapper_wayland_client)(struct wl_list*); +extern int (*wl_list_length_dylibloader_wrapper_wayland_client)(struct wl_list*); +extern int (*wl_list_empty_dylibloader_wrapper_wayland_client)(struct wl_list*); +extern void (*wl_list_insert_list_dylibloader_wrapper_wayland_client)(struct wl_list*,struct wl_list*); +extern void (*wl_array_init_dylibloader_wrapper_wayland_client)(struct wl_array*); +extern void (*wl_array_release_dylibloader_wrapper_wayland_client)(struct wl_array*); +extern void* (*wl_array_add_dylibloader_wrapper_wayland_client)(struct wl_array*, size_t); +extern int (*wl_array_copy_dylibloader_wrapper_wayland_client)(struct wl_array*,struct wl_array*); +extern void (*wl_event_queue_destroy_dylibloader_wrapper_wayland_client)(struct wl_event_queue*); +extern struct wl_proxy* (*wl_proxy_marshal_flags_dylibloader_wrapper_wayland_client)(struct wl_proxy*, uint32_t,const struct wl_interface*, uint32_t, uint32_t,...); +extern struct wl_proxy* (*wl_proxy_marshal_array_flags_dylibloader_wrapper_wayland_client)(struct wl_proxy*, uint32_t,const struct wl_interface*, uint32_t, uint32_t,union wl_argument); +extern void (*wl_proxy_marshal_dylibloader_wrapper_wayland_client)(struct wl_proxy*, uint32_t,...); +extern void (*wl_proxy_marshal_array_dylibloader_wrapper_wayland_client)(struct wl_proxy*, uint32_t,union wl_argument); +extern struct wl_proxy* (*wl_proxy_create_dylibloader_wrapper_wayland_client)(struct wl_proxy*,const struct wl_interface*); +extern void* (*wl_proxy_create_wrapper_dylibloader_wrapper_wayland_client)( void*); +extern void (*wl_proxy_wrapper_destroy_dylibloader_wrapper_wayland_client)( void*); +extern struct wl_proxy* (*wl_proxy_marshal_constructor_dylibloader_wrapper_wayland_client)(struct wl_proxy*, uint32_t,const struct wl_interface*,...); +extern struct wl_proxy* (*wl_proxy_marshal_constructor_versioned_dylibloader_wrapper_wayland_client)(struct wl_proxy*, uint32_t,const struct wl_interface*, uint32_t,...); +extern struct wl_proxy* (*wl_proxy_marshal_array_constructor_dylibloader_wrapper_wayland_client)(struct wl_proxy*, uint32_t,union wl_argument,const struct wl_interface*); +extern struct wl_proxy* (*wl_proxy_marshal_array_constructor_versioned_dylibloader_wrapper_wayland_client)(struct wl_proxy*, uint32_t,union wl_argument,const struct wl_interface*, uint32_t); +extern void (*wl_proxy_destroy_dylibloader_wrapper_wayland_client)(struct wl_proxy*); +extern int (*wl_proxy_add_listener_dylibloader_wrapper_wayland_client)(struct wl_proxy*, void(**)(void), void*); +extern const void* (*wl_proxy_get_listener_dylibloader_wrapper_wayland_client)(struct wl_proxy*); +extern int (*wl_proxy_add_dispatcher_dylibloader_wrapper_wayland_client)(struct wl_proxy*, wl_dispatcher_func_t,const void*, void*); +extern void (*wl_proxy_set_user_data_dylibloader_wrapper_wayland_client)(struct wl_proxy*, void*); +extern void* (*wl_proxy_get_user_data_dylibloader_wrapper_wayland_client)(struct wl_proxy*); +extern uint32_t (*wl_proxy_get_version_dylibloader_wrapper_wayland_client)(struct wl_proxy*); +extern uint32_t (*wl_proxy_get_id_dylibloader_wrapper_wayland_client)(struct wl_proxy*); +extern void (*wl_proxy_set_tag_dylibloader_wrapper_wayland_client)(struct wl_proxy*,const char**); +extern const char** (*wl_proxy_get_tag_dylibloader_wrapper_wayland_client)(struct wl_proxy*); +extern const char* (*wl_proxy_get_class_dylibloader_wrapper_wayland_client)(struct wl_proxy*); +extern void (*wl_proxy_set_queue_dylibloader_wrapper_wayland_client)(struct wl_proxy*,struct wl_event_queue*); +extern struct wl_display* (*wl_display_connect_dylibloader_wrapper_wayland_client)(const char*); +extern struct wl_display* (*wl_display_connect_to_fd_dylibloader_wrapper_wayland_client)( int); +extern void (*wl_display_disconnect_dylibloader_wrapper_wayland_client)(struct wl_display*); +extern int (*wl_display_get_fd_dylibloader_wrapper_wayland_client)(struct wl_display*); +extern int (*wl_display_dispatch_dylibloader_wrapper_wayland_client)(struct wl_display*); +extern int (*wl_display_dispatch_queue_dylibloader_wrapper_wayland_client)(struct wl_display*,struct wl_event_queue*); +extern int (*wl_display_dispatch_queue_pending_dylibloader_wrapper_wayland_client)(struct wl_display*,struct wl_event_queue*); +extern int (*wl_display_dispatch_pending_dylibloader_wrapper_wayland_client)(struct wl_display*); +extern int (*wl_display_get_error_dylibloader_wrapper_wayland_client)(struct wl_display*); +extern uint32_t (*wl_display_get_protocol_error_dylibloader_wrapper_wayland_client)(struct wl_display*,const struct wl_interface**, uint32_t*); +extern int (*wl_display_flush_dylibloader_wrapper_wayland_client)(struct wl_display*); +extern int (*wl_display_roundtrip_queue_dylibloader_wrapper_wayland_client)(struct wl_display*,struct wl_event_queue*); +extern int (*wl_display_roundtrip_dylibloader_wrapper_wayland_client)(struct wl_display*); +extern struct wl_event_queue* (*wl_display_create_queue_dylibloader_wrapper_wayland_client)(struct wl_display*); +extern int (*wl_display_prepare_read_queue_dylibloader_wrapper_wayland_client)(struct wl_display*,struct wl_event_queue*); +extern int (*wl_display_prepare_read_dylibloader_wrapper_wayland_client)(struct wl_display*); +extern void (*wl_display_cancel_read_dylibloader_wrapper_wayland_client)(struct wl_display*); +extern int (*wl_display_read_events_dylibloader_wrapper_wayland_client)(struct wl_display*); +extern void (*wl_log_set_handler_client_dylibloader_wrapper_wayland_client)( wl_log_func_t); +int initialize_wayland_client(int verbose); +#ifdef __cplusplus +} +#endif +#endif diff --git a/platform/linuxbsd/wayland/dynwrappers/wayland-cursor-so_wrap.c b/platform/linuxbsd/wayland/dynwrappers/wayland-cursor-so_wrap.c new file mode 100644 index 00000000000..61ccfbf4f91 --- /dev/null +++ b/platform/linuxbsd/wayland/dynwrappers/wayland-cursor-so_wrap.c @@ -0,0 +1,89 @@ +// This file is generated. Do not edit! +// see https://github.com/hpvb/dynload-wrapper for details +// generated by ../dynload-wrapper/generate-wrapper.py 0.3 on 2023-01-25 17:46:12 +// flags: ../dynload-wrapper/generate-wrapper.py --include ./thirdparty/linuxbsd_headers/wayland/wayland-cursor.h --sys-include "./thirdparty/linuxbsd_headers/wayland/wayland-cursor.h" --soname libwayland-cursor.so.0 --init-name wayland_cursor --output-header platform/linuxbsd/wayland/dynwrappers/wayland-cursor-so_wrap.h --output-implementation platform/linuxbsd/wayland/dynwrappers/wayland-cursor-so_wrap.c +// +#include + +#define wl_cursor_theme_load wl_cursor_theme_load_dylibloader_orig_wayland_cursor +#define wl_cursor_theme_destroy wl_cursor_theme_destroy_dylibloader_orig_wayland_cursor +#define wl_cursor_theme_get_cursor wl_cursor_theme_get_cursor_dylibloader_orig_wayland_cursor +#define wl_cursor_image_get_buffer wl_cursor_image_get_buffer_dylibloader_orig_wayland_cursor +#define wl_cursor_frame wl_cursor_frame_dylibloader_orig_wayland_cursor +#define wl_cursor_frame_and_duration wl_cursor_frame_and_duration_dylibloader_orig_wayland_cursor +#include "./thirdparty/linuxbsd_headers/wayland/wayland-cursor.h" +#undef wl_cursor_theme_load +#undef wl_cursor_theme_destroy +#undef wl_cursor_theme_get_cursor +#undef wl_cursor_image_get_buffer +#undef wl_cursor_frame +#undef wl_cursor_frame_and_duration +#include +#include +struct wl_cursor_theme* (*wl_cursor_theme_load_dylibloader_wrapper_wayland_cursor)(const char*, int,struct wl_shm*); +void (*wl_cursor_theme_destroy_dylibloader_wrapper_wayland_cursor)(struct wl_cursor_theme*); +struct wl_cursor* (*wl_cursor_theme_get_cursor_dylibloader_wrapper_wayland_cursor)(struct wl_cursor_theme*,const char*); +struct wl_buffer* (*wl_cursor_image_get_buffer_dylibloader_wrapper_wayland_cursor)(struct wl_cursor_image*); +int (*wl_cursor_frame_dylibloader_wrapper_wayland_cursor)(struct wl_cursor*, uint32_t); +int (*wl_cursor_frame_and_duration_dylibloader_wrapper_wayland_cursor)(struct wl_cursor*, uint32_t, uint32_t*); +int initialize_wayland_cursor(int verbose) { + void *handle; + char *error; + handle = dlopen("libwayland-cursor.so.0", RTLD_LAZY); + if (!handle) { + if (verbose) { + fprintf(stderr, "%s\n", dlerror()); + } + return(1); + } + dlerror(); +// wl_cursor_theme_load + *(void **) (&wl_cursor_theme_load_dylibloader_wrapper_wayland_cursor) = dlsym(handle, "wl_cursor_theme_load"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_cursor_theme_destroy + *(void **) (&wl_cursor_theme_destroy_dylibloader_wrapper_wayland_cursor) = dlsym(handle, "wl_cursor_theme_destroy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_cursor_theme_get_cursor + *(void **) (&wl_cursor_theme_get_cursor_dylibloader_wrapper_wayland_cursor) = dlsym(handle, "wl_cursor_theme_get_cursor"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_cursor_image_get_buffer + *(void **) (&wl_cursor_image_get_buffer_dylibloader_wrapper_wayland_cursor) = dlsym(handle, "wl_cursor_image_get_buffer"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_cursor_frame + *(void **) (&wl_cursor_frame_dylibloader_wrapper_wayland_cursor) = dlsym(handle, "wl_cursor_frame"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_cursor_frame_and_duration + *(void **) (&wl_cursor_frame_and_duration_dylibloader_wrapper_wayland_cursor) = dlsym(handle, "wl_cursor_frame_and_duration"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +return 0; +} diff --git a/platform/linuxbsd/wayland/dynwrappers/wayland-cursor-so_wrap.h b/platform/linuxbsd/wayland/dynwrappers/wayland-cursor-so_wrap.h new file mode 100644 index 00000000000..43520e74a16 --- /dev/null +++ b/platform/linuxbsd/wayland/dynwrappers/wayland-cursor-so_wrap.h @@ -0,0 +1,42 @@ +#ifndef DYLIBLOAD_WRAPPER_WAYLAND_CURSOR +#define DYLIBLOAD_WRAPPER_WAYLAND_CURSOR +// This file is generated. Do not edit! +// see https://github.com/hpvb/dynload-wrapper for details +// generated by ../dynload-wrapper/generate-wrapper.py 0.3 on 2023-01-25 17:46:12 +// flags: ../dynload-wrapper/generate-wrapper.py --include ./thirdparty/linuxbsd_headers/wayland/wayland-cursor.h --sys-include "./thirdparty/linuxbsd_headers/wayland/wayland-cursor.h" --soname libwayland-cursor.so.0 --init-name wayland_cursor --output-header platform/linuxbsd/wayland/dynwrappers/wayland-cursor-so_wrap.h --output-implementation platform/linuxbsd/wayland/dynwrappers/wayland-cursor-so_wrap.c +// +#include + +#define wl_cursor_theme_load wl_cursor_theme_load_dylibloader_orig_wayland_cursor +#define wl_cursor_theme_destroy wl_cursor_theme_destroy_dylibloader_orig_wayland_cursor +#define wl_cursor_theme_get_cursor wl_cursor_theme_get_cursor_dylibloader_orig_wayland_cursor +#define wl_cursor_image_get_buffer wl_cursor_image_get_buffer_dylibloader_orig_wayland_cursor +#define wl_cursor_frame wl_cursor_frame_dylibloader_orig_wayland_cursor +#define wl_cursor_frame_and_duration wl_cursor_frame_and_duration_dylibloader_orig_wayland_cursor +#include "./thirdparty/linuxbsd_headers/wayland/wayland-cursor.h" +#undef wl_cursor_theme_load +#undef wl_cursor_theme_destroy +#undef wl_cursor_theme_get_cursor +#undef wl_cursor_image_get_buffer +#undef wl_cursor_frame +#undef wl_cursor_frame_and_duration +#ifdef __cplusplus +extern "C" { +#endif +#define wl_cursor_theme_load wl_cursor_theme_load_dylibloader_wrapper_wayland_cursor +#define wl_cursor_theme_destroy wl_cursor_theme_destroy_dylibloader_wrapper_wayland_cursor +#define wl_cursor_theme_get_cursor wl_cursor_theme_get_cursor_dylibloader_wrapper_wayland_cursor +#define wl_cursor_image_get_buffer wl_cursor_image_get_buffer_dylibloader_wrapper_wayland_cursor +#define wl_cursor_frame wl_cursor_frame_dylibloader_wrapper_wayland_cursor +#define wl_cursor_frame_and_duration wl_cursor_frame_and_duration_dylibloader_wrapper_wayland_cursor +extern struct wl_cursor_theme* (*wl_cursor_theme_load_dylibloader_wrapper_wayland_cursor)(const char*, int,struct wl_shm*); +extern void (*wl_cursor_theme_destroy_dylibloader_wrapper_wayland_cursor)(struct wl_cursor_theme*); +extern struct wl_cursor* (*wl_cursor_theme_get_cursor_dylibloader_wrapper_wayland_cursor)(struct wl_cursor_theme*,const char*); +extern struct wl_buffer* (*wl_cursor_image_get_buffer_dylibloader_wrapper_wayland_cursor)(struct wl_cursor_image*); +extern int (*wl_cursor_frame_dylibloader_wrapper_wayland_cursor)(struct wl_cursor*, uint32_t); +extern int (*wl_cursor_frame_and_duration_dylibloader_wrapper_wayland_cursor)(struct wl_cursor*, uint32_t, uint32_t*); +int initialize_wayland_cursor(int verbose); +#ifdef __cplusplus +} +#endif +#endif diff --git a/platform/linuxbsd/wayland/dynwrappers/wayland-egl-core-so_wrap.c b/platform/linuxbsd/wayland/dynwrappers/wayland-egl-core-so_wrap.c new file mode 100644 index 00000000000..122241d2414 --- /dev/null +++ b/platform/linuxbsd/wayland/dynwrappers/wayland-egl-core-so_wrap.c @@ -0,0 +1,67 @@ +// This file is generated. Do not edit! +// see https://github.com/hpvb/dynload-wrapper for details +// generated by ../dynload-wrapper/generate-wrapper.py 0.3 on 2023-01-25 17:49:37 +// flags: ../dynload-wrapper/generate-wrapper.py --include ./thirdparty/linuxbsd_headers/wayland/wayland-egl-core.h --sys-include "./thirdparty/linuxbsd_headers/wayland/wayland-egl-core.h" --soname libwayland-egl.so.1 --init-name wayland_egl --output-header platform/linuxbsd/wayland/dynwrappers/wayland-egl-core-so_wrap.h --output-implementation platform/linuxbsd/wayland/dynwrappers/wayland-egl-core-so_wrap.c +// +#include + +#define wl_egl_window_create wl_egl_window_create_dylibloader_orig_wayland_egl +#define wl_egl_window_destroy wl_egl_window_destroy_dylibloader_orig_wayland_egl +#define wl_egl_window_resize wl_egl_window_resize_dylibloader_orig_wayland_egl +#define wl_egl_window_get_attached_size wl_egl_window_get_attached_size_dylibloader_orig_wayland_egl +#include "./thirdparty/linuxbsd_headers/wayland/wayland-egl-core.h" +#undef wl_egl_window_create +#undef wl_egl_window_destroy +#undef wl_egl_window_resize +#undef wl_egl_window_get_attached_size +#include +#include +struct wl_egl_window* (*wl_egl_window_create_dylibloader_wrapper_wayland_egl)(struct wl_surface*, int, int); +void (*wl_egl_window_destroy_dylibloader_wrapper_wayland_egl)(struct wl_egl_window*); +void (*wl_egl_window_resize_dylibloader_wrapper_wayland_egl)(struct wl_egl_window*, int, int, int, int); +void (*wl_egl_window_get_attached_size_dylibloader_wrapper_wayland_egl)(struct wl_egl_window*, int*, int*); +int initialize_wayland_egl(int verbose) { + void *handle; + char *error; + handle = dlopen("libwayland-egl.so.1", RTLD_LAZY); + if (!handle) { + if (verbose) { + fprintf(stderr, "%s\n", dlerror()); + } + return(1); + } + dlerror(); +// wl_egl_window_create + *(void **) (&wl_egl_window_create_dylibloader_wrapper_wayland_egl) = dlsym(handle, "wl_egl_window_create"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_egl_window_destroy + *(void **) (&wl_egl_window_destroy_dylibloader_wrapper_wayland_egl) = dlsym(handle, "wl_egl_window_destroy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_egl_window_resize + *(void **) (&wl_egl_window_resize_dylibloader_wrapper_wayland_egl) = dlsym(handle, "wl_egl_window_resize"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// wl_egl_window_get_attached_size + *(void **) (&wl_egl_window_get_attached_size_dylibloader_wrapper_wayland_egl) = dlsym(handle, "wl_egl_window_get_attached_size"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +return 0; +} diff --git a/platform/linuxbsd/wayland/dynwrappers/wayland-egl-core-so_wrap.h b/platform/linuxbsd/wayland/dynwrappers/wayland-egl-core-so_wrap.h new file mode 100644 index 00000000000..c2643f973f3 --- /dev/null +++ b/platform/linuxbsd/wayland/dynwrappers/wayland-egl-core-so_wrap.h @@ -0,0 +1,34 @@ +#ifndef DYLIBLOAD_WRAPPER_WAYLAND_EGL +#define DYLIBLOAD_WRAPPER_WAYLAND_EGL +// This file is generated. Do not edit! +// see https://github.com/hpvb/dynload-wrapper for details +// generated by ../dynload-wrapper/generate-wrapper.py 0.3 on 2023-01-25 17:49:37 +// flags: ../dynload-wrapper/generate-wrapper.py --include ./thirdparty/linuxbsd_headers/wayland/wayland-egl-core.h --sys-include "./thirdparty/linuxbsd_headers/wayland/wayland-egl-core.h" --soname libwayland-egl.so.1 --init-name wayland_egl --output-header platform/linuxbsd/wayland/dynwrappers/wayland-egl-core-so_wrap.h --output-implementation platform/linuxbsd/wayland/dynwrappers/wayland-egl-core-so_wrap.c +// +#include + +#define wl_egl_window_create wl_egl_window_create_dylibloader_orig_wayland_egl +#define wl_egl_window_destroy wl_egl_window_destroy_dylibloader_orig_wayland_egl +#define wl_egl_window_resize wl_egl_window_resize_dylibloader_orig_wayland_egl +#define wl_egl_window_get_attached_size wl_egl_window_get_attached_size_dylibloader_orig_wayland_egl +#include "./thirdparty/linuxbsd_headers/wayland/wayland-egl-core.h" +#undef wl_egl_window_create +#undef wl_egl_window_destroy +#undef wl_egl_window_resize +#undef wl_egl_window_get_attached_size +#ifdef __cplusplus +extern "C" { +#endif +#define wl_egl_window_create wl_egl_window_create_dylibloader_wrapper_wayland_egl +#define wl_egl_window_destroy wl_egl_window_destroy_dylibloader_wrapper_wayland_egl +#define wl_egl_window_resize wl_egl_window_resize_dylibloader_wrapper_wayland_egl +#define wl_egl_window_get_attached_size wl_egl_window_get_attached_size_dylibloader_wrapper_wayland_egl +extern struct wl_egl_window* (*wl_egl_window_create_dylibloader_wrapper_wayland_egl)(struct wl_surface*, int, int); +extern void (*wl_egl_window_destroy_dylibloader_wrapper_wayland_egl)(struct wl_egl_window*); +extern void (*wl_egl_window_resize_dylibloader_wrapper_wayland_egl)(struct wl_egl_window*, int, int, int, int); +extern void (*wl_egl_window_get_attached_size_dylibloader_wrapper_wayland_egl)(struct wl_egl_window*, int*, int*); +int initialize_wayland_egl(int verbose); +#ifdef __cplusplus +} +#endif +#endif diff --git a/platform/linuxbsd/wayland/egl_manager_wayland.cpp b/platform/linuxbsd/wayland/egl_manager_wayland.cpp new file mode 100644 index 00000000000..6cf24277a01 --- /dev/null +++ b/platform/linuxbsd/wayland/egl_manager_wayland.cpp @@ -0,0 +1,66 @@ +/**************************************************************************/ +/* egl_manager_wayland.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 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. */ +/**************************************************************************/ + +#include "egl_manager_wayland.h" + +#ifdef WAYLAND_ENABLED +#ifdef EGL_ENABLED +#ifdef GLES3_ENABLED + +const char *EGLManagerWayland::_get_platform_extension_name() const { + return "EGL_KHR_platform_wayland"; +} + +EGLenum EGLManagerWayland::_get_platform_extension_enum() const { + return EGL_PLATFORM_WAYLAND_KHR; +} + +EGLenum EGLManagerWayland::_get_platform_api_enum() const { + return EGL_OPENGL_API; +} + +Vector EGLManagerWayland::_get_platform_display_attributes() const { + return Vector(); +} + +Vector EGLManagerWayland::_get_platform_context_attribs() const { + Vector ret; + ret.push_back(EGL_CONTEXT_MAJOR_VERSION); + ret.push_back(3); + ret.push_back(EGL_CONTEXT_MINOR_VERSION); + ret.push_back(3); + ret.push_back(EGL_NONE); + + return ret; +} + +#endif // GLES3_ENABLED +#endif // EGL_ENABLED +#endif // WAYLAND_ENABLED diff --git a/platform/linuxbsd/wayland/egl_manager_wayland.h b/platform/linuxbsd/wayland/egl_manager_wayland.h new file mode 100644 index 00000000000..551c126760d --- /dev/null +++ b/platform/linuxbsd/wayland/egl_manager_wayland.h @@ -0,0 +1,53 @@ +/**************************************************************************/ +/* egl_manager_wayland.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 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. */ +/**************************************************************************/ + +#ifndef EGL_MANAGER_WAYLAND_H +#define EGL_MANAGER_WAYLAND_H + +#ifdef WAYLAND_ENABLED +#ifdef EGL_ENABLED +#ifdef GLES3_ENABLED + +#include "drivers/egl/egl_manager.h" + +class EGLManagerWayland : public EGLManager { +public: + virtual const char *_get_platform_extension_name() const override; + virtual EGLenum _get_platform_extension_enum() const override; + virtual EGLenum _get_platform_api_enum() const override; + virtual Vector _get_platform_display_attributes() const override; + virtual Vector _get_platform_context_attribs() const override; +}; + +#endif // GLES3_ENABLED +#endif // EGL_ENABLED +#endif // WAYLAND_ENABLED + +#endif // EGL_MANAGER_WAYLAND_H diff --git a/platform/linuxbsd/wayland/key_mapping_xkb.cpp b/platform/linuxbsd/wayland/key_mapping_xkb.cpp new file mode 100644 index 00000000000..bd1a1e38351 --- /dev/null +++ b/platform/linuxbsd/wayland/key_mapping_xkb.cpp @@ -0,0 +1,411 @@ +/**************************************************************************/ +/* key_mapping_xkb.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 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. */ +/**************************************************************************/ + +#include "key_mapping_xkb.h" + +void KeyMappingXKB::initialize() { + // XKB keycode to Godot Key map. + + xkb_keycode_map[XKB_KEY_Escape] = Key::ESCAPE; + xkb_keycode_map[XKB_KEY_Tab] = Key::TAB; + xkb_keycode_map[XKB_KEY_ISO_Left_Tab] = Key::BACKTAB; + xkb_keycode_map[XKB_KEY_BackSpace] = Key::BACKSPACE; + xkb_keycode_map[XKB_KEY_Return] = Key::ENTER; + xkb_keycode_map[XKB_KEY_Insert] = Key::INSERT; + xkb_keycode_map[XKB_KEY_Delete] = Key::KEY_DELETE; + xkb_keycode_map[XKB_KEY_Clear] = Key::KEY_DELETE; + xkb_keycode_map[XKB_KEY_Pause] = Key::PAUSE; + xkb_keycode_map[XKB_KEY_Print] = Key::PRINT; + xkb_keycode_map[XKB_KEY_Home] = Key::HOME; + xkb_keycode_map[XKB_KEY_End] = Key::END; + xkb_keycode_map[XKB_KEY_Left] = Key::LEFT; + xkb_keycode_map[XKB_KEY_Up] = Key::UP; + xkb_keycode_map[XKB_KEY_Right] = Key::RIGHT; + xkb_keycode_map[XKB_KEY_Down] = Key::DOWN; + xkb_keycode_map[XKB_KEY_Prior] = Key::PAGEUP; + xkb_keycode_map[XKB_KEY_Next] = Key::PAGEDOWN; + xkb_keycode_map[XKB_KEY_Shift_L] = Key::SHIFT; + xkb_keycode_map[XKB_KEY_Shift_R] = Key::SHIFT; + xkb_keycode_map[XKB_KEY_Shift_Lock] = Key::SHIFT; + xkb_keycode_map[XKB_KEY_Control_L] = Key::CTRL; + xkb_keycode_map[XKB_KEY_Control_R] = Key::CTRL; + xkb_keycode_map[XKB_KEY_Meta_L] = Key::META; + xkb_keycode_map[XKB_KEY_Meta_R] = Key::META; + xkb_keycode_map[XKB_KEY_Alt_L] = Key::ALT; + xkb_keycode_map[XKB_KEY_Alt_R] = Key::ALT; + xkb_keycode_map[XKB_KEY_Caps_Lock] = Key::CAPSLOCK; + xkb_keycode_map[XKB_KEY_Num_Lock] = Key::NUMLOCK; + xkb_keycode_map[XKB_KEY_Scroll_Lock] = Key::SCROLLLOCK; + xkb_keycode_map[XKB_KEY_less] = Key::QUOTELEFT; + xkb_keycode_map[XKB_KEY_grave] = Key::SECTION; + xkb_keycode_map[XKB_KEY_Super_L] = Key::META; + xkb_keycode_map[XKB_KEY_Super_R] = Key::META; + xkb_keycode_map[XKB_KEY_Menu] = Key::MENU; + xkb_keycode_map[XKB_KEY_Hyper_L] = Key::HYPER; + xkb_keycode_map[XKB_KEY_Hyper_R] = Key::HYPER; + xkb_keycode_map[XKB_KEY_Help] = Key::HELP; + xkb_keycode_map[XKB_KEY_KP_Space] = Key::SPACE; + xkb_keycode_map[XKB_KEY_KP_Tab] = Key::TAB; + xkb_keycode_map[XKB_KEY_KP_Enter] = Key::KP_ENTER; + xkb_keycode_map[XKB_KEY_Home] = Key::HOME; + xkb_keycode_map[XKB_KEY_Left] = Key::LEFT; + xkb_keycode_map[XKB_KEY_Up] = Key::UP; + xkb_keycode_map[XKB_KEY_Right] = Key::RIGHT; + xkb_keycode_map[XKB_KEY_Down] = Key::DOWN; + xkb_keycode_map[XKB_KEY_Prior] = Key::PAGEUP; + xkb_keycode_map[XKB_KEY_Next] = Key::PAGEDOWN; + xkb_keycode_map[XKB_KEY_End] = Key::END; + xkb_keycode_map[XKB_KEY_Begin] = Key::CLEAR; + xkb_keycode_map[XKB_KEY_Insert] = Key::INSERT; + xkb_keycode_map[XKB_KEY_Delete] = Key::KEY_DELETE; + xkb_keycode_map[XKB_KEY_KP_Equal] = Key::EQUAL; + xkb_keycode_map[XKB_KEY_KP_Separator] = Key::COMMA; + xkb_keycode_map[XKB_KEY_KP_Decimal] = Key::KP_PERIOD; + xkb_keycode_map[XKB_KEY_KP_Multiply] = Key::KP_MULTIPLY; + xkb_keycode_map[XKB_KEY_KP_Divide] = Key::KP_DIVIDE; + xkb_keycode_map[XKB_KEY_KP_Subtract] = Key::KP_SUBTRACT; + xkb_keycode_map[XKB_KEY_KP_Add] = Key::KP_ADD; + xkb_keycode_map[XKB_KEY_KP_0] = Key::KP_0; + xkb_keycode_map[XKB_KEY_KP_1] = Key::KP_1; + xkb_keycode_map[XKB_KEY_KP_2] = Key::KP_2; + xkb_keycode_map[XKB_KEY_KP_3] = Key::KP_3; + xkb_keycode_map[XKB_KEY_KP_4] = Key::KP_4; + xkb_keycode_map[XKB_KEY_KP_5] = Key::KP_5; + xkb_keycode_map[XKB_KEY_KP_6] = Key::KP_6; + xkb_keycode_map[XKB_KEY_KP_7] = Key::KP_7; + xkb_keycode_map[XKB_KEY_KP_8] = Key::KP_8; + xkb_keycode_map[XKB_KEY_KP_9] = Key::KP_9; + // Same keys but with numlock off. + xkb_keycode_map[XKB_KEY_KP_Insert] = Key::INSERT; + xkb_keycode_map[XKB_KEY_KP_Delete] = Key::KEY_DELETE; + xkb_keycode_map[XKB_KEY_KP_End] = Key::END; + xkb_keycode_map[XKB_KEY_KP_Down] = Key::DOWN; + xkb_keycode_map[XKB_KEY_KP_Page_Down] = Key::PAGEDOWN; + xkb_keycode_map[XKB_KEY_KP_Left] = Key::LEFT; + // X11 documents this (numpad 5) as "begin of line" but no toolkit seems to interpret it this way. + // On Windows this is emitting Key::Clear so for consistency it will be mapped to Key::Clear + xkb_keycode_map[XKB_KEY_KP_Begin] = Key::CLEAR; + xkb_keycode_map[XKB_KEY_KP_Right] = Key::RIGHT; + xkb_keycode_map[XKB_KEY_KP_Home] = Key::HOME; + xkb_keycode_map[XKB_KEY_KP_Up] = Key::UP; + xkb_keycode_map[XKB_KEY_KP_Page_Up] = Key::PAGEUP; + xkb_keycode_map[XKB_KEY_F1] = Key::F1; + xkb_keycode_map[XKB_KEY_F2] = Key::F2; + xkb_keycode_map[XKB_KEY_F3] = Key::F3; + xkb_keycode_map[XKB_KEY_F4] = Key::F4; + xkb_keycode_map[XKB_KEY_F5] = Key::F5; + xkb_keycode_map[XKB_KEY_F6] = Key::F6; + xkb_keycode_map[XKB_KEY_F7] = Key::F7; + xkb_keycode_map[XKB_KEY_F8] = Key::F8; + xkb_keycode_map[XKB_KEY_F9] = Key::F9; + xkb_keycode_map[XKB_KEY_F10] = Key::F10; + xkb_keycode_map[XKB_KEY_F11] = Key::F11; + xkb_keycode_map[XKB_KEY_F12] = Key::F12; + xkb_keycode_map[XKB_KEY_F13] = Key::F13; + xkb_keycode_map[XKB_KEY_F14] = Key::F14; + xkb_keycode_map[XKB_KEY_F15] = Key::F15; + xkb_keycode_map[XKB_KEY_F16] = Key::F16; + xkb_keycode_map[XKB_KEY_F17] = Key::F17; + xkb_keycode_map[XKB_KEY_F18] = Key::F18; + xkb_keycode_map[XKB_KEY_F19] = Key::F19; + xkb_keycode_map[XKB_KEY_F20] = Key::F20; + xkb_keycode_map[XKB_KEY_F21] = Key::F21; + xkb_keycode_map[XKB_KEY_F22] = Key::F22; + xkb_keycode_map[XKB_KEY_F23] = Key::F23; + xkb_keycode_map[XKB_KEY_F24] = Key::F24; + xkb_keycode_map[XKB_KEY_F25] = Key::F25; + xkb_keycode_map[XKB_KEY_F26] = Key::F26; + xkb_keycode_map[XKB_KEY_F27] = Key::F27; + xkb_keycode_map[XKB_KEY_F28] = Key::F28; + xkb_keycode_map[XKB_KEY_F29] = Key::F29; + xkb_keycode_map[XKB_KEY_F30] = Key::F30; + xkb_keycode_map[XKB_KEY_F31] = Key::F31; + xkb_keycode_map[XKB_KEY_F32] = Key::F32; + xkb_keycode_map[XKB_KEY_F33] = Key::F33; + xkb_keycode_map[XKB_KEY_F34] = Key::F34; + xkb_keycode_map[XKB_KEY_F35] = Key::F35; + xkb_keycode_map[XKB_KEY_yen] = Key::YEN; + xkb_keycode_map[XKB_KEY_section] = Key::SECTION; + // Media keys. + xkb_keycode_map[XKB_KEY_XF86Back] = Key::BACK; + xkb_keycode_map[XKB_KEY_XF86Forward] = Key::FORWARD; + xkb_keycode_map[XKB_KEY_XF86Stop] = Key::STOP; + xkb_keycode_map[XKB_KEY_XF86Refresh] = Key::REFRESH; + xkb_keycode_map[XKB_KEY_XF86Favorites] = Key::FAVORITES; + xkb_keycode_map[XKB_KEY_XF86OpenURL] = Key::OPENURL; + xkb_keycode_map[XKB_KEY_XF86HomePage] = Key::HOMEPAGE; + xkb_keycode_map[XKB_KEY_XF86Search] = Key::SEARCH; + xkb_keycode_map[XKB_KEY_XF86AudioLowerVolume] = Key::VOLUMEDOWN; + xkb_keycode_map[XKB_KEY_XF86AudioMute] = Key::VOLUMEMUTE; + xkb_keycode_map[XKB_KEY_XF86AudioRaiseVolume] = Key::VOLUMEUP; + xkb_keycode_map[XKB_KEY_XF86AudioPlay] = Key::MEDIAPLAY; + xkb_keycode_map[XKB_KEY_XF86AudioStop] = Key::MEDIASTOP; + xkb_keycode_map[XKB_KEY_XF86AudioPrev] = Key::MEDIAPREVIOUS; + xkb_keycode_map[XKB_KEY_XF86AudioNext] = Key::MEDIANEXT; + xkb_keycode_map[XKB_KEY_XF86AudioRecord] = Key::MEDIARECORD; + xkb_keycode_map[XKB_KEY_XF86Standby] = Key::STANDBY; + // Launch keys. + xkb_keycode_map[XKB_KEY_XF86Mail] = Key::LAUNCHMAIL; + xkb_keycode_map[XKB_KEY_XF86AudioMedia] = Key::LAUNCHMEDIA; + xkb_keycode_map[XKB_KEY_XF86MyComputer] = Key::LAUNCH0; + xkb_keycode_map[XKB_KEY_XF86Calculator] = Key::LAUNCH1; + xkb_keycode_map[XKB_KEY_XF86Launch0] = Key::LAUNCH2; + xkb_keycode_map[XKB_KEY_XF86Launch1] = Key::LAUNCH3; + xkb_keycode_map[XKB_KEY_XF86Launch2] = Key::LAUNCH4; + xkb_keycode_map[XKB_KEY_XF86Launch3] = Key::LAUNCH5; + xkb_keycode_map[XKB_KEY_XF86Launch4] = Key::LAUNCH6; + xkb_keycode_map[XKB_KEY_XF86Launch5] = Key::LAUNCH7; + xkb_keycode_map[XKB_KEY_XF86Launch6] = Key::LAUNCH8; + xkb_keycode_map[XKB_KEY_XF86Launch7] = Key::LAUNCH9; + xkb_keycode_map[XKB_KEY_XF86Launch8] = Key::LAUNCHA; + xkb_keycode_map[XKB_KEY_XF86Launch9] = Key::LAUNCHB; + xkb_keycode_map[XKB_KEY_XF86LaunchA] = Key::LAUNCHC; + xkb_keycode_map[XKB_KEY_XF86LaunchB] = Key::LAUNCHD; + xkb_keycode_map[XKB_KEY_XF86LaunchC] = Key::LAUNCHE; + xkb_keycode_map[XKB_KEY_XF86LaunchD] = Key::LAUNCHF; + + // Scancode to Godot Key map. + scancode_map[0x09] = Key::ESCAPE; + scancode_map[0x0A] = Key::KEY_1; + scancode_map[0x0B] = Key::KEY_2; + scancode_map[0x0C] = Key::KEY_3; + scancode_map[0x0D] = Key::KEY_4; + scancode_map[0x0E] = Key::KEY_5; + scancode_map[0x0F] = Key::KEY_6; + scancode_map[0x10] = Key::KEY_7; + scancode_map[0x11] = Key::KEY_8; + scancode_map[0x12] = Key::KEY_9; + scancode_map[0x13] = Key::KEY_0; + scancode_map[0x14] = Key::MINUS; + scancode_map[0x15] = Key::EQUAL; + scancode_map[0x16] = Key::BACKSPACE; + scancode_map[0x17] = Key::TAB; + scancode_map[0x18] = Key::Q; + scancode_map[0x19] = Key::W; + scancode_map[0x1A] = Key::E; + scancode_map[0x1B] = Key::R; + scancode_map[0x1C] = Key::T; + scancode_map[0x1D] = Key::Y; + scancode_map[0x1E] = Key::U; + scancode_map[0x1F] = Key::I; + scancode_map[0x20] = Key::O; + scancode_map[0x21] = Key::P; + scancode_map[0x22] = Key::BRACELEFT; + scancode_map[0x23] = Key::BRACERIGHT; + scancode_map[0x24] = Key::ENTER; + scancode_map[0x25] = Key::CTRL; // Left + scancode_map[0x26] = Key::A; + scancode_map[0x27] = Key::S; + scancode_map[0x28] = Key::D; + scancode_map[0x29] = Key::F; + scancode_map[0x2A] = Key::G; + scancode_map[0x2B] = Key::H; + scancode_map[0x2C] = Key::J; + scancode_map[0x2D] = Key::K; + scancode_map[0x2E] = Key::L; + scancode_map[0x2F] = Key::SEMICOLON; + scancode_map[0x30] = Key::APOSTROPHE; + scancode_map[0x31] = Key::SECTION; + scancode_map[0x32] = Key::SHIFT; // Left + scancode_map[0x33] = Key::BACKSLASH; + scancode_map[0x34] = Key::Z; + scancode_map[0x35] = Key::X; + scancode_map[0x36] = Key::C; + scancode_map[0x37] = Key::V; + scancode_map[0x38] = Key::B; + scancode_map[0x39] = Key::N; + scancode_map[0x3A] = Key::M; + scancode_map[0x3B] = Key::COMMA; + scancode_map[0x3C] = Key::PERIOD; + scancode_map[0x3D] = Key::SLASH; + scancode_map[0x3E] = Key::SHIFT; // Right + scancode_map[0x3F] = Key::KP_MULTIPLY; + scancode_map[0x40] = Key::ALT; // Left + scancode_map[0x41] = Key::SPACE; + scancode_map[0x42] = Key::CAPSLOCK; + scancode_map[0x43] = Key::F1; + scancode_map[0x44] = Key::F2; + scancode_map[0x45] = Key::F3; + scancode_map[0x46] = Key::F4; + scancode_map[0x47] = Key::F5; + scancode_map[0x48] = Key::F6; + scancode_map[0x49] = Key::F7; + scancode_map[0x4A] = Key::F8; + scancode_map[0x4B] = Key::F9; + scancode_map[0x4C] = Key::F10; + scancode_map[0x4D] = Key::NUMLOCK; + scancode_map[0x4E] = Key::SCROLLLOCK; + scancode_map[0x4F] = Key::KP_7; + scancode_map[0x50] = Key::KP_8; + scancode_map[0x51] = Key::KP_9; + scancode_map[0x52] = Key::KP_SUBTRACT; + scancode_map[0x53] = Key::KP_4; + scancode_map[0x54] = Key::KP_5; + scancode_map[0x55] = Key::KP_6; + scancode_map[0x56] = Key::KP_ADD; + scancode_map[0x57] = Key::KP_1; + scancode_map[0x58] = Key::KP_2; + scancode_map[0x59] = Key::KP_3; + scancode_map[0x5A] = Key::KP_0; + scancode_map[0x5B] = Key::KP_PERIOD; + //scancode_map[0x5C] + //scancode_map[0x5D] // Zenkaku Hankaku + scancode_map[0x5E] = Key::QUOTELEFT; + scancode_map[0x5F] = Key::F11; + scancode_map[0x60] = Key::F12; + //scancode_map[0x61] // Romaji + //scancode_map[0x62] // Katakana + //scancode_map[0x63] // Hiragana + //scancode_map[0x64] // Henkan + //scancode_map[0x65] // Hiragana Katakana + //scancode_map[0x66] // Muhenkan + scancode_map[0x67] = Key::COMMA; // KP_Separator + scancode_map[0x68] = Key::KP_ENTER; + scancode_map[0x69] = Key::CTRL; // Right + scancode_map[0x6A] = Key::KP_DIVIDE; + scancode_map[0x6B] = Key::PRINT; + scancode_map[0x6C] = Key::ALT; // Right + scancode_map[0x6D] = Key::ENTER; + scancode_map[0x6E] = Key::HOME; + scancode_map[0x6F] = Key::UP; + scancode_map[0x70] = Key::PAGEUP; + scancode_map[0x71] = Key::LEFT; + scancode_map[0x72] = Key::RIGHT; + scancode_map[0x73] = Key::END; + scancode_map[0x74] = Key::DOWN; + scancode_map[0x75] = Key::PAGEDOWN; + scancode_map[0x76] = Key::INSERT; + scancode_map[0x77] = Key::KEY_DELETE; + //scancode_map[0x78] // Macro + scancode_map[0x79] = Key::VOLUMEMUTE; + scancode_map[0x7A] = Key::VOLUMEDOWN; + scancode_map[0x7B] = Key::VOLUMEUP; + //scancode_map[0x7C] // Power + scancode_map[0x7D] = Key::EQUAL; // KP_Equal + //scancode_map[0x7E] // KP_PlusMinus + scancode_map[0x7F] = Key::PAUSE; + scancode_map[0x80] = Key::LAUNCH0; + scancode_map[0x81] = Key::COMMA; // KP_Comma + //scancode_map[0x82] // Hangul + //scancode_map[0x83] // Hangul_Hanja + scancode_map[0x84] = Key::YEN; + scancode_map[0x85] = Key::META; // Left + scancode_map[0x86] = Key::META; // Right + scancode_map[0x87] = Key::MENU; + + scancode_map[0xA6] = Key::BACK; // On Chromebooks + scancode_map[0xA7] = Key::FORWARD; // On Chromebooks + + scancode_map[0xB5] = Key::REFRESH; // On Chromebooks + + scancode_map[0xBF] = Key::F13; + scancode_map[0xC0] = Key::F14; + scancode_map[0xC1] = Key::F15; + scancode_map[0xC2] = Key::F16; + scancode_map[0xC3] = Key::F17; + scancode_map[0xC4] = Key::F18; + scancode_map[0xC5] = Key::F19; + scancode_map[0xC6] = Key::F20; + scancode_map[0xC7] = Key::F21; + scancode_map[0xC8] = Key::F22; + scancode_map[0xC9] = Key::F23; + scancode_map[0xCA] = Key::F24; + scancode_map[0xCB] = Key::F25; + scancode_map[0xCC] = Key::F26; + scancode_map[0xCD] = Key::F27; + scancode_map[0xCE] = Key::F28; + scancode_map[0xCF] = Key::F29; + scancode_map[0xD0] = Key::F30; + scancode_map[0xD1] = Key::F31; + scancode_map[0xD2] = Key::F32; + scancode_map[0xD3] = Key::F33; + scancode_map[0xD4] = Key::F34; + scancode_map[0xD5] = Key::F35; + + // Godot to scancode map. + for (const KeyValue &E : scancode_map) { + scancode_map_inv[E.value] = E.key; + } + + // Scancode to physical location map. + // Ctrl. + location_map[0x25] = KeyLocation::LEFT; + location_map[0x69] = KeyLocation::RIGHT; + // Shift. + location_map[0x32] = KeyLocation::LEFT; + location_map[0x3E] = KeyLocation::RIGHT; + // Alt. + location_map[0x40] = KeyLocation::LEFT; + location_map[0x6C] = KeyLocation::RIGHT; + // Meta. + location_map[0x85] = KeyLocation::LEFT; + location_map[0x86] = KeyLocation::RIGHT; +} + +Key KeyMappingXKB::get_keycode(xkb_keycode_t p_keysym) { + if (p_keysym >= 0x20 && p_keysym < 0x7E) { // ASCII, maps 1-1 + if (p_keysym > 0x60 && p_keysym < 0x7B) { // Lowercase ASCII. + return (Key)(p_keysym - 32); + } else { + return (Key)p_keysym; + } + } + + const Key *key = xkb_keycode_map.getptr(p_keysym); + if (key) { + return *key; + } + return Key::NONE; +} + +Key KeyMappingXKB::get_scancode(unsigned int p_code) { + const Key *key = scancode_map.getptr(p_code); + if (key) { + return *key; + } + + return Key::NONE; +} + +xkb_keycode_t KeyMappingXKB::get_xkb_keycode(Key p_key) { + const unsigned int *key = scancode_map_inv.getptr(p_key); + if (key) { + return *key; + } + return 0x00; +} + +KeyLocation KeyMappingXKB::get_location(unsigned int p_code) { + const KeyLocation *location = location_map.getptr(p_code); + if (location) { + return *location; + } + return KeyLocation::UNSPECIFIED; +} diff --git a/platform/linuxbsd/wayland/key_mapping_xkb.h b/platform/linuxbsd/wayland/key_mapping_xkb.h new file mode 100644 index 00000000000..306a8f25b57 --- /dev/null +++ b/platform/linuxbsd/wayland/key_mapping_xkb.h @@ -0,0 +1,65 @@ +/**************************************************************************/ +/* key_mapping_xkb.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 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. */ +/**************************************************************************/ + +#ifndef KEY_MAPPING_XKB_H +#define KEY_MAPPING_XKB_H + +#include "core/os/keyboard.h" +#include "core/templates/hash_map.h" + +#ifdef SOWRAP_ENABLED +#include "xkbcommon-so_wrap.h" +#else +#include +#endif // SOWRAP_ENABLED + +class KeyMappingXKB { + struct HashMapHasherKeys { + static _FORCE_INLINE_ uint32_t hash(Key p_key) { return hash_fmix32(static_cast(p_key)); } + static _FORCE_INLINE_ uint32_t hash(unsigned p_key) { return hash_fmix32(p_key); } + }; + + static inline HashMap xkb_keycode_map; + static inline HashMap scancode_map; + static inline HashMap scancode_map_inv; + static inline HashMap location_map; + + KeyMappingXKB(){}; + +public: + static void initialize(); + + static Key get_keycode(xkb_keysym_t p_keysym); + static xkb_keycode_t get_xkb_keycode(Key p_keycode); + static Key get_scancode(unsigned int p_code); + static KeyLocation get_location(unsigned int p_code); +}; + +#endif // KEY_MAPPING_XKB_H diff --git a/platform/linuxbsd/wayland/vulkan_context_wayland.cpp b/platform/linuxbsd/wayland/vulkan_context_wayland.cpp new file mode 100644 index 00000000000..b3f28a16788 --- /dev/null +++ b/platform/linuxbsd/wayland/vulkan_context_wayland.cpp @@ -0,0 +1,59 @@ +/**************************************************************************/ +/* vulkan_context_wayland.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 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. */ +/**************************************************************************/ + +#include "vulkan_context_wayland.h" + +#ifdef VULKAN_ENABLED + +#ifdef USE_VOLK +#include +#else +#include +#endif + +const char *VulkanContextWayland::_get_platform_surface_extension() const { + return VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME; +} + +Error VulkanContextWayland::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) { + const WindowPlatformData *wpd = (const WindowPlatformData *)p_platform_data; + + VkWaylandSurfaceCreateInfoKHR createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; + createInfo.display = wpd->display; + createInfo.surface = wpd->surface; + + VkSurfaceKHR surface = VK_NULL_HANDLE; + VkResult err = vkCreateWaylandSurfaceKHR(get_instance(), &createInfo, nullptr, &surface); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height); +} + +#endif // VULKAN_ENABLED diff --git a/platform/linuxbsd/wayland/vulkan_context_wayland.h b/platform/linuxbsd/wayland/vulkan_context_wayland.h new file mode 100644 index 00000000000..b0a7d1ff87f --- /dev/null +++ b/platform/linuxbsd/wayland/vulkan_context_wayland.h @@ -0,0 +1,52 @@ +/**************************************************************************/ +/* vulkan_context_wayland.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 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. */ +/**************************************************************************/ + +#ifndef VULKAN_CONTEXT_WAYLAND_H +#define VULKAN_CONTEXT_WAYLAND_H + +#ifdef VULKAN_ENABLED + +#include "drivers/vulkan/vulkan_context.h" + +class VulkanContextWayland : public VulkanContext { + const char *_get_platform_surface_extension() const override final; + +public: + struct WindowPlatformData { + struct wl_display *display; + struct wl_surface *surface; + }; + + Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final; +}; + +#endif // VULKAN_ENABLED + +#endif // VULKAN_CONTEXT_WAYLAND_H diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp new file mode 100644 index 00000000000..9410e4653d6 --- /dev/null +++ b/platform/linuxbsd/wayland/wayland_thread.cpp @@ -0,0 +1,4004 @@ +/**************************************************************************/ +/* wayland_thread.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 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. */ +/**************************************************************************/ + +#include "wayland_thread.h" + +#ifdef WAYLAND_ENABLED + +// FIXME: Does this cause issues with *BSDs? +#include + +// For the actual polling thread. +#include + +// For shared memory buffer creation. +#include +#include +#include + +// Fix the wl_array_for_each macro to work with C++. This is based on the +// original from `wayland-util.h` in the Wayland client library. +#undef wl_array_for_each +#define wl_array_for_each(pos, array) \ + for (pos = (decltype(pos))(array)->data; (const char *)pos < ((const char *)(array)->data + (array)->size); (pos)++) + +#define WAYLAND_THREAD_DEBUG_LOGS_ENABLED +#ifdef WAYLAND_THREAD_DEBUG_LOGS_ENABLED +#define DEBUG_LOG_WAYLAND_THREAD(...) print_verbose(__VA_ARGS__) +#else +#define DEBUG_LOG_WAYLAND_THREAD(...) +#endif + +// Read the content pointed by fd into a Vector. +Vector WaylandThread::_read_fd(int fd) { + // This is pretty much an arbitrary size. + uint32_t chunk_size = 2048; + + LocalVector data; + data.resize(chunk_size); + + uint32_t bytes_read = 0; + + while (true) { + ssize_t last_bytes_read = read(fd, data.ptr() + bytes_read, chunk_size); + if (last_bytes_read < 0) { + ERR_PRINT(vformat("Read error %d.", errno)); + + data.clear(); + break; + } + + if (last_bytes_read == 0) { + // We're done, we've reached the EOF. + DEBUG_LOG_WAYLAND_THREAD(vformat("Done reading %d bytes.", bytes_read)); + + close(fd); + + data.resize(bytes_read); + break; + } + + DEBUG_LOG_WAYLAND_THREAD(vformat("Read chunk of %d bytes.", last_bytes_read)); + + bytes_read += last_bytes_read; + + // Increase the buffer size by one chunk in preparation of the next read. + data.resize(bytes_read + chunk_size); + } + + return data; +} + +// Based on the wayland book's shared memory boilerplate (PD/CC0). +// See: https://wayland-book.com/surfaces/shared-memory.html +int WaylandThread::_allocate_shm_file(size_t size) { + int retries = 100; + + do { + // Generate a random name. + char name[] = "/wl_shm-godot-XXXXXX"; + for (long unsigned int i = sizeof(name) - 7; i < sizeof(name) - 1; i++) { + name[i] = Math::random('A', 'Z'); + } + + // Try to open a shared memory object with that name. + int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd >= 0) { + // Success, unlink its name as we just need the file descriptor. + shm_unlink(name); + + // Resize the file to the requested length. + int ret; + do { + ret = ftruncate(fd, size); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) { + close(fd); + return -1; + } + + return fd; + } + + retries--; + } while (retries > 0 && errno == EEXIST); + + return -1; +} + +// Return the content of a wl_data_offer. +Vector WaylandThread::_wl_data_offer_read(struct wl_display *p_display, const char *p_mime, struct wl_data_offer *p_offer) { + if (!p_offer) { + return Vector(); + } + + int fds[2]; + if (pipe(fds) == 0) { + wl_data_offer_receive(p_offer, p_mime, fds[1]); + + // Let the compositor know about the pipe. + // NOTE: It's important to just flush and not roundtrip here as we would risk + // running some cleanup event, like for example `wl_data_device::leave`. We're + // going to wait for the message anyways as the read will probably block if + // the compositor doesn't read from the other end of the pipe. + wl_display_flush(p_display); + + // Close the write end of the pipe, which we don't need and would otherwise + // just stall our next `read`s. + close(fds[1]); + + return _read_fd(fds[0]); + } + + return Vector(); +} + +// Read the content of a wp_primary_selection_offer. +Vector WaylandThread::_wp_primary_selection_offer_read(struct wl_display *p_display, const char *p_mime, struct zwp_primary_selection_offer_v1 *p_offer) { + if (!p_offer) { + return Vector(); + } + + int fds[2]; + if (pipe(fds) == 0) { + // This function expects to return a string, so we can only ask for a MIME of + // "text/plain" + zwp_primary_selection_offer_v1_receive(p_offer, p_mime, fds[1]); + + // Wait for the compositor to know about the pipe. + wl_display_roundtrip(p_display); + + // Close the write end of the pipe, which we don't need and would otherwise + // just stall our next `read`s. + close(fds[1]); + + return _read_fd(fds[0]); + } + + return Vector(); +} + +// Sets up an `InputEventKey` and returns whether it has any meaningful value. +bool WaylandThread::_seat_state_configure_key_event(SeatState &p_ss, Ref p_event, xkb_keycode_t p_keycode, bool p_pressed) { + // TODO: Handle keys that release multiple symbols? + Key keycode = KeyMappingXKB::get_keycode(xkb_state_key_get_one_sym(p_ss.xkb_state, p_keycode)); + Key physical_keycode = KeyMappingXKB::get_scancode(p_keycode); + KeyLocation key_location = KeyMappingXKB::get_location(p_keycode); + + if (physical_keycode == Key::NONE) { + return false; + } + + if (keycode == Key::NONE) { + keycode = physical_keycode; + } + + if (keycode >= Key::A + 32 && keycode <= Key::Z + 32) { + keycode -= 'a' - 'A'; + } + + p_event->set_window_id(DisplayServer::MAIN_WINDOW_ID); + + // Set all pressed modifiers. + p_event->set_shift_pressed(p_ss.shift_pressed); + p_event->set_ctrl_pressed(p_ss.ctrl_pressed); + p_event->set_alt_pressed(p_ss.alt_pressed); + p_event->set_meta_pressed(p_ss.meta_pressed); + + p_event->set_pressed(p_pressed); + p_event->set_keycode(keycode); + p_event->set_physical_keycode(physical_keycode); + p_event->set_location(key_location); + + uint32_t unicode = xkb_state_key_get_utf32(p_ss.xkb_state, p_keycode); + + if (unicode != 0) { + p_event->set_key_label(fix_key_label(unicode, keycode)); + } else { + p_event->set_key_label(keycode); + } + + if (p_pressed) { + p_event->set_unicode(fix_unicode(unicode)); + } + + // Taken from DisplayServerX11. + if (p_event->get_keycode() == Key::BACKTAB) { + // Make it consistent across platforms. + p_event->set_keycode(Key::TAB); + p_event->set_physical_keycode(Key::TAB); + p_event->set_shift_pressed(true); + } + + return true; +} + +void WaylandThread::_set_current_seat(struct wl_seat *p_seat) { + if (p_seat == wl_seat_current) { + return; + } + + SeatState *old_state = wl_seat_get_seat_state(wl_seat_current); + + if (old_state) { + seat_state_unlock_pointer(old_state); + } + + SeatState *new_state = wl_seat_get_seat_state(p_seat); + seat_state_unlock_pointer(new_state); + + wl_seat_current = p_seat; + pointer_set_constraint(pointer_constraint); +} + +// Returns whether it loaded the theme or not. +bool WaylandThread::_load_cursor_theme(int p_cursor_size) { + if (wl_cursor_theme) { + wl_cursor_theme_destroy(wl_cursor_theme); + wl_cursor_theme = nullptr; + + current_wl_cursor = nullptr; + } + + if (cursor_theme_name.is_empty()) { + cursor_theme_name = "default"; + } + + print_verbose(vformat("Loading cursor theme \"%s\" size %d.", cursor_theme_name, p_cursor_size)); + + wl_cursor_theme = wl_cursor_theme_load(cursor_theme_name.utf8().get_data(), p_cursor_size, registry.wl_shm); + + ERR_FAIL_NULL_V_MSG(wl_cursor_theme, false, "Can't load any cursor theme."); + + static const char *cursor_names[] = { + "left_ptr", + "xterm", + "hand2", + "cross", + "watch", + "left_ptr_watch", + "fleur", + "dnd-move", + "crossed_circle", + "v_double_arrow", + "h_double_arrow", + "size_bdiag", + "size_fdiag", + "move", + "row_resize", + "col_resize", + "question_arrow" + }; + + static const char *cursor_names_fallback[] = { + nullptr, + nullptr, + "pointer", + "cross", + "wait", + "progress", + "grabbing", + "hand1", + "forbidden", + "ns-resize", + "ew-resize", + "fd_double_arrow", + "bd_double_arrow", + "fleur", + "sb_v_double_arrow", + "sb_h_double_arrow", + "help" + }; + + for (int i = 0; i < DisplayServer::CURSOR_MAX; i++) { + struct wl_cursor *cursor = wl_cursor_theme_get_cursor(wl_cursor_theme, cursor_names[i]); + + if (!cursor && cursor_names_fallback[i]) { + cursor = wl_cursor_theme_get_cursor(wl_cursor_theme, cursor_names_fallback[i]); + } + + if (cursor && cursor->image_count > 0) { + wl_cursors[i] = cursor; + } else { + wl_cursors[i] = nullptr; + print_verbose("Failed loading cursor: " + String(cursor_names[i])); + } + } + + return true; +} + +void WaylandThread::_update_scale(int p_scale) { + if (p_scale <= cursor_scale) { + return; + } + + print_verbose(vformat("Bumping cursor scale to %d", p_scale)); + + // There's some display that's bigger than the cache, let's update it. + cursor_scale = p_scale; + + if (wl_cursor_theme == nullptr) { + // Ugh. Either we're still initializing (this must've been called from the + // first roundtrips) or we had some error while doing so. We'll trust that it + // will be updated for us if needed. + return; + } + + int cursor_size = unscaled_cursor_size * p_scale; + + if (_load_cursor_theme(cursor_size)) { + cursor_set_shape(last_cursor_shape); + } +} + +void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, uint32_t version) { + RegistryState *registry = (RegistryState *)data; + ERR_FAIL_NULL(registry); + + if (strcmp(interface, wl_shm_interface.name) == 0) { + registry->wl_shm = (struct wl_shm *)wl_registry_bind(wl_registry, name, &wl_shm_interface, 1); + registry->wl_shm_name = name; + return; + } + + if (strcmp(interface, wl_compositor_interface.name) == 0) { + registry->wl_compositor = (struct wl_compositor *)wl_registry_bind(wl_registry, name, &wl_compositor_interface, 4); + registry->wl_compositor_name = name; + return; + } + + if (strcmp(interface, wl_subcompositor_interface.name) == 0) { + registry->wl_subcompositor = (struct wl_subcompositor *)wl_registry_bind(wl_registry, name, &wl_subcompositor_interface, 1); + registry->wl_subcompositor_name = name; + return; + } + + if (strcmp(interface, wl_data_device_manager_interface.name) == 0) { + registry->wl_data_device_manager = (struct wl_data_device_manager *)wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, 3); + registry->wl_data_device_manager_name = name; + + // This global creates some seats data. Let's do that for the ones already available. + for (struct wl_seat *wl_seat : registry->wl_seats) { + SeatState *ss = wl_seat_get_seat_state(wl_seat); + ERR_FAIL_NULL(ss); + + if (ss->wl_data_device == nullptr) { + ss->wl_data_device = wl_data_device_manager_get_data_device(registry->wl_data_device_manager, wl_seat); + wl_data_device_add_listener(ss->wl_data_device, &wl_data_device_listener, ss); + } + } + return; + } + + if (strcmp(interface, wl_output_interface.name) == 0) { + struct wl_output *wl_output = (struct wl_output *)wl_registry_bind(wl_registry, name, &wl_output_interface, 2); + wl_proxy_tag_godot((struct wl_proxy *)wl_output); + + registry->wl_outputs.push_back(wl_output); + + ScreenState *ss = memnew(ScreenState); + ss->wl_output_name = name; + ss->wayland_thread = registry->wayland_thread; + + wl_proxy_tag_godot((struct wl_proxy *)wl_output); + wl_output_add_listener(wl_output, &wl_output_listener, ss); + return; + } + + if (strcmp(interface, wl_seat_interface.name) == 0) { + struct wl_seat *wl_seat = (struct wl_seat *)wl_registry_bind(wl_registry, name, &wl_seat_interface, 5); + wl_proxy_tag_godot((struct wl_proxy *)wl_seat); + + SeatState *ss = memnew(SeatState); + ss->wl_seat = wl_seat; + ss->wl_seat_name = name; + + ss->registry = registry; + ss->wayland_thread = registry->wayland_thread; + + // Some extra stuff depends on other globals. We'll initialize them if the + // globals are already there, otherwise we'll have to do that once and if they + // get announced. + // + // NOTE: Don't forget to also bind/destroy with the respective global. + if (!ss->wl_data_device && registry->wl_data_device_manager) { + // Clipboard & DnD. + ss->wl_data_device = wl_data_device_manager_get_data_device(registry->wl_data_device_manager, wl_seat); + wl_data_device_add_listener(ss->wl_data_device, &wl_data_device_listener, ss); + } + + if (!ss->wp_primary_selection_device && registry->wp_primary_selection_device_manager) { + // Primary selection. + ss->wp_primary_selection_device = zwp_primary_selection_device_manager_v1_get_device(registry->wp_primary_selection_device_manager, wl_seat); + zwp_primary_selection_device_v1_add_listener(ss->wp_primary_selection_device, &wp_primary_selection_device_listener, ss); + } + +#if 0 + // FIXME: Broken. + if (!ss->wp_tablet_seat && registry->wp_tablet_manager) { + // Tablet. + ss->wp_tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(registry->wp_tablet_manager, wl_seat); + zwp_tablet_seat_v2_add_listener(ss->wp_tablet_seat, &wp_tablet_seat_listener, ss); + } +#endif + + registry->wl_seats.push_back(wl_seat); + + wl_seat_add_listener(wl_seat, &wl_seat_listener, ss); + + if (registry->wayland_thread->wl_seat_current == nullptr) { + registry->wayland_thread->_set_current_seat(wl_seat); + } + + return; + } + + if (strcmp(interface, xdg_wm_base_interface.name) == 0) { + registry->xdg_wm_base = (struct xdg_wm_base *)wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, MAX(2, MIN(5, (int)version))); + registry->xdg_wm_base_name = name; + + xdg_wm_base_add_listener(registry->xdg_wm_base, &xdg_wm_base_listener, nullptr); + return; + } + + if (strcmp(interface, wp_viewporter_interface.name) == 0) { + registry->wp_viewporter = (struct wp_viewporter *)wl_registry_bind(wl_registry, name, &wp_viewporter_interface, 1); + registry->wp_viewporter_name = name; + } + + if (strcmp(interface, wp_fractional_scale_manager_v1_interface.name) == 0) { + registry->wp_fractional_scale_manager = (struct wp_fractional_scale_manager_v1 *)wl_registry_bind(wl_registry, name, &wp_fractional_scale_manager_v1_interface, 1); + registry->wp_fractional_scale_manager_name = name; + + // NOTE: We're not mapping the fractional scale object here because this is + // supposed to be a "startup global". If for some reason this isn't true (who + // knows), add a conditional branch for creating the add-on object. + } + + if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) { + registry->xdg_decoration_manager = (struct zxdg_decoration_manager_v1 *)wl_registry_bind(wl_registry, name, &zxdg_decoration_manager_v1_interface, 1); + registry->xdg_decoration_manager_name = name; + return; + } + + if (strcmp(interface, xdg_activation_v1_interface.name) == 0) { + registry->xdg_activation = (struct xdg_activation_v1 *)wl_registry_bind(wl_registry, name, &xdg_activation_v1_interface, 1); + registry->xdg_activation_name = name; + return; + } + + if (strcmp(interface, zwp_primary_selection_device_manager_v1_interface.name) == 0) { + registry->wp_primary_selection_device_manager = (struct zwp_primary_selection_device_manager_v1 *)wl_registry_bind(wl_registry, name, &zwp_primary_selection_device_manager_v1_interface, 1); + + // This global creates some seats data. Let's do that for the ones already available. + for (struct wl_seat *wl_seat : registry->wl_seats) { + SeatState *ss = wl_seat_get_seat_state(wl_seat); + ERR_FAIL_NULL(ss); + + if (!ss->wp_primary_selection_device && registry->wp_primary_selection_device_manager) { + ss->wp_primary_selection_device = zwp_primary_selection_device_manager_v1_get_device(registry->wp_primary_selection_device_manager, wl_seat); + zwp_primary_selection_device_v1_add_listener(ss->wp_primary_selection_device, &wp_primary_selection_device_listener, ss); + } + } + } + + if (strcmp(interface, zwp_relative_pointer_manager_v1_interface.name) == 0) { + registry->wp_relative_pointer_manager = (struct zwp_relative_pointer_manager_v1 *)wl_registry_bind(wl_registry, name, &zwp_relative_pointer_manager_v1_interface, 1); + registry->wp_relative_pointer_manager_name = name; + return; + } + + if (strcmp(interface, zwp_pointer_constraints_v1_interface.name) == 0) { + registry->wp_pointer_constraints = (struct zwp_pointer_constraints_v1 *)wl_registry_bind(wl_registry, name, &zwp_pointer_constraints_v1_interface, 1); + registry->wp_pointer_constraints_name = name; + return; + } + + if (strcmp(interface, zwp_pointer_gestures_v1_interface.name) == 0) { + registry->wp_pointer_gestures = (struct zwp_pointer_gestures_v1 *)wl_registry_bind(wl_registry, name, &zwp_pointer_gestures_v1_interface, 1); + registry->wp_pointer_gestures_name = name; + return; + } + + if (strcmp(interface, zwp_idle_inhibit_manager_v1_interface.name) == 0) { + registry->wp_idle_inhibit_manager = (struct zwp_idle_inhibit_manager_v1 *)wl_registry_bind(wl_registry, name, &zwp_idle_inhibit_manager_v1_interface, 1); + registry->wp_idle_inhibit_manager_name = name; + return; + } + +#if 0 + // FIXME: Broken. + if (strcmp(interface, zwp_tablet_manager_v2_interface.name) == 0) { + registry->wp_tablet_manager = (struct zwp_tablet_manager_v2 *)wl_registry_bind(wl_registry, name, &zwp_tablet_manager_v2_interface, 1); + registry->wp_tablet_manager_name = name; + + // This global creates some seats data. Let's do that for the ones already available. + for (struct wl_seat *wl_seat : registry->wl_seats) { + SeatState *ss = wl_seat_get_seat_state(wl_seat); + ERR_FAIL_NULL(ss); + + ss->wp_tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(registry->wp_tablet_manager, wl_seat); + zwp_tablet_seat_v2_add_listener(ss->wp_tablet_seat, &wp_tablet_seat_listener, ss); + } + + return; + } +#endif +} + +void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name) { + RegistryState *registry = (RegistryState *)data; + ERR_FAIL_NULL(registry); + + if (name == registry->wl_shm_name) { + if (registry->wl_shm) { + wl_shm_destroy(registry->wl_shm); + registry->wl_shm = nullptr; + } + + registry->wl_shm_name = 0; + + return; + } + + if (name == registry->wl_compositor_name) { + if (registry->wl_compositor) { + wl_compositor_destroy(registry->wl_compositor); + registry->wl_compositor = nullptr; + } + + registry->wl_compositor_name = 0; + + return; + } + + if (name == registry->wl_subcompositor_name) { + if (registry->wl_subcompositor) { + wl_subcompositor_destroy(registry->wl_subcompositor); + registry->wl_subcompositor = nullptr; + } + + registry->wl_subcompositor_name = 0; + + return; + } + + if (name == registry->wl_data_device_manager_name) { + if (registry->wl_data_device_manager) { + wl_data_device_manager_destroy(registry->wl_data_device_manager); + registry->wl_data_device_manager = nullptr; + } + + registry->wl_data_device_manager_name = 0; + + // This global is used to create some seat data. Let's clean it. + for (struct wl_seat *wl_seat : registry->wl_seats) { + SeatState *ss = wl_seat_get_seat_state(wl_seat); + ERR_FAIL_NULL(ss); + + if (ss->wl_data_device) { + wl_data_device_destroy(ss->wl_data_device); + ss->wl_data_device = nullptr; + } + + ss->wl_data_device = nullptr; + } + + return; + } + + if (name == registry->xdg_wm_base_name) { + if (registry->xdg_wm_base) { + xdg_wm_base_destroy(registry->xdg_wm_base); + registry->xdg_wm_base = nullptr; + } + + registry->xdg_wm_base_name = 0; + + return; + } + + if (name == registry->wp_viewporter_name) { + WindowState *ws = ®istry->wayland_thread->main_window; + + if (registry->wp_viewporter) { + wp_viewporter_destroy(registry->wp_viewporter); + registry->wp_viewporter = nullptr; + } + + if (ws->wp_viewport) { + wp_viewport_destroy(ws->wp_viewport); + ws->wp_viewport = nullptr; + } + + registry->wp_viewporter_name = 0; + + return; + } + + if (name == registry->wp_fractional_scale_manager_name) { + WindowState *ws = ®istry->wayland_thread->main_window; + + if (registry->wp_fractional_scale_manager) { + wp_fractional_scale_manager_v1_destroy(registry->wp_fractional_scale_manager); + registry->wp_fractional_scale_manager = nullptr; + } + + if (ws->wp_fractional_scale) { + wp_fractional_scale_v1_destroy(ws->wp_fractional_scale); + ws->wp_fractional_scale = nullptr; + } + + registry->wp_fractional_scale_manager_name = 0; + } + + if (name == registry->xdg_decoration_manager_name) { + if (registry->xdg_decoration_manager) { + zxdg_decoration_manager_v1_destroy(registry->xdg_decoration_manager); + registry->xdg_decoration_manager = nullptr; + } + + registry->xdg_decoration_manager_name = 0; + + return; + } + + if (name == registry->xdg_activation_name) { + if (registry->xdg_activation) { + xdg_activation_v1_destroy(registry->xdg_activation); + registry->xdg_activation = nullptr; + } + + registry->xdg_activation_name = 0; + + return; + } + + if (name == registry->wp_primary_selection_device_manager_name) { + if (registry->wp_primary_selection_device_manager) { + zwp_primary_selection_device_manager_v1_destroy(registry->wp_primary_selection_device_manager); + registry->wp_primary_selection_device_manager = nullptr; + } + + registry->wp_primary_selection_device_manager_name = 0; + + // This global is used to create some seat data. Let's clean it. + for (struct wl_seat *wl_seat : registry->wl_seats) { + SeatState *ss = wl_seat_get_seat_state(wl_seat); + ERR_FAIL_NULL(ss); + + if (ss->wp_primary_selection_device) { + zwp_primary_selection_device_v1_destroy(ss->wp_primary_selection_device); + ss->wp_primary_selection_device = nullptr; + } + + if (ss->wp_primary_selection_source) { + zwp_primary_selection_source_v1_destroy(ss->wp_primary_selection_source); + ss->wp_primary_selection_source = nullptr; + } + + if (ss->wp_primary_selection_offer) { + memfree(wp_primary_selection_offer_get_offer_state(ss->wp_primary_selection_offer)); + zwp_primary_selection_offer_v1_destroy(ss->wp_primary_selection_offer); + ss->wp_primary_selection_offer = nullptr; + } + } + + return; + } + + if (name == registry->wp_relative_pointer_manager_name) { + if (registry->wp_relative_pointer_manager) { + zwp_relative_pointer_manager_v1_destroy(registry->wp_relative_pointer_manager); + registry->wp_relative_pointer_manager = nullptr; + } + + registry->wp_relative_pointer_manager_name = 0; + + // This global is used to create some seat data. Let's clean it. + for (struct wl_seat *wl_seat : registry->wl_seats) { + SeatState *ss = wl_seat_get_seat_state(wl_seat); + ERR_FAIL_NULL(ss); + + if (ss->wp_relative_pointer) { + zwp_relative_pointer_v1_destroy(ss->wp_relative_pointer); + ss->wp_relative_pointer = nullptr; + } + } + + return; + } + + if (name == registry->wp_pointer_constraints_name) { + if (registry->wp_pointer_constraints) { + zwp_pointer_constraints_v1_destroy(registry->wp_pointer_constraints); + registry->wp_pointer_constraints = nullptr; + } + + registry->wp_pointer_constraints_name = 0; + + // This global is used to create some seat data. Let's clean it. + for (struct wl_seat *wl_seat : registry->wl_seats) { + SeatState *ss = wl_seat_get_seat_state(wl_seat); + ERR_FAIL_NULL(ss); + + if (ss->wp_relative_pointer) { + zwp_relative_pointer_v1_destroy(ss->wp_relative_pointer); + ss->wp_relative_pointer = nullptr; + } + + if (ss->wp_locked_pointer) { + zwp_locked_pointer_v1_destroy(ss->wp_locked_pointer); + ss->wp_locked_pointer = nullptr; + } + + if (ss->wp_confined_pointer) { + zwp_confined_pointer_v1_destroy(ss->wp_confined_pointer); + ss->wp_confined_pointer = nullptr; + } + } + + return; + } + + if (name == registry->wp_pointer_gestures_name) { + if (registry->wp_pointer_gestures) { + zwp_pointer_gestures_v1_destroy(registry->wp_pointer_gestures); + } + + registry->wp_pointer_gestures = nullptr; + registry->wp_pointer_gestures_name = 0; + + // This global is used to create some seat data. Let's clean it. + for (struct wl_seat *wl_seat : registry->wl_seats) { + SeatState *ss = wl_seat_get_seat_state(wl_seat); + ERR_FAIL_NULL(ss); + + if (ss->wp_pointer_gesture_pinch) { + zwp_pointer_gesture_pinch_v1_destroy(ss->wp_pointer_gesture_pinch); + ss->wp_pointer_gesture_pinch = nullptr; + } + } + + return; + } + + if (name == registry->wp_idle_inhibit_manager_name) { + if (registry->wp_idle_inhibit_manager) { + zwp_idle_inhibit_manager_v1_destroy(registry->wp_idle_inhibit_manager); + registry->wp_idle_inhibit_manager = nullptr; + } + + registry->wp_idle_inhibit_manager_name = 0; + + return; + } + +#if 0 + // FIXME: Broken. + if (name == registry->wp_tablet_manager_name) { + if (registry->wp_tablet_manager) { + zwp_tablet_manager_v2_destroy(registry->wp_tablet_manager); + registry->wp_tablet_manager = nullptr; + } + + registry->wp_tablet_manager_name = 0; + + // This global is used to create some seat data. Let's clean it. + for (struct wl_seat *wl_seat : registry->wl_seats) { + SeatState *ss = wl_seat_get_seat_state(wl_seat); + ERR_FAIL_NULL(ss); + + List::Element *it = ss->tablet_tools.front(); + + while (it) { + zwp_tablet_tool_v2_destroy(it->get()); + ss->tablet_tools.erase(it); + + it = it->next(); + } + } + + return; + } +#endif + + { + // Iterate through all of the seats to find if any got removed. + List::Element *it = registry->wl_seats.front(); + while (it) { + struct wl_seat *wl_seat = it->get(); + + SeatState *ss = wl_seat_get_seat_state(wl_seat); + ERR_FAIL_NULL(ss); + + if (ss->wl_seat_name == name) { + if (wl_seat) { + wl_seat_destroy(wl_seat); + } + + if (ss->wl_data_device) { + wl_data_device_destroy(ss->wl_data_device); + } + +#if 0 + // FIXME: Broken. + if (ss->wp_tablet_seat) { + zwp_tablet_seat_v2_destroy(ss->wp_tablet_seat); + + for (struct zwp_tablet_tool_v2 *tool : ss->tablet_tools) { + zwp_tablet_tool_v2_destroy(tool); + } + } + + // Let's destroy all tools. + for (struct zwp_tablet_tool_v2 *tool : ss->tablet_tools) { + zwp_tablet_tool_v2_destroy(tool); + } + + memdelete(ss); + registry->wl_seats.erase(it); +#endif + return; + } + + it = it->next(); + } + } + + { + // Iterate through all of the outputs to find if any got removed. + // FIXME: This is a very bruteforce approach. + List::Element *it = registry->wl_outputs.front(); + while (it) { + // Iterate through all of the screens to find if any got removed. + struct wl_output *wl_output = it->get(); + ERR_FAIL_NULL(wl_output); + + ScreenState *ss = wl_output_get_screen_state(wl_output); + + if (ss->wl_output_name == name) { + registry->wl_outputs.erase(it); + + memdelete(ss); + wl_output_destroy(wl_output); + + return; + } + + it = it->next(); + } + } +} + +void WaylandThread::_wl_surface_on_enter(void *data, struct wl_surface *wl_surface, struct wl_output *wl_output) { + if (!wl_output || !wl_proxy_is_godot((struct wl_proxy *)wl_output)) { + // This won't have the right data bound to it. Not worth it and would probably + // just break everything. + return; + } + + WindowState *ws = (WindowState *)data; + ERR_FAIL_NULL(ws); + + DEBUG_LOG_WAYLAND_THREAD(vformat("Window entered output %x.\n", (size_t)wl_output)); + + ws->wl_outputs.insert(wl_output); + + // Workaround for buffer scaling as there's no guaranteed way of knowing the + // preferred scale. + // TODO: Skip this branch for newer `wl_surface`s once we add support for + // `wl_surface::preferred_buffer_scale` + if (ws->preferred_fractional_scale == 0) { + window_state_update_size(ws, ws->rect.size.width, ws->rect.size.height); + } +} + +void WaylandThread::_frame_wl_callback_on_done(void *data, struct wl_callback *wl_callback, uint32_t callback_data) { + wl_callback_destroy(wl_callback); + + WindowState *ws = (WindowState *)data; + ERR_FAIL_NULL(ws); + ERR_FAIL_NULL(ws->wayland_thread); + ERR_FAIL_NULL(ws->wl_surface); + + ws->wayland_thread->set_frame(); + + ws->frame_callback = wl_surface_frame(ws->wl_surface), + wl_callback_add_listener(ws->frame_callback, &frame_wl_callback_listener, ws); + wl_surface_commit(ws->wl_surface); + + if (ws->wl_surface && ws->buffer_scale_changed) { + // NOTE: We're only now setting the buffer scale as the idea is to get this + // data committed together with the new frame, all by the rendering driver. + // This is important because we might otherwise set an invalid combination of + // buffer size and scale (e.g. odd size and 2x scale). We're pretty much + // guaranteed to get a proper buffer in the next render loop as the rescaling + // method also informs the engine of a "window rect change", triggering + // rendering if needed. + wl_surface_set_buffer_scale(ws->wl_surface, window_state_get_preferred_buffer_scale(ws)); + } + + // NOTE: Remember to set here also other buffer-dependent states (e.g. opaque + // region) if used, to be as close as possible to an atomic surface update. + // Ideally we'd only have one surface commit, but it's not really doable given + // the current state of things. +} + +void WaylandThread::_wl_surface_on_leave(void *data, struct wl_surface *wl_surface, struct wl_output *wl_output) { + if (!wl_output || !wl_proxy_is_godot((struct wl_proxy *)wl_output)) { + // This won't have the right data bound to it. Not worth it and would probably + // just break everything. + return; + } + + WindowState *ws = (WindowState *)data; + ERR_FAIL_NULL(ws); + + ws->wl_outputs.erase(wl_output); + + DEBUG_LOG_WAYLAND_THREAD(vformat("Window left output %x.\n", (size_t)wl_output)); +} + +void WaylandThread::_wl_output_on_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char *make, const char *model, int32_t transform) { + ScreenState *ss = (ScreenState *)data; + ERR_FAIL_NULL(ss); + + ss->pending_data.position.x = x; + + ss->pending_data.position.x = x; + ss->pending_data.position.y = y; + + ss->pending_data.physical_size.width = physical_width; + ss->pending_data.physical_size.height = physical_height; + + ss->pending_data.make.parse_utf8(make); + ss->pending_data.model.parse_utf8(model); +} + +void WaylandThread::_wl_output_on_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { + ScreenState *ss = (ScreenState *)data; + ERR_FAIL_NULL(ss); + + ss->pending_data.size.width = width; + ss->pending_data.size.height = height; + + ss->pending_data.refresh_rate = refresh ? refresh / 1000.0f : -1; +} + +void WaylandThread::_wl_output_on_done(void *data, struct wl_output *wl_output) { + ScreenState *ss = (ScreenState *)data; + ERR_FAIL_NULL(ss); + + ss->data = ss->pending_data; + + ss->wayland_thread->_update_scale(ss->data.scale); + + DEBUG_LOG_WAYLAND_THREAD(vformat("Output %x done.", (size_t)wl_output)); +} + +void WaylandThread::_wl_output_on_scale(void *data, struct wl_output *wl_output, int32_t factor) { + ScreenState *ss = (ScreenState *)data; + ERR_FAIL_NULL(ss); + + ss->pending_data.scale = factor; + + DEBUG_LOG_WAYLAND_THREAD(vformat("Output %x scale %d", (size_t)wl_output, factor)); +} + +void WaylandThread::_wl_output_on_name(void *data, struct wl_output *wl_output, const char *name) { +} + +void WaylandThread::_wl_output_on_description(void *data, struct wl_output *wl_output, const char *description) { +} + +void WaylandThread::_xdg_wm_base_on_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial) { + xdg_wm_base_pong(xdg_wm_base, serial); +} + +void WaylandThread::_xdg_surface_on_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial) { + xdg_surface_ack_configure(xdg_surface, serial); + + WindowState *ws = (WindowState *)data; + ERR_FAIL_NULL(ws); + + DEBUG_LOG_WAYLAND_THREAD(vformat("xdg surface on configure width %d height %d", ws->rect.size.width, ws->rect.size.height)); +} + +void WaylandThread::_xdg_toplevel_on_configure(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *states) { + WindowState *ws = (WindowState *)data; + ERR_FAIL_NULL(ws); + + // Expect the window to be in windowed mode. The mode will get overridden if + // the compositor reports otherwise. + ws->mode = DisplayServer::WINDOW_MODE_WINDOWED; + + uint32_t *state = nullptr; + wl_array_for_each(state, states) { + switch (*state) { + case XDG_TOPLEVEL_STATE_MAXIMIZED: { + ws->mode = DisplayServer::WINDOW_MODE_MAXIMIZED; + } break; + + case XDG_TOPLEVEL_STATE_FULLSCREEN: { + ws->mode = DisplayServer::WINDOW_MODE_FULLSCREEN; + } break; + + default: { + // We don't care about the other states (for now). + } break; + } + } + + if (width != 0 && height != 0) { + window_state_update_size(ws, width, height); + } + + DEBUG_LOG_WAYLAND_THREAD(vformat("XDG toplevel on configure width %d height %d.", width, height)); +} + +void WaylandThread::_xdg_toplevel_on_close(void *data, struct xdg_toplevel *xdg_toplevel) { + WindowState *ws = (WindowState *)data; + ERR_FAIL_NULL(ws); + + Ref msg; + msg.instantiate(); + msg->event = DisplayServer::WINDOW_EVENT_CLOSE_REQUEST; + ws->wayland_thread->push_message(msg); +} + +void WaylandThread::_xdg_toplevel_on_configure_bounds(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) { +} + +void WaylandThread::_xdg_toplevel_on_wm_capabilities(void *data, struct xdg_toplevel *xdg_toplevel, struct wl_array *capabilities) { + WindowState *ws = (WindowState *)data; + ERR_FAIL_NULL(ws); + + ws->can_maximize = false; + ws->can_fullscreen = false; + ws->can_minimize = false; + + uint32_t *capability = nullptr; + wl_array_for_each(capability, capabilities) { + switch (*capability) { + case XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE: { + ws->can_maximize = true; + } break; + case XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN: { + ws->can_fullscreen = true; + } break; + + case XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE: { + ws->can_minimize = true; + } break; + + default: { + } break; + } + } +} + +void WaylandThread::_xdg_toplevel_decoration_on_configure(void *data, struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration, uint32_t mode) { + if (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE) { +#ifdef LIBDECOR_ENABLED + WARN_PRINT_ONCE("Native client side decorations are not yet supported without libdecor!"); +#else + WARN_PRINT_ONCE("Native client side decorations are not yet supported!"); +#endif // LIBDECOR_ENABLED + } +} + +#ifdef LIBDECOR_ENABLED +void WaylandThread::libdecor_on_error(struct libdecor *context, enum libdecor_error error, const char *message) { + ERR_PRINT(vformat("libdecor error %d: %s", error, message)); +} + +// NOTE: This is pretty much a reimplementation of _xdg_surface_on_configure +// and _xdg_toplevel_on_configure. Libdecor really likes wrapping everything, +// forcing us to do stuff like this. +void WaylandThread::libdecor_frame_on_configure(struct libdecor_frame *frame, struct libdecor_configuration *configuration, void *user_data) { + WindowState *ws = (WindowState *)user_data; + ERR_FAIL_NULL(ws); + + int width = 0; + int height = 0; + + ws->pending_libdecor_configuration = configuration; + + if (!libdecor_configuration_get_content_size(configuration, frame, &width, &height)) { + // The configuration doesn't have a size. We'll use the one already set in the window. + width = ws->rect.size.width; + height = ws->rect.size.height; + } + + ERR_FAIL_COND_MSG(width == 0 || height == 0, "Window has invalid size."); + + libdecor_window_state window_state = LIBDECOR_WINDOW_STATE_NONE; + + // Expect the window to be in windowed mode. The mode will get overridden if + // the compositor reports otherwise. + ws->mode = DisplayServer::WINDOW_MODE_WINDOWED; + + if (libdecor_configuration_get_window_state(configuration, &window_state)) { + if (window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED) { + ws->mode = DisplayServer::WINDOW_MODE_MAXIMIZED; + } + + if (window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN) { + ws->mode = DisplayServer::WINDOW_MODE_FULLSCREEN; + } + } + + window_state_update_size(ws, width, height); + + DEBUG_LOG_WAYLAND_THREAD(vformat("libdecor frame on configure rect %s", ws->rect)); +} + +void WaylandThread::libdecor_frame_on_close(struct libdecor_frame *frame, void *user_data) { + WindowState *ws = (WindowState *)user_data; + ERR_FAIL_NULL(ws); + + Ref winevent_msg; + winevent_msg.instantiate(); + winevent_msg->event = DisplayServer::WINDOW_EVENT_CLOSE_REQUEST; + + ws->wayland_thread->push_message(winevent_msg); + + DEBUG_LOG_WAYLAND_THREAD("libdecor frame on close"); +} + +void WaylandThread::libdecor_frame_on_commit(struct libdecor_frame *frame, void *user_data) { + // We're skipping this as we don't really care about libdecor's commit for + // atomicity reasons. See `_frame_wl_callback_on_done` for more info. + + DEBUG_LOG_WAYLAND_THREAD("libdecor frame on commit"); +} + +void WaylandThread::libdecor_frame_on_dismiss_popup(struct libdecor_frame *frame, const char *seat_name, void *user_data) { +} +#endif // LIBDECOR_ENABLED + +void WaylandThread::_wl_seat_on_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities) { + SeatState *ss = (SeatState *)data; + + ERR_FAIL_NULL(ss); + + // TODO: Handle touch. + + // Pointer handling. + if (capabilities & WL_SEAT_CAPABILITY_POINTER) { + ss->cursor_surface = wl_compositor_create_surface(ss->registry->wl_compositor); + ss->cursor_frame_callback = wl_surface_frame(ss->cursor_surface); + wl_callback_add_listener(ss->cursor_frame_callback, &cursor_frame_callback_listener, ss); + wl_surface_commit(ss->cursor_surface); + + ss->wl_pointer = wl_seat_get_pointer(wl_seat); + wl_pointer_add_listener(ss->wl_pointer, &wl_pointer_listener, ss); + + if (ss->registry->wp_relative_pointer_manager) { + ss->wp_relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(ss->registry->wp_relative_pointer_manager, ss->wl_pointer); + zwp_relative_pointer_v1_add_listener(ss->wp_relative_pointer, &wp_relative_pointer_listener, ss); + } + + if (ss->registry->wp_pointer_gestures) { + ss->wp_pointer_gesture_pinch = zwp_pointer_gestures_v1_get_pinch_gesture(ss->registry->wp_pointer_gestures, ss->wl_pointer); + zwp_pointer_gesture_pinch_v1_add_listener(ss->wp_pointer_gesture_pinch, &wp_pointer_gesture_pinch_listener, ss); + } + + // TODO: Constrain new pointers if the global mouse mode is constrained. + } else { + if (ss->cursor_frame_callback) { + // Just in case. I got bitten by weird race-like conditions already. + wl_callback_set_user_data(ss->cursor_frame_callback, nullptr); + + wl_callback_destroy(ss->cursor_frame_callback); + ss->cursor_frame_callback = nullptr; + } + + if (ss->cursor_surface) { + wl_surface_destroy(ss->cursor_surface); + ss->cursor_surface = nullptr; + } + + if (ss->wl_pointer) { + wl_pointer_destroy(ss->wl_pointer); + ss->wl_pointer = nullptr; + } + + if (ss->wp_relative_pointer) { + zwp_relative_pointer_v1_destroy(ss->wp_relative_pointer); + ss->wp_relative_pointer = nullptr; + } + + if (ss->wp_confined_pointer) { + zwp_confined_pointer_v1_destroy(ss->wp_confined_pointer); + ss->wp_confined_pointer = nullptr; + } + + if (ss->wp_locked_pointer) { + zwp_locked_pointer_v1_destroy(ss->wp_locked_pointer); + ss->wp_locked_pointer = nullptr; + } + } + + // Keyboard handling. + if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { + ss->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + ERR_FAIL_NULL(ss->xkb_context); + + ss->wl_keyboard = wl_seat_get_keyboard(wl_seat); + wl_keyboard_add_listener(ss->wl_keyboard, &wl_keyboard_listener, ss); + } else { + if (ss->xkb_context) { + xkb_context_unref(ss->xkb_context); + ss->xkb_context = nullptr; + } + + if (ss->wl_keyboard) { + wl_keyboard_destroy(ss->wl_keyboard); + ss->wl_keyboard = nullptr; + } + } +} + +void WaylandThread::_wl_seat_on_name(void *data, struct wl_seat *wl_seat, const char *name) { +} + +void WaylandThread::_cursor_frame_callback_on_done(void *data, struct wl_callback *wl_callback, uint32_t time_ms) { + wl_callback_destroy(wl_callback); + + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + ss->cursor_time_ms = time_ms; + + ss->cursor_frame_callback = wl_surface_frame(ss->cursor_surface); + wl_callback_add_listener(ss->cursor_frame_callback, &cursor_frame_callback_listener, ss); + wl_surface_commit(ss->cursor_surface); + + seat_state_update_cursor(ss); +} + +void WaylandThread::_wl_pointer_on_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { + if (!surface || !wl_proxy_is_godot((struct wl_proxy *)surface)) { + return; + } + + DEBUG_LOG_WAYLAND_THREAD("Pointing window."); + + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + ERR_FAIL_NULL(ss->cursor_surface); + ss->pointer_enter_serial = serial; + ss->pointed_surface = surface; + ss->last_pointed_surface = surface; + + seat_state_update_cursor(ss); + + Ref msg; + msg.instantiate(); + msg->event = DisplayServer::WINDOW_EVENT_MOUSE_ENTER; + + ss->wayland_thread->push_message(msg); +} + +void WaylandThread::_wl_pointer_on_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface) { + if (!surface || !wl_proxy_is_godot((struct wl_proxy *)surface)) { + return; + } + + DEBUG_LOG_WAYLAND_THREAD("Left window."); + + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + WaylandThread *wayland_thread = ss->wayland_thread; + ERR_FAIL_NULL(wayland_thread); + + ss->pointed_surface = nullptr; + + Ref msg; + msg.instantiate(); + msg->event = DisplayServer::WINDOW_EVENT_MOUSE_EXIT; + + wayland_thread->push_message(msg); +} + +void WaylandThread::_wl_pointer_on_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + if (!ss->pointed_surface) { + // We're probably on a decoration or some other third-party thing. + return; + } + + WindowState *ws = wl_surface_get_window_state(ss->pointed_surface); + ERR_FAIL_NULL(ws); + + PointerData &pd = ss->pointer_data_buffer; + + // TODO: Scale only when sending the Wayland message. + pd.position.x = wl_fixed_to_int(surface_x); + pd.position.y = wl_fixed_to_int(surface_y); + + pd.position = scale_vector2i(pd.position, window_state_get_scale_factor(ws)); + + pd.motion_time = time; +} + +void WaylandThread::_wl_pointer_on_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + if (!ss->pointed_surface) { + // We're probably on a decoration or some other third-party thing. + return; + } + + PointerData &pd = ss->pointer_data_buffer; + + MouseButton button_pressed = MouseButton::NONE; + + switch (button) { + case BTN_LEFT: + button_pressed = MouseButton::LEFT; + break; + + case BTN_MIDDLE: + button_pressed = MouseButton::MIDDLE; + break; + + case BTN_RIGHT: + button_pressed = MouseButton::RIGHT; + break; + + case BTN_EXTRA: + button_pressed = MouseButton::MB_XBUTTON1; + break; + + case BTN_SIDE: + button_pressed = MouseButton::MB_XBUTTON2; + break; + + default: { + } + } + + MouseButtonMask mask = mouse_button_to_mask(button_pressed); + + if (state & WL_POINTER_BUTTON_STATE_PRESSED) { + pd.pressed_button_mask.set_flag(mask); + pd.last_button_pressed = button_pressed; + pd.double_click_begun = true; + } else { + pd.pressed_button_mask.clear_flag(mask); + } + + pd.button_time = time; + pd.button_serial = serial; +} + +void WaylandThread::_wl_pointer_on_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + if (!ss->pointed_surface) { + // We're probably on a decoration or some other third-party thing. + return; + } + + PointerData &pd = ss->pointer_data_buffer; + + switch (axis) { + case WL_POINTER_AXIS_VERTICAL_SCROLL: { + pd.scroll_vector.y = wl_fixed_to_double(value); + } break; + + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: { + pd.scroll_vector.x = wl_fixed_to_double(value); + } break; + } + + pd.button_time = time; +} + +void WaylandThread::_wl_pointer_on_frame(void *data, struct wl_pointer *wl_pointer) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + if (!ss->pointed_surface) { + // We're probably on a decoration or some other third-party thing. + return; + } + + WaylandThread *wayland_thread = ss->wayland_thread; + ERR_FAIL_NULL(wayland_thread); + + wayland_thread->_set_current_seat(ss->wl_seat); + + PointerData &old_pd = ss->pointer_data; + PointerData &pd = ss->pointer_data_buffer; + + if (old_pd.motion_time != pd.motion_time || old_pd.relative_motion_time != pd.relative_motion_time) { + Ref mm; + mm.instantiate(); + + // Set all pressed modifiers. + mm->set_shift_pressed(ss->shift_pressed); + mm->set_ctrl_pressed(ss->ctrl_pressed); + mm->set_alt_pressed(ss->alt_pressed); + mm->set_meta_pressed(ss->meta_pressed); + + mm->set_window_id(DisplayServer::MAIN_WINDOW_ID); + mm->set_button_mask(pd.pressed_button_mask); + mm->set_position(pd.position); + mm->set_global_position(pd.position); + + Vector2i pos_delta = pd.position - old_pd.position; + + if (old_pd.relative_motion_time != pd.relative_motion_time) { + uint32_t time_delta = pd.relative_motion_time - old_pd.relative_motion_time; + + mm->set_relative(pd.relative_motion); + mm->set_velocity((Vector2)pos_delta / time_delta); + } else { + // The spec includes the possibility of having motion events without an + // associated relative motion event. If that's the case, fallback to a + // simple delta of the position. The captured mouse won't report the + // relative speed anymore though. + uint32_t time_delta = pd.motion_time - old_pd.motion_time; + + mm->set_relative(pd.position - old_pd.position); + mm->set_velocity((Vector2)pos_delta / time_delta); + } + + Ref msg; + msg.instantiate(); + + msg->event = mm; + + wayland_thread->push_message(msg); + } + + if (pd.discrete_scroll_vector - old_pd.discrete_scroll_vector != Vector2i()) { + // This is a discrete scroll (eg. from a scroll wheel), so we'll just emit + // scroll wheel buttons. + if (pd.scroll_vector.y != 0) { + MouseButton button = pd.scroll_vector.y > 0 ? MouseButton::WHEEL_DOWN : MouseButton::WHEEL_UP; + pd.pressed_button_mask.set_flag(mouse_button_to_mask(button)); + } + + if (pd.scroll_vector.x != 0) { + MouseButton button = pd.scroll_vector.x > 0 ? MouseButton::WHEEL_RIGHT : MouseButton::WHEEL_LEFT; + pd.pressed_button_mask.set_flag(mouse_button_to_mask(button)); + } + } else { + if (pd.scroll_vector - old_pd.scroll_vector != Vector2()) { + // This is a continuous scroll, so we'll emit a pan gesture. + Ref pg; + pg.instantiate(); + + // Set all pressed modifiers. + pg->set_shift_pressed(ss->shift_pressed); + pg->set_ctrl_pressed(ss->ctrl_pressed); + pg->set_alt_pressed(ss->alt_pressed); + pg->set_meta_pressed(ss->meta_pressed); + + pg->set_position(pd.position); + + pg->set_window_id(DisplayServer::MAIN_WINDOW_ID); + + pg->set_delta(pd.scroll_vector); + + Ref msg; + msg.instantiate(); + + msg->event = pg; + + wayland_thread->push_message(msg); + } + } + + if (old_pd.pressed_button_mask != pd.pressed_button_mask) { + BitField pressed_mask_delta = BitField((uint32_t)old_pd.pressed_button_mask ^ (uint32_t)pd.pressed_button_mask); + + const MouseButton buttons_to_test[] = { + MouseButton::LEFT, + MouseButton::MIDDLE, + MouseButton::RIGHT, + MouseButton::WHEEL_UP, + MouseButton::WHEEL_DOWN, + MouseButton::WHEEL_LEFT, + MouseButton::WHEEL_RIGHT, + MouseButton::MB_XBUTTON1, + MouseButton::MB_XBUTTON2, + }; + + for (MouseButton test_button : buttons_to_test) { + MouseButtonMask test_button_mask = mouse_button_to_mask(test_button); + if (pressed_mask_delta.has_flag(test_button_mask)) { + Ref mb; + mb.instantiate(); + + // Set all pressed modifiers. + mb->set_shift_pressed(ss->shift_pressed); + mb->set_ctrl_pressed(ss->ctrl_pressed); + mb->set_alt_pressed(ss->alt_pressed); + mb->set_meta_pressed(ss->meta_pressed); + + mb->set_window_id(DisplayServer::MAIN_WINDOW_ID); + mb->set_position(pd.position); + mb->set_global_position(pd.position); + + if (test_button == MouseButton::WHEEL_UP || test_button == MouseButton::WHEEL_DOWN) { + // If this is a discrete scroll, specify how many "clicks" it did for this + // pointer frame. + mb->set_factor(abs(pd.discrete_scroll_vector.y)); + } + + if (test_button == MouseButton::WHEEL_RIGHT || test_button == MouseButton::WHEEL_LEFT) { + // If this is a discrete scroll, specify how many "clicks" it did for this + // pointer frame. + mb->set_factor(abs(pd.discrete_scroll_vector.x)); + } + + mb->set_button_mask(pd.pressed_button_mask); + + mb->set_button_index(test_button); + mb->set_pressed(pd.pressed_button_mask.has_flag(test_button_mask)); + + // We have to set the last position pressed here as we can't take for + // granted what the individual events might have seen due to them not having + // a garaunteed order. + if (mb->is_pressed()) { + pd.last_pressed_position = pd.position; + } + + if (old_pd.double_click_begun && mb->is_pressed() && pd.last_button_pressed == old_pd.last_button_pressed && (pd.button_time - old_pd.button_time) < 400 && Vector2(old_pd.last_pressed_position).distance_to(Vector2(pd.last_pressed_position)) < 5) { + pd.double_click_begun = false; + mb->set_double_click(true); + } + + Ref msg; + msg.instantiate(); + + msg->event = mb; + + wayland_thread->push_message(msg); + + // Send an event resetting immediately the wheel key. + // Wayland specification defines axis_stop events as optional and says to + // treat all axis events as unterminated. As such, we have to manually do + // it ourselves. + if (test_button == MouseButton::WHEEL_UP || test_button == MouseButton::WHEEL_DOWN || test_button == MouseButton::WHEEL_LEFT || test_button == MouseButton::WHEEL_RIGHT) { + // FIXME: This is ugly, I can't find a clean way to clone an InputEvent. + // This works for now, despite being horrible. + Ref wh_up; + wh_up.instantiate(); + + wh_up->set_window_id(DisplayServer::MAIN_WINDOW_ID); + wh_up->set_position(pd.position); + wh_up->set_global_position(pd.position); + + // We have to unset the button to avoid it getting stuck. + pd.pressed_button_mask.clear_flag(test_button_mask); + wh_up->set_button_mask(pd.pressed_button_mask); + + wh_up->set_button_index(test_button); + wh_up->set_pressed(false); + + Ref msg_up; + msg_up.instantiate(); + msg_up->event = wh_up; + wayland_thread->push_message(msg_up); + } + } + } + } + + // Reset the scroll vectors as we already handled them. + pd.scroll_vector = Vector2(); + pd.discrete_scroll_vector = Vector2(); + + // Update the data all getters read. Wayland's specification requires us to do + // this, since all pointer actions are sent in individual events. + old_pd = pd; +} + +void WaylandThread::_wl_pointer_on_axis_source(void *data, struct wl_pointer *wl_pointer, uint32_t axis_source) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + if (!ss->pointed_surface) { + // We're probably on a decoration or some other third-party thing. + return; + } + + ss->pointer_data_buffer.scroll_type = axis_source; +} + +void WaylandThread::_wl_pointer_on_axis_stop(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis) { +} + +void WaylandThread::_wl_pointer_on_axis_discrete(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + if (!ss->pointed_surface) { + // We're probably on a decoration or some other third-party thing. + return; + } + + PointerData &pd = ss->pointer_data_buffer; + + if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { + pd.discrete_scroll_vector.y = discrete; + } + + if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { + pd.discrete_scroll_vector.x = discrete; + } +} + +// TODO: Add support to this event. +void WaylandThread::_wl_pointer_on_axis_value120(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t value120) { +} + +void WaylandThread::_wl_keyboard_on_keymap(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size) { + ERR_FAIL_COND_MSG(format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, "Unsupported keymap format announced from the Wayland compositor."); + + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + if (ss->keymap_buffer) { + // We have already a mapped buffer, so we unmap it. There's no need to reset + // its pointer or size, as we're gonna set them below. + munmap((void *)ss->keymap_buffer, ss->keymap_buffer_size); + ss->keymap_buffer = nullptr; + } + + ss->keymap_buffer = (const char *)mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + ss->keymap_buffer_size = size; + + xkb_keymap_unref(ss->xkb_keymap); + ss->xkb_keymap = xkb_keymap_new_from_string(ss->xkb_context, ss->keymap_buffer, + XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + + xkb_state_unref(ss->xkb_state); + ss->xkb_state = xkb_state_new(ss->xkb_keymap); +} + +void WaylandThread::_wl_keyboard_on_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + WaylandThread *wayland_thread = ss->wayland_thread; + ERR_FAIL_NULL(wayland_thread); + + wayland_thread->_set_current_seat(ss->wl_seat); + + Ref msg; + msg.instantiate(); + msg->event = DisplayServer::WINDOW_EVENT_FOCUS_IN; + wayland_thread->push_message(msg); +} + +void WaylandThread::_wl_keyboard_on_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + WaylandThread *wayland_thread = ss->wayland_thread; + ERR_FAIL_NULL(wayland_thread); + + ss->repeating_keycode = XKB_KEYCODE_INVALID; + + Ref msg; + msg.instantiate(); + msg->event = DisplayServer::WINDOW_EVENT_FOCUS_OUT; + wayland_thread->push_message(msg); +} + +void WaylandThread::_wl_keyboard_on_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + WaylandThread *wayland_thread = ss->wayland_thread; + ERR_FAIL_NULL(wayland_thread); + + // We have to add 8 to the scancode to get an XKB-compatible keycode. + xkb_keycode_t xkb_keycode = key + 8; + + bool pressed = state & WL_KEYBOARD_KEY_STATE_PRESSED; + + if (pressed) { + if (xkb_keymap_key_repeats(ss->xkb_keymap, xkb_keycode)) { + ss->last_repeat_start_msec = OS::get_singleton()->get_ticks_msec(); + ss->repeating_keycode = xkb_keycode; + } + + ss->last_key_pressed_serial = serial; + } else if (ss->repeating_keycode == xkb_keycode) { + ss->repeating_keycode = XKB_KEYCODE_INVALID; + } + + Ref k; + k.instantiate(); + + if (!_seat_state_configure_key_event(*ss, k, xkb_keycode, pressed)) { + return; + } + + Ref msg; + msg.instantiate(); + msg->event = k; + wayland_thread->push_message(msg); +} + +void WaylandThread::_wl_keyboard_on_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + xkb_state_update_mask(ss->xkb_state, mods_depressed, mods_latched, mods_locked, ss->current_layout_index, ss->current_layout_index, group); + + ss->shift_pressed = xkb_state_mod_name_is_active(ss->xkb_state, XKB_MOD_NAME_SHIFT, XKB_STATE_MODS_DEPRESSED); + ss->ctrl_pressed = xkb_state_mod_name_is_active(ss->xkb_state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_DEPRESSED); + ss->alt_pressed = xkb_state_mod_name_is_active(ss->xkb_state, XKB_MOD_NAME_ALT, XKB_STATE_MODS_DEPRESSED); + ss->meta_pressed = xkb_state_mod_name_is_active(ss->xkb_state, XKB_MOD_NAME_LOGO, XKB_STATE_MODS_DEPRESSED); + + ss->current_layout_index = group; +} + +void WaylandThread::_wl_keyboard_on_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + ss->repeat_key_delay_msec = 1000 / rate; + ss->repeat_start_delay_msec = delay; +} + +// NOTE: Don't forget to `memfree` the offer's state. +void WaylandThread::_wl_data_device_on_data_offer(void *data, struct wl_data_device *wl_data_device, struct wl_data_offer *id) { + wl_proxy_tag_godot((struct wl_proxy *)id); + wl_data_offer_add_listener(id, &wl_data_offer_listener, memnew(OfferState)); +} + +void WaylandThread::_wl_data_device_on_enter(void *data, struct wl_data_device *wl_data_device, uint32_t serial, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *id) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + ss->dnd_enter_serial = serial; + ss->wl_data_offer_dnd = id; + + // Godot only supports DnD file copying for now. + wl_data_offer_accept(id, serial, "text/uri-list"); + wl_data_offer_set_actions(id, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY); +} + +void WaylandThread::_wl_data_device_on_leave(void *data, struct wl_data_device *wl_data_device) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + if (ss->wl_data_offer_dnd) { + memdelete(wl_data_offer_get_offer_state(ss->wl_data_offer_dnd)); + wl_data_offer_destroy(ss->wl_data_offer_dnd); + ss->wl_data_offer_dnd = nullptr; + } +} + +void WaylandThread::_wl_data_device_on_motion(void *data, struct wl_data_device *wl_data_device, uint32_t time, wl_fixed_t x, wl_fixed_t y) { +} + +void WaylandThread::_wl_data_device_on_drop(void *data, struct wl_data_device *wl_data_device) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + WaylandThread *wayland_thread = ss->wayland_thread; + ERR_FAIL_NULL(wayland_thread); + + OfferState *os = wl_data_offer_get_offer_state(ss->wl_data_offer_dnd); + ERR_FAIL_NULL(os); + + if (os) { + Ref msg; + msg.instantiate(); + + Vector list_data = _wl_data_offer_read(wayland_thread->wl_display, "text/uri-list", ss->wl_data_offer_dnd); + + msg->files = String::utf8((const char *)list_data.ptr(), list_data.size()).split("\r\n", false); + for (int i = 0; i < msg->files.size(); i++) { + msg->files.write[i] = msg->files[i].replace("file://", "").uri_decode(); + } + + wayland_thread->push_message(msg); + + wl_data_offer_finish(ss->wl_data_offer_dnd); + } + + memdelete(wl_data_offer_get_offer_state(ss->wl_data_offer_dnd)); + wl_data_offer_destroy(ss->wl_data_offer_dnd); + ss->wl_data_offer_dnd = nullptr; +} + +void WaylandThread::_wl_data_device_on_selection(void *data, struct wl_data_device *wl_data_device, struct wl_data_offer *id) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + if (ss->wl_data_offer_selection) { + memdelete(wl_data_offer_get_offer_state(ss->wl_data_offer_selection)); + wl_data_offer_destroy(ss->wl_data_offer_selection); + } + + ss->wl_data_offer_selection = id; +} + +void WaylandThread::_wl_data_offer_on_offer(void *data, struct wl_data_offer *wl_data_offer, const char *mime_type) { + OfferState *os = (OfferState *)data; + ERR_FAIL_NULL(os); + + if (os) { + os->mime_types.insert(String::utf8(mime_type)); + } +} + +void WaylandThread::_wl_data_offer_on_source_actions(void *data, struct wl_data_offer *wl_data_offer, uint32_t source_actions) { +} + +void WaylandThread::_wl_data_offer_on_action(void *data, struct wl_data_offer *wl_data_offer, uint32_t dnd_action) { +} + +void WaylandThread::_wl_data_source_on_target(void *data, struct wl_data_source *wl_data_source, const char *mime_type) { +} + +void WaylandThread::_wl_data_source_on_send(void *data, struct wl_data_source *wl_data_source, const char *mime_type, int32_t fd) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + Vector *data_to_send = nullptr; + + if (wl_data_source == ss->wl_data_source_selection) { + data_to_send = &ss->selection_data; + DEBUG_LOG_WAYLAND_THREAD("Clipboard: requested selection."); + } + + if (data_to_send) { + ssize_t written_bytes = 0; + + bool valid_mime = false; + + if (strcmp(mime_type, "text/plain;charset=utf-8") == 0) { + valid_mime = true; + } else if (strcmp(mime_type, "text/plain") == 0) { + valid_mime = true; + } + + if (valid_mime) { + written_bytes = write(fd, data_to_send->ptr(), data_to_send->size()); + } + + if (written_bytes > 0) { + DEBUG_LOG_WAYLAND_THREAD(vformat("Clipboard: sent %d bytes.", written_bytes)); + } else if (written_bytes == 0) { + DEBUG_LOG_WAYLAND_THREAD("Clipboard: no bytes sent."); + } else { + ERR_PRINT(vformat("Clipboard: write error %d.", errno)); + } + } + + close(fd); +} + +void WaylandThread::_wl_data_source_on_cancelled(void *data, struct wl_data_source *wl_data_source) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + wl_data_source_destroy(wl_data_source); + + if (wl_data_source == ss->wl_data_source_selection) { + ss->wl_data_source_selection = nullptr; + ss->selection_data.clear(); + + DEBUG_LOG_WAYLAND_THREAD("Clipboard: selection set by another program."); + return; + } +} + +void WaylandThread::_wl_data_source_on_dnd_drop_performed(void *data, struct wl_data_source *wl_data_source) { +} + +void WaylandThread::_wl_data_source_on_dnd_finished(void *data, struct wl_data_source *wl_data_source) { +} + +void WaylandThread::_wl_data_source_on_action(void *data, struct wl_data_source *wl_data_source, uint32_t dnd_action) { +} + +void WaylandThread::_wp_fractional_scale_on_preferred_scale(void *data, struct wp_fractional_scale_v1 *wp_fractional_scale_v1, uint32_t scale) { + WindowState *ws = (WindowState *)data; + ERR_FAIL_NULL(ws); + + ws->preferred_fractional_scale = (double)scale / 120; + + window_state_update_size(ws, ws->rect.size.width, ws->rect.size.height); +} + +void WaylandThread::_wp_relative_pointer_on_relative_motion(void *data, struct zwp_relative_pointer_v1 *wp_relative_pointer, uint32_t uptime_hi, uint32_t uptime_lo, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + PointerData &pd = ss->pointer_data_buffer; + + pd.relative_motion.x = wl_fixed_to_double(dx); + pd.relative_motion.y = wl_fixed_to_double(dy); + + pd.relative_motion_time = uptime_lo; +} + +void WaylandThread::_wp_pointer_gesture_pinch_on_begin(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, struct wl_surface *surface, uint32_t fingers) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + if (fingers == 2) { + ss->old_pinch_scale = wl_fixed_from_int(1); + ss->active_gesture = Gesture::MAGNIFY; + } +} + +void WaylandThread::_wp_pointer_gesture_pinch_on_update(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t time, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t scale, wl_fixed_t rotation) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + WaylandThread *wayland_thread = ss->wayland_thread; + ERR_FAIL_NULL(wayland_thread); + + PointerData &pd = ss->pointer_data_buffer; + + if (ss->active_gesture == Gesture::MAGNIFY) { + Ref mg; + mg.instantiate(); + + mg->set_window_id(DisplayServer::MAIN_WINDOW_ID); + + // Set all pressed modifiers. + mg->set_shift_pressed(ss->shift_pressed); + mg->set_ctrl_pressed(ss->ctrl_pressed); + mg->set_alt_pressed(ss->alt_pressed); + mg->set_meta_pressed(ss->meta_pressed); + + mg->set_position(pd.position); + + wl_fixed_t scale_delta = scale - ss->old_pinch_scale; + mg->set_factor(1 + wl_fixed_to_double(scale_delta)); + + Ref magnify_msg; + magnify_msg.instantiate(); + magnify_msg->event = mg; + + // Since Wayland allows only one gesture at a time and godot instead expects + // both of them, we'll have to create two separate input events: one for + // magnification and one for panning. + + Ref pg; + pg.instantiate(); + + pg->set_window_id(DisplayServer::MAIN_WINDOW_ID); + + // Set all pressed modifiers. + pg->set_shift_pressed(ss->shift_pressed); + pg->set_ctrl_pressed(ss->ctrl_pressed); + pg->set_alt_pressed(ss->alt_pressed); + pg->set_meta_pressed(ss->meta_pressed); + + pg->set_position(pd.position); + pg->set_delta(Vector2(wl_fixed_to_double(dx), wl_fixed_to_double(dy))); + + Ref pan_msg; + pan_msg.instantiate(); + pan_msg->event = pg; + + wayland_thread->push_message(magnify_msg); + wayland_thread->push_message(pan_msg); + + ss->old_pinch_scale = scale; + } +} + +void WaylandThread::_wp_pointer_gesture_pinch_on_end(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, int32_t cancelled) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + ss->active_gesture = Gesture::NONE; +} + +// NOTE: Don't forget to `memfree` the offer's state. +void WaylandThread::_wp_primary_selection_device_on_data_offer(void *data, struct zwp_primary_selection_device_v1 *wp_primary_selection_device_v1, struct zwp_primary_selection_offer_v1 *offer) { + wl_proxy_tag_godot((struct wl_proxy *)offer); + zwp_primary_selection_offer_v1_add_listener(offer, &wp_primary_selection_offer_listener, memnew(OfferState)); +} + +void WaylandThread::_wp_primary_selection_device_on_selection(void *data, struct zwp_primary_selection_device_v1 *wp_primary_selection_device_v1, struct zwp_primary_selection_offer_v1 *id) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + if (ss->wp_primary_selection_offer) { + memfree(wp_primary_selection_offer_get_offer_state(ss->wp_primary_selection_offer)); + zwp_primary_selection_offer_v1_destroy(ss->wp_primary_selection_offer); + } + + ss->wp_primary_selection_offer = id; +} + +void WaylandThread::_wp_primary_selection_offer_on_offer(void *data, struct zwp_primary_selection_offer_v1 *zwp_primary_selection_offer_v1, const char *mime_type) { + OfferState *os = (OfferState *)data; + ERR_FAIL_NULL(os); + + if (os) { + os->mime_types.insert(String::utf8(mime_type)); + } +} + +void WaylandThread::_wp_primary_selection_source_on_send(void *data, struct zwp_primary_selection_source_v1 *wp_primary_selection_source_v1, const char *mime_type, int32_t fd) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + Vector *data_to_send = nullptr; + + if (wp_primary_selection_source_v1 == ss->wp_primary_selection_source) { + data_to_send = &ss->primary_data; + DEBUG_LOG_WAYLAND_THREAD("Clipboard: requested primary selection."); + } + + if (data_to_send) { + ssize_t written_bytes = 0; + + if (strcmp(mime_type, "text/plain") == 0) { + written_bytes = write(fd, data_to_send->ptr(), data_to_send->size()); + } + + if (written_bytes > 0) { + DEBUG_LOG_WAYLAND_THREAD(vformat("Clipboard: sent %d bytes.", written_bytes)); + } else if (written_bytes == 0) { + DEBUG_LOG_WAYLAND_THREAD("Clipboard: no bytes sent."); + } else { + ERR_PRINT(vformat("Clipboard: write error %d.", errno)); + } + } + + close(fd); +} + +void WaylandThread::_wp_primary_selection_source_on_cancelled(void *data, struct zwp_primary_selection_source_v1 *wp_primary_selection_source_v1) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + if (wp_primary_selection_source_v1 == ss->wp_primary_selection_source) { + zwp_primary_selection_source_v1_destroy(ss->wp_primary_selection_source); + ss->wp_primary_selection_source = nullptr; + + ss->primary_data.clear(); + + DEBUG_LOG_WAYLAND_THREAD("Clipboard: primary selection set by another program."); + return; + } +} + +void WaylandThread::_wp_tablet_seat_on_tablet_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_v2 *id) { + DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet seat %x on tablet %x added", (size_t)zwp_tablet_seat_v2, (size_t)id)); +} + +void WaylandThread::_wp_tablet_seat_on_tool_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_tool_v2 *id) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + ss->tablet_tools.push_back(id); + + zwp_tablet_tool_v2_add_listener(id, &wp_tablet_tool_listener, ss); + + DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet seat %x on tool %x added", (size_t)zwp_tablet_seat_v2, (size_t)id)); +} + +void WaylandThread::_wp_tablet_seat_on_pad_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_pad_v2 *id) { + DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet seat %x on pad %x added", (size_t)zwp_tablet_seat_v2, (size_t)id)); +} + +void WaylandThread::_wp_tablet_tool_on_type(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t tool_type) { + DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on type %d", (size_t)zwp_tablet_tool_v2, tool_type)); +} + +void WaylandThread::_wp_tablet_tool_on_hardware_serial(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t hardware_serial_hi, uint32_t hardware_serial_lo) { + DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on hardware serial %x%x", (size_t)zwp_tablet_tool_v2, hardware_serial_hi, hardware_serial_lo)); +} + +void WaylandThread::_wp_tablet_tool_on_hardware_id_wacom(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t hardware_id_hi, uint32_t hardware_id_lo) { + DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on hardware id wacom hardware id %x%x", (size_t)zwp_tablet_tool_v2, hardware_id_hi, hardware_id_lo)); +} + +void WaylandThread::_wp_tablet_tool_on_capability(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t capability) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + if (capability == ZWP_TABLET_TOOL_V2_TYPE_ERASER) { + ss->tablet_tool_data_buffer.is_eraser = true; + } + + DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on capability %d", (size_t)zwp_tablet_tool_v2, capability)); +} + +void WaylandThread::_wp_tablet_tool_on_done(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) { + DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on done", (size_t)zwp_tablet_tool_v2)); +} + +void WaylandThread::_wp_tablet_tool_on_removed(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + List::Element *it = ss->tablet_tools.front(); + + while (it) { + struct zwp_tablet_tool_v2 *tool = it->get(); + + if (tool == zwp_tablet_tool_v2) { + zwp_tablet_tool_v2_destroy(tool); + ss->tablet_tools.erase(it); + break; + } + } + + DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on removed", (size_t)zwp_tablet_tool_v2)); +} + +void WaylandThread::_wp_tablet_tool_on_proximity_in(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial, struct zwp_tablet_v2 *tablet, struct wl_surface *surface) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + WaylandThread *wayland_thread = ss->wayland_thread; + ERR_FAIL_NULL(wayland_thread); + + ss->tablet_tool_data_buffer.in_proximity = true; + + ss->pointer_enter_serial = serial; + ss->pointed_surface = surface; + ss->last_pointed_surface = surface; + + Ref msg; + msg.instantiate(); + msg->event = DisplayServer::WINDOW_EVENT_MOUSE_ENTER; + wayland_thread->push_message(msg); + + DEBUG_LOG_WAYLAND_THREAD("Tablet tool entered window."); + + DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on proximity in serial %d tablet %x surface %x", (size_t)zwp_tablet_tool_v2, serial, (size_t)tablet, (size_t)surface)); +} + +void WaylandThread::_wp_tablet_tool_on_proximity_out(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + WaylandThread *wayland_thread = ss->wayland_thread; + ERR_FAIL_NULL(wayland_thread); + + ss->pointed_surface = nullptr; + ss->tablet_tool_data_buffer.in_proximity = false; + + DEBUG_LOG_WAYLAND_THREAD("Tablet tool left window."); + + Ref msg; + msg.instantiate(); + msg->event = DisplayServer::WINDOW_EVENT_MOUSE_EXIT; + + wayland_thread->push_message(msg); + + DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on proximity out", (size_t)zwp_tablet_tool_v2)); +} + +void WaylandThread::_wp_tablet_tool_on_down(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + TabletToolData &td = ss->tablet_tool_data_buffer; + + td.touching = true; + td.pressed_button_mask.set_flag(mouse_button_to_mask(MouseButton::LEFT)); + td.last_button_pressed = MouseButton::LEFT; + td.double_click_begun = true; + + // The protocol doesn't cover this, but we can use this funky hack to make + // double clicking work. + td.button_time = OS::get_singleton()->get_ticks_msec(); + + DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on down serial %x", (size_t)zwp_tablet_tool_v2, serial)); +} + +void WaylandThread::_wp_tablet_tool_on_up(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + TabletToolData &td = ss->tablet_tool_data_buffer; + + td.touching = false; + td.pressed_button_mask.clear_flag(mouse_button_to_mask(MouseButton::LEFT)); + + // The protocol doesn't cover this, but we can use this funky hack to make + // double clicking work. + td.button_time = OS::get_singleton()->get_ticks_msec(); + + DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on up", (size_t)zwp_tablet_tool_v2)); +} + +void WaylandThread::_wp_tablet_tool_on_motion(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t x, wl_fixed_t y) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + WindowState *ws = wl_surface_get_window_state(ss->pointed_surface); + ERR_FAIL_NULL(ws); + + double scale_factor = window_state_get_scale_factor(ws); + + TabletToolData &td = ss->tablet_tool_data_buffer; + + td.position = scale_vector2i(td.position, scale_factor); +} + +void WaylandThread::_wp_tablet_tool_on_pressure(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t pressure) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + ss->tablet_tool_data_buffer.pressure = pressure; +} + +void WaylandThread::_wp_tablet_tool_on_distance(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t distance) { + // Unsupported +} + +void WaylandThread::_wp_tablet_tool_on_tilt(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t tilt_x, wl_fixed_t tilt_y) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + ss->tablet_tool_data_buffer.tilt.x = wl_fixed_to_double(tilt_x); + ss->tablet_tool_data_buffer.tilt.y = wl_fixed_to_double(tilt_y); +} + +void WaylandThread::_wp_tablet_tool_on_rotation(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t degrees) { + // Unsupported. +} + +void WaylandThread::_wp_tablet_tool_on_slider(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, int32_t position) { + // Unsupported. +} + +void WaylandThread::_wp_tablet_tool_on_wheel(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t degrees, int32_t clicks) { + // TODO +} + +void WaylandThread::_wp_tablet_tool_on_button(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial, uint32_t button, uint32_t state) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + TabletToolData &td = ss->tablet_tool_data_buffer; + + MouseButton mouse_button = MouseButton::NONE; + + if (button == BTN_STYLUS) { + mouse_button = MouseButton::LEFT; + } + + if (button == BTN_STYLUS2) { + mouse_button = MouseButton::RIGHT; + } + + if (mouse_button != MouseButton::NONE) { + MouseButtonMask mask = mouse_button_to_mask(mouse_button); + + if (state == ZWP_TABLET_TOOL_V2_BUTTON_STATE_PRESSED) { + td.pressed_button_mask.set_flag(mask); + td.last_button_pressed = mouse_button; + td.double_click_begun = true; + } else { + td.pressed_button_mask.clear_flag(mask); + } + + // The protocol doesn't cover this, but we can use this funky hack to make + // double clicking work. + td.button_time = OS::get_singleton()->get_ticks_msec(); + } +} + +void WaylandThread::_wp_tablet_tool_on_frame(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t time) { + SeatState *ss = (SeatState *)data; + ERR_FAIL_NULL(ss); + + WaylandThread *wayland_thread = ss->wayland_thread; + ERR_FAIL_NULL(wayland_thread); + + TabletToolData &old_td = ss->tablet_tool_data; + TabletToolData &td = ss->tablet_tool_data_buffer; + + if (old_td.position != td.position || old_td.tilt != td.tilt || old_td.pressure != td.pressure) { + Ref mm; + mm.instantiate(); + + mm->set_window_id(DisplayServer::MAIN_WINDOW_ID); + + // Set all pressed modifiers. + mm->set_shift_pressed(ss->shift_pressed); + mm->set_ctrl_pressed(ss->ctrl_pressed); + mm->set_alt_pressed(ss->alt_pressed); + mm->set_meta_pressed(ss->meta_pressed); + + mm->set_button_mask(td.pressed_button_mask); + + mm->set_position(td.position); + mm->set_global_position(td.position); + + // NOTE: The Godot API expects normalized values and we store them raw, + // straight from the compositor, so we have to normalize them here. + + // According to the tablet proto spec, tilt is expressed in degrees relative + // to the Z axis of the tablet, so it shouldn't go over 90 degrees, I think. + // TODO: Investigate whether the tilt can go over 90 degrees (it shouldn't). + mm->set_tilt(td.tilt / 90); + + // The tablet proto spec explicitly says that pressure is defined as a value + // between 0 to 65535. + mm->set_pressure(td.pressure / (float)65535); + + // FIXME: Tool handling is broken. + mm->set_pen_inverted(td.is_eraser); + + mm->set_relative(td.position - old_td.position); + + // FIXME: Stop doing this to calculate speed. + // FIXME2: It has been done, port this from the pointer logic once this works again. + Input::get_singleton()->set_mouse_position(td.position); + mm->set_velocity(Input::get_singleton()->get_last_mouse_velocity()); + + Ref inputev_msg; + inputev_msg.instantiate(); + + inputev_msg->event = mm; + + wayland_thread->push_message(inputev_msg); + } + + if (old_td.pressed_button_mask != td.pressed_button_mask) { + BitField pressed_mask_delta = BitField((int64_t)old_td.pressed_button_mask ^ (int64_t)td.pressed_button_mask); + + for (MouseButton test_button : { MouseButton::LEFT, MouseButton::RIGHT }) { + MouseButtonMask test_button_mask = mouse_button_to_mask(test_button); + + if (pressed_mask_delta.has_flag(test_button_mask)) { + Ref mb; + mb.instantiate(); + + // Set all pressed modifiers. + mb->set_shift_pressed(ss->shift_pressed); + mb->set_ctrl_pressed(ss->ctrl_pressed); + mb->set_alt_pressed(ss->alt_pressed); + mb->set_meta_pressed(ss->meta_pressed); + + mb->set_window_id(DisplayServer::MAIN_WINDOW_ID); + mb->set_position(td.position); + mb->set_global_position(td.position); + + mb->set_button_mask(td.pressed_button_mask); + mb->set_button_index(test_button); + mb->set_pressed(td.pressed_button_mask.has_flag(test_button_mask)); + + // We have to set the last position pressed here as we can't take for + // granted what the individual events might have seen due to them not having + // a garaunteed order. + if (mb->is_pressed()) { + td.last_pressed_position = td.position; + } + + if (old_td.double_click_begun && mb->is_pressed() && td.last_button_pressed == old_td.last_button_pressed && (td.button_time - old_td.button_time) < 400 && Vector2(td.last_pressed_position).distance_to(Vector2(old_td.last_pressed_position)) < 5) { + td.double_click_begun = false; + mb->set_double_click(true); + } + + Ref msg; + msg.instantiate(); + + msg->event = mb; + + wayland_thread->push_message(msg); + } + } + } + + old_td = td; +} + +void WaylandThread::_xdg_activation_token_on_done(void *data, struct xdg_activation_token_v1 *xdg_activation_token, const char *token) { + WindowState *ws = (WindowState *)data; + ERR_FAIL_NULL(ws); + ERR_FAIL_NULL(ws->wayland_thread); + ERR_FAIL_NULL(ws->wl_surface); + + xdg_activation_v1_activate(ws->wayland_thread->registry.xdg_activation, token, ws->wl_surface); + xdg_activation_token_v1_destroy(xdg_activation_token); + + DEBUG_LOG_WAYLAND_THREAD(vformat("Received activation token and requested window activation.")); +} + +// NOTE: This must be started after a valid wl_display is loaded. +void WaylandThread::_poll_events_thread(void *p_data) { + ThreadData *data = (ThreadData *)p_data; + ERR_FAIL_NULL(data); + ERR_FAIL_NULL(data->wl_display); + + struct pollfd poll_fd; + poll_fd.fd = wl_display_get_fd(data->wl_display); + poll_fd.events = POLLIN | POLLHUP; + + while (true) { + // Empty the event queue while it's full. + while (wl_display_prepare_read(data->wl_display) != 0) { + // We aren't using wl_display_dispatch(), instead "manually" handling events + // through wl_display_dispatch_pending so that we can use a global mutex and + // be sure that this and the main thread won't race over stuff, as long as + // the main thread locks it too. + // + // Note that the main thread can still call wl_display_roundtrip as that + // method directly handles all events, effectively bypassing this polling + // loop and thus the mutex locking, avoiding a deadlock. + MutexLock mutex_lock(data->mutex); + + if (wl_display_dispatch_pending(data->wl_display) == -1) { + // Oh no. We'll check and handle any display error below. + break; + } + } + + int werror = wl_display_get_error(data->wl_display); + + if (werror) { + if (werror == EPROTO) { + struct wl_interface *wl_interface = nullptr; + uint32_t id = 0; + + int error_code = wl_display_get_protocol_error(data->wl_display, (const struct wl_interface **)&wl_interface, &id); + CRASH_NOW_MSG(vformat("Wayland protocol error %d on interface %s@%d.", error_code, wl_interface ? wl_interface->name : "unknown", id)); + } else { + CRASH_NOW_MSG(vformat("Wayland client error code %d.", werror)); + } + } + + wl_display_flush(data->wl_display); + + // Wait for the event file descriptor to have new data. + poll(&poll_fd, 1, -1); + + if (data->thread_done.is_set()) { + wl_display_cancel_read(data->wl_display); + break; + } + + if (poll_fd.revents | POLLIN) { + // Load the queues with fresh new data. + wl_display_read_events(data->wl_display); + } else { + // Oh well... Stop signaling that we want to read. + wl_display_cancel_read(data->wl_display); + } + + // The docs advise to redispatch unconditionally and it looks like that if we + // don't do this we can't catch protocol errors, which is bad. + MutexLock mutex_lock(data->mutex); + wl_display_dispatch_pending(data->wl_display); + } +} + +struct wl_display *WaylandThread::get_wl_display() const { + return wl_display; +} + +// NOTE: Stuff like libdecor can (and will) register foreign proxies which +// aren't formatted as we like. This method is needed to detect whether a proxy +// has our tag. Also, be careful! The proxy has to be manually tagged or it +// won't be recognized. +bool WaylandThread::wl_proxy_is_godot(struct wl_proxy *p_proxy) { + ERR_FAIL_NULL_V(p_proxy, false); + + return wl_proxy_get_tag(p_proxy) == &proxy_tag; +} + +void WaylandThread::wl_proxy_tag_godot(struct wl_proxy *p_proxy) { + ERR_FAIL_NULL(p_proxy); + + wl_proxy_set_tag(p_proxy, &proxy_tag); +} + +// Returns the wl_surface's `WindowState`, otherwise `nullptr`. +// NOTE: This will fail if the surface isn't tagged as ours. +WaylandThread::WindowState *WaylandThread::wl_surface_get_window_state(struct wl_surface *p_surface) { + if (p_surface && wl_proxy_is_godot((wl_proxy *)p_surface)) { + return (WindowState *)wl_surface_get_user_data(p_surface); + } + + return nullptr; +} + +// Returns the wl_outputs's `ScreenState`, otherwise `nullptr`. +// NOTE: This will fail if the output isn't tagged as ours. +WaylandThread::ScreenState *WaylandThread::wl_output_get_screen_state(struct wl_output *p_output) { + if (p_output && wl_proxy_is_godot((wl_proxy *)p_output)) { + return (ScreenState *)wl_output_get_user_data(p_output); + } + + return nullptr; +} + +// Returns the wl_seat's `SeatState`, otherwise `nullptr`. +// NOTE: This will fail if the output isn't tagged as ours. +WaylandThread::SeatState *WaylandThread::wl_seat_get_seat_state(struct wl_seat *p_seat) { + if (p_seat && wl_proxy_is_godot((wl_proxy *)p_seat)) { + return (SeatState *)wl_seat_get_user_data(p_seat); + } + + return nullptr; +} + +// Returns the wl_data_offer's `OfferState`, otherwise `nullptr`. +// NOTE: This will fail if the output isn't tagged as ours. +WaylandThread::OfferState *WaylandThread::wl_data_offer_get_offer_state(struct wl_data_offer *p_offer) { + if (p_offer && wl_proxy_is_godot((wl_proxy *)p_offer)) { + return (OfferState *)wl_data_offer_get_user_data(p_offer); + } + + return nullptr; +} + +// Returns the wl_data_offer's `OfferState`, otherwise `nullptr`. +// NOTE: This will fail if the output isn't tagged as ours. +WaylandThread::OfferState *WaylandThread::wp_primary_selection_offer_get_offer_state(struct zwp_primary_selection_offer_v1 *p_offer) { + if (p_offer && wl_proxy_is_godot((wl_proxy *)p_offer)) { + return (OfferState *)zwp_primary_selection_offer_v1_get_user_data(p_offer); + } + + return nullptr; +} + +// This is implemented as a method because this is the simplest way of +// accounting for dynamic output scale changes. +int WaylandThread::window_state_get_preferred_buffer_scale(WindowState *p_ws) { + ERR_FAIL_NULL_V(p_ws, 1); + + if (p_ws->preferred_fractional_scale > 0) { + // We're scaling fractionally. Per spec, the buffer scale is always 1. + return 1; + } + + if (p_ws->wl_outputs.is_empty()) { + DEBUG_LOG_WAYLAND_THREAD("Window has no output associated, returning buffer scale of 1."); + return 1; + } + + // TODO: Cache value? + int max_size = 1; + + // ================================ IMPORTANT ================================= + // NOTE: Due to a Godot limitation, we can't really rescale the whole UI yet. + // Because of this reason, all platforms have resorted to forcing the highest + // scale possible of a system on any window, despite of what screen it's onto. + // On this backend everything's already in place for dynamic window scale + // handling, but in the meantime we'll just select the biggest _global_ output. + // To restore dynamic scale selection, simply iterate over `p_ws->wl_outputs` + // instead. + for (struct wl_output *wl_output : p_ws->registry->wl_outputs) { + ScreenState *ss = wl_output_get_screen_state(wl_output); + + if (ss && ss->pending_data.scale > max_size) { + // NOTE: For some mystical reason, wl_output.done is emitted _after_ windows + // get resized but the scale event gets sent _before_ that. I'm still leaning + // towards the idea that rescaling when a window gets a resolution change is a + // pretty good approach, but this means that we'll have to use the screen data + // before it's "committed". + // FIXME: Use the committed data. Somehow. + max_size = ss->pending_data.scale; + } + } + + return max_size; +} + +double WaylandThread::window_state_get_scale_factor(WindowState *p_ws) { + ERR_FAIL_NULL_V(p_ws, 1); + + if (p_ws->fractional_scale > 0) { + // The fractional scale amount takes priority. + return p_ws->fractional_scale; + } + + return p_ws->buffer_scale; +} + +void WaylandThread::window_state_update_size(WindowState *p_ws, int p_width, int p_height) { + ERR_FAIL_NULL(p_ws); + + int preferred_buffer_scale = window_state_get_preferred_buffer_scale(p_ws); + bool using_fractional = p_ws->preferred_fractional_scale > 0; + + // If neither is true we no-op. + bool scale_changed = false; + bool size_changed = false; + + if (p_ws->rect.size.width != p_width || p_ws->rect.size.height != p_height) { + p_ws->rect.size.width = p_width; + p_ws->rect.size.height = p_height; + + size_changed = true; + } + + if (using_fractional && p_ws->fractional_scale != p_ws->preferred_fractional_scale) { + p_ws->fractional_scale = p_ws->preferred_fractional_scale; + scale_changed = true; + } + + if (p_ws->buffer_scale != preferred_buffer_scale) { + // The buffer scale is always important, even if we use frac scaling. + p_ws->buffer_scale = preferred_buffer_scale; + p_ws->buffer_scale_changed = true; + + if (!using_fractional) { + // We don't bother updating everything else if it's turned on though. + scale_changed = true; + } + } + + if (p_ws->wl_surface && (size_changed || scale_changed)) { + if (p_ws->wp_viewport) { + wp_viewport_set_destination(p_ws->wp_viewport, p_width, p_height); + } + + if (p_ws->xdg_surface) { + xdg_surface_set_window_geometry(p_ws->xdg_surface, 0, 0, p_width, p_height); + } + } + +#ifdef LIBDECOR_ENABLED + if (p_ws->libdecor_frame) { + struct libdecor_state *state = libdecor_state_new(p_width, p_height); + libdecor_frame_commit(p_ws->libdecor_frame, state, p_ws->pending_libdecor_configuration); + libdecor_state_free(state); + p_ws->pending_libdecor_configuration = nullptr; + } +#endif + + if (size_changed || scale_changed) { + Size2i scaled_size = scale_vector2i(p_ws->rect.size, window_state_get_scale_factor(p_ws)); + + if (using_fractional) { + DEBUG_LOG_WAYLAND_THREAD(vformat("Resizing the window from %s to %s (fractional scale x%f).", p_ws->rect.size, scaled_size, p_ws->fractional_scale)); + } else { + DEBUG_LOG_WAYLAND_THREAD(vformat("Resizing the window from %s to %s (buffer scale x%d).", p_ws->rect.size, scaled_size, p_ws->buffer_scale)); + } + + // FIXME: Actually resize the hint instead of centering it. + p_ws->wayland_thread->pointer_set_hint(scaled_size / 2); + + Ref rect_msg; + rect_msg.instantiate(); + rect_msg->rect = p_ws->rect; + rect_msg->rect.size = scaled_size; + p_ws->wayland_thread->push_message(rect_msg); + } + + if (scale_changed) { + Ref dpi_msg; + dpi_msg.instantiate(); + dpi_msg->event = DisplayServer::WINDOW_EVENT_DPI_CHANGE; + p_ws->wayland_thread->push_message(dpi_msg); + } +} + +// Scales a vector according to wp_fractional_scale's rules, where coordinates +// must be scaled with away from zero half-rounding. +Vector2i WaylandThread::scale_vector2i(const Vector2i &p_vector, double p_amount) { + // This snippet is tiny, I know, but this is done a lot. + int x = round(p_vector.x * p_amount); + int y = round(p_vector.y * p_amount); + + return Vector2i(x, y); +} + +void WaylandThread::seat_state_unlock_pointer(SeatState *p_ss) { + ERR_FAIL_NULL(p_ss); + + if (p_ss->wl_pointer == nullptr) { + return; + } + + if (p_ss->wp_locked_pointer) { + zwp_locked_pointer_v1_destroy(p_ss->wp_locked_pointer); + p_ss->wp_locked_pointer = nullptr; + } + + if (p_ss->wp_confined_pointer) { + zwp_confined_pointer_v1_destroy(p_ss->wp_confined_pointer); + p_ss->wp_confined_pointer = nullptr; + } +} + +void WaylandThread::seat_state_lock_pointer(SeatState *p_ss) { + ERR_FAIL_NULL(p_ss); + + if (p_ss->wl_pointer == nullptr) { + return; + } + + if (registry.wp_pointer_constraints == nullptr) { + return; + } + + if (p_ss->wp_locked_pointer == nullptr) { + struct wl_surface *locked_surface = p_ss->last_pointed_surface; + + if (locked_surface == nullptr) { + locked_surface = window_get_wl_surface(DisplayServer::MAIN_WINDOW_ID); + } + + ERR_FAIL_NULL(locked_surface); + + p_ss->wp_locked_pointer = zwp_pointer_constraints_v1_lock_pointer(registry.wp_pointer_constraints, locked_surface, p_ss->wl_pointer, NULL, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); + } +} + +void WaylandThread::seat_state_set_hint(SeatState *p_ss, int p_x, int p_y) { + if (p_ss->wp_locked_pointer == nullptr) { + return; + } + + zwp_locked_pointer_v1_set_cursor_position_hint(p_ss->wp_locked_pointer, wl_fixed_from_int(p_x), wl_fixed_from_int(p_y)); +} + +void WaylandThread::seat_state_confine_pointer(SeatState *p_ss) { + ERR_FAIL_NULL(p_ss); + + if (p_ss->wl_pointer == nullptr) { + return; + } + + if (registry.wp_pointer_constraints == nullptr) { + return; + } + + if (p_ss->wp_confined_pointer == nullptr) { + struct wl_surface *confined_surface = p_ss->last_pointed_surface; + + if (confined_surface == nullptr) { + confined_surface = window_get_wl_surface(DisplayServer::MAIN_WINDOW_ID); + } + + ERR_FAIL_NULL(confined_surface); + + p_ss->wp_confined_pointer = zwp_pointer_constraints_v1_confine_pointer(registry.wp_pointer_constraints, confined_surface, p_ss->wl_pointer, NULL, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); + } +} + +void WaylandThread::seat_state_update_cursor(SeatState *p_ss) { + ERR_FAIL_NULL(p_ss); + ERR_FAIL_NULL(p_ss->wayland_thread); + + if (p_ss->wl_pointer && p_ss->cursor_surface) { + // NOTE: Those values are valid by default and will hide the cursor when + // unchanged, which happens when both the current custom cursor and the + // current wl_cursor are `nullptr`. + struct wl_buffer *cursor_buffer = nullptr; + uint32_t hotspot_x = 0; + uint32_t hotspot_y = 0; + int scale = 1; + + CustomCursor *custom_cursor = p_ss->wayland_thread->current_custom_cursor; + struct wl_cursor *wl_cursor = p_ss->wayland_thread->current_wl_cursor; + + if (custom_cursor) { + cursor_buffer = custom_cursor->wl_buffer; + hotspot_x = custom_cursor->hotspot.x; + hotspot_y = custom_cursor->hotspot.y; + + // We can't really reasonably scale custom cursors, so we'll let the + // compositor do it for us (badly). + scale = 1; + } else if (wl_cursor) { + int frame_idx = wl_cursor_frame(wl_cursor, p_ss->cursor_time_ms); + + struct wl_cursor_image *wl_cursor_image = wl_cursor->images[frame_idx]; + + scale = p_ss->wayland_thread->cursor_scale; + + cursor_buffer = wl_cursor_image_get_buffer(wl_cursor_image); + + // As the surface's buffer is scaled (thus the surface is smaller) and the + // hotspot must be expressed in surface-local coordinates, we need to scale + // them down accordingly. + hotspot_x = wl_cursor_image->hotspot_x / scale; + hotspot_y = wl_cursor_image->hotspot_y / scale; + } + + wl_pointer_set_cursor(p_ss->wl_pointer, p_ss->pointer_enter_serial, p_ss->cursor_surface, hotspot_x, hotspot_y); + wl_surface_set_buffer_scale(p_ss->cursor_surface, scale); + wl_surface_attach(p_ss->cursor_surface, cursor_buffer, 0, 0); + wl_surface_damage_buffer(p_ss->cursor_surface, 0, 0, INT_MAX, INT_MAX); + + wl_surface_commit(p_ss->cursor_surface); + } +} + +void WaylandThread::seat_state_echo_keys(SeatState *p_ss) { + ERR_FAIL_NULL(p_ss); + + if (p_ss->wl_keyboard == nullptr) { + return; + } + + // TODO: Comment and document out properly this block of code. + // In short, this implements key repeating. + if (p_ss->repeat_key_delay_msec && p_ss->repeating_keycode != XKB_KEYCODE_INVALID) { + uint64_t current_ticks = OS::get_singleton()->get_ticks_msec(); + uint64_t delayed_start_ticks = p_ss->last_repeat_start_msec + p_ss->repeat_start_delay_msec; + + if (p_ss->last_repeat_msec < delayed_start_ticks) { + p_ss->last_repeat_msec = delayed_start_ticks; + } + + if (current_ticks >= delayed_start_ticks) { + uint64_t ticks_delta = current_ticks - p_ss->last_repeat_msec; + + int keys_amount = (ticks_delta / p_ss->repeat_key_delay_msec); + + for (int i = 0; i < keys_amount; i++) { + Ref k; + k.instantiate(); + + if (!_seat_state_configure_key_event(*p_ss, k, p_ss->repeating_keycode, true)) { + continue; + } + + k->set_echo(true); + + Input::get_singleton()->parse_input_event(k); + } + + p_ss->last_repeat_msec += ticks_delta - (ticks_delta % p_ss->repeat_key_delay_msec); + } + } +} + +void WaylandThread::push_message(Ref message) { + messages.push_back(message); +} + +bool WaylandThread::has_message() { + return messages.front() != nullptr; +} + +Ref WaylandThread::pop_message() { + if (messages.front() != nullptr) { + Ref msg = messages.front()->get(); + messages.pop_front(); + return msg; + } + + // This method should only be called if `has_messages` returns true but if + // that isn't the case we'll just return an invalid `Ref`. After all, due to + // its `InputEvent`-like interface, we still have to dynamically cast and check + // the `Ref`'s validity anyways. + return Ref(); +} + +void WaylandThread::window_create(DisplayServer::WindowID p_window_id, int p_width, int p_height) { + // TODO: Implement multi-window support. + WindowState &ws = main_window; + + ws.registry = ®istry; + ws.wayland_thread = this; + + ws.rect.size.width = p_width; + ws.rect.size.height = p_height; + + ws.wl_surface = wl_compositor_create_surface(registry.wl_compositor); + wl_proxy_tag_godot((struct wl_proxy *)ws.wl_surface); + wl_surface_add_listener(ws.wl_surface, &wl_surface_listener, &ws); + + if (registry.wp_viewporter) { + ws.wp_viewport = wp_viewporter_get_viewport(registry.wp_viewporter, ws.wl_surface); + + if (registry.wp_fractional_scale_manager) { + ws.wp_fractional_scale = wp_fractional_scale_manager_v1_get_fractional_scale(registry.wp_fractional_scale_manager, ws.wl_surface); + wp_fractional_scale_v1_add_listener(ws.wp_fractional_scale, &wp_fractional_scale_listener, &ws); + } + } + + bool decorated = false; + +#ifdef LIBDECOR_ENABLED + if (!decorated && libdecor_context) { + ws.libdecor_frame = libdecor_decorate(libdecor_context, ws.wl_surface, (struct libdecor_frame_interface *)&libdecor_frame_interface, &ws); + libdecor_frame_map(ws.libdecor_frame); + + decorated = true; + } +#endif + + if (!decorated) { + // libdecor has failed loading or is disabled, we shall handle xdg_toplevel + // creation and decoration ourselves (and by decorating for now I just mean + // asking for SSDs and hoping for the best). + ws.xdg_surface = xdg_wm_base_get_xdg_surface(registry.xdg_wm_base, ws.wl_surface); + xdg_surface_add_listener(ws.xdg_surface, &xdg_surface_listener, &ws); + + ws.xdg_toplevel = xdg_surface_get_toplevel(ws.xdg_surface); + xdg_toplevel_add_listener(ws.xdg_toplevel, &xdg_toplevel_listener, &ws); + + if (registry.xdg_decoration_manager) { + ws.xdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(registry.xdg_decoration_manager, ws.xdg_toplevel); + zxdg_toplevel_decoration_v1_add_listener(ws.xdg_toplevel_decoration, &xdg_toplevel_decoration_listener, &ws); + + decorated = true; + } + } + + ws.frame_callback = wl_surface_frame(ws.wl_surface); + wl_callback_add_listener(ws.frame_callback, &frame_wl_callback_listener, &ws); + + // NOTE: This commit is only called once to start the whole frame callback + // "loop". + wl_surface_commit(ws.wl_surface); + + // Wait for the surface to be configured before continuing. + wl_display_roundtrip(wl_display); +} + +struct wl_surface *WaylandThread::window_get_wl_surface(DisplayServer::WindowID p_window_id) const { + // TODO: Use window IDs for multiwindow support. + const WindowState &ws = main_window; + + return ws.wl_surface; +} + +void WaylandThread::window_set_max_size(DisplayServer::WindowID p_window_id, const Size2i &p_size) { + // TODO: Use window IDs for multiwindow support. + WindowState &ws = main_window; + + Vector2i logical_max_size = p_size / window_state_get_scale_factor(&ws); + + if (ws.wl_surface && ws.xdg_toplevel) { + xdg_toplevel_set_max_size(ws.xdg_toplevel, logical_max_size.width, logical_max_size.height); + } + +#ifdef LIBDECOR_ENABLED + if (ws.libdecor_frame) { + libdecor_frame_set_max_content_size(ws.libdecor_frame, logical_max_size.width, logical_max_size.height); + } + + // FIXME: I'm not sure whether we have to commit the surface for this to apply. +#endif +} + +void WaylandThread::window_set_min_size(DisplayServer::WindowID p_window_id, const Size2i &p_size) { + // TODO: Use window IDs for multiwindow support. + WindowState &ws = main_window; + + Size2i logical_min_size = p_size / window_state_get_scale_factor(&ws); + + if (ws.wl_surface && ws.xdg_toplevel) { + xdg_toplevel_set_min_size(ws.xdg_toplevel, logical_min_size.width, logical_min_size.height); + } + +#ifdef LIBDECOR_ENABLED + if (ws.libdecor_frame) { + libdecor_frame_set_min_content_size(ws.libdecor_frame, logical_min_size.width, logical_min_size.height); + } + + // FIXME: I'm not sure whether we have to commit the surface for this to apply. +#endif +} + +bool WaylandThread::window_can_set_mode(DisplayServer::WindowID p_window_id, DisplayServer::WindowMode p_window_mode) const { + // TODO: Use window IDs for multiwindow support. + const WindowState &ws = main_window; + + switch (p_window_mode) { + case DisplayServer::WINDOW_MODE_WINDOWED: { + // Looks like it's guaranteed. + return true; + }; + + case DisplayServer::WINDOW_MODE_MINIMIZED: { +#ifdef LIBDECOR_ENABLED + if (ws.libdecor_frame) { + return libdecor_frame_has_capability(ws.libdecor_frame, LIBDECOR_ACTION_MINIMIZE); + } +#endif // LIBDECOR_ENABLED + + return ws.can_minimize; + }; + + case DisplayServer::WINDOW_MODE_MAXIMIZED: { + // NOTE: libdecor doesn't seem to have a maximize capability query? + // The fact that there's a fullscreen one makes me suspicious. + return ws.can_maximize; + }; + + case DisplayServer::WINDOW_MODE_FULLSCREEN: { +#ifdef LIBDECOR_ENABLED + if (ws.libdecor_frame) { + return libdecor_frame_has_capability(ws.libdecor_frame, LIBDECOR_ACTION_FULLSCREEN); + } +#endif // LIBDECOR_ENABLED + + return ws.can_fullscreen; + }; + + case DisplayServer::WINDOW_MODE_EXCLUSIVE_FULLSCREEN: { + // I'm not really sure but from what I can find Wayland doesn't really have + // the concept of exclusive fullscreen. + // TODO: Discuss whether to fallback to regular fullscreen or not. + return false; + }; + } + + return false; +} + +void WaylandThread::window_try_set_mode(DisplayServer::WindowID p_window_id, DisplayServer::WindowMode p_window_mode) { + // TODO: Use window IDs for multiwindow support. + WindowState &ws = main_window; + + if (ws.mode == p_window_mode) { + return; + } + + // Don't waste time with hidden windows and whatnot. Behave like it worked. +#ifdef LIBDECOR_ENABLED + if ((!ws.wl_surface || !ws.xdg_toplevel) && !ws.libdecor_frame) { +#else + if (!ws.wl_surface || !ws.xdg_toplevel) { +#endif // LIBDECOR_ENABLED + ws.mode = p_window_mode; + return; + } + + // Return back to a windowed state so that we can apply what the user asked. + switch (ws.mode) { + case DisplayServer::WINDOW_MODE_WINDOWED: { + // Do nothing. + } break; + + case DisplayServer::WINDOW_MODE_MINIMIZED: { + // We can't do much according to the xdg_shell protocol. I have no idea + // whether this implies that we should return or who knows what. For now + // we'll do nothing. + // TODO: Test this properly. + } break; + + case DisplayServer::WINDOW_MODE_MAXIMIZED: { + // Try to unmaximize. This isn't garaunteed to work actually, so we'll have + // to check whether something changed. + if (ws.xdg_toplevel) { + xdg_toplevel_unset_maximized(ws.xdg_toplevel); + } + +#ifdef LIBDECOR_ENABLED + if (ws.libdecor_frame) { + libdecor_frame_unset_maximized(ws.libdecor_frame); + } +#endif // LIBDECOR_ENABLED + } break; + + case DisplayServer::WINDOW_MODE_FULLSCREEN: + case DisplayServer::WINDOW_MODE_EXCLUSIVE_FULLSCREEN: { + // Same thing as above, unset fullscreen and check later if it worked. + if (ws.xdg_toplevel) { + xdg_toplevel_unset_fullscreen(ws.xdg_toplevel); + } + +#ifdef LIBDECOR_ENABLED + if (ws.libdecor_frame) { + libdecor_frame_unset_fullscreen(ws.libdecor_frame); + } +#endif // LIBDECOR_ENABLED + } break; + } + + // Wait for a configure event and hope that something changed. + wl_display_roundtrip(wl_display); + + if (ws.mode != DisplayServer::WINDOW_MODE_WINDOWED) { + // The compositor refused our "normalization" request. It'd be useless or + // unpredictable to attempt setting a new state. We're done. + return; + } + + // Ask the compositor to set the state indicated by the new mode. + switch (p_window_mode) { + case DisplayServer::WINDOW_MODE_WINDOWED: { + // Do nothing. We're already windowed. + } break; + + case DisplayServer::WINDOW_MODE_MINIMIZED: { + if (!window_can_set_mode(p_window_id, p_window_mode)) { + // Minimization is special (read below). Better not mess with it if the + // compositor explicitly announces that it doesn't support it. + break; + } + + if (ws.xdg_toplevel) { + xdg_toplevel_set_minimized(ws.xdg_toplevel); + } + +#ifdef LIBDECOR_ENABLED + if (ws.libdecor_frame) { + libdecor_frame_set_minimized(ws.libdecor_frame); + } +#endif // LIBDECOR_ENABLED + // We have no way to actually detect this state, so we'll have to report it + // manually to the engine (hoping that it worked). In the worst case it'll + // get reset by the next configure event. + ws.mode = DisplayServer::WINDOW_MODE_MINIMIZED; + } break; + + case DisplayServer::WINDOW_MODE_MAXIMIZED: { + if (ws.xdg_toplevel) { + xdg_toplevel_set_maximized(ws.xdg_toplevel); + } + +#ifdef LIBDECOR_ENABLED + if (ws.libdecor_frame) { + libdecor_frame_set_maximized(ws.libdecor_frame); + } +#endif // LIBDECOR_ENABLED + } break; + + case DisplayServer::WINDOW_MODE_FULLSCREEN: { + if (ws.xdg_toplevel) { + xdg_toplevel_set_fullscreen(ws.xdg_toplevel, nullptr); + } + +#ifdef LIBDECOR_ENABLED + if (ws.libdecor_frame) { + libdecor_frame_set_fullscreen(ws.libdecor_frame, nullptr); + } +#endif // LIBDECOR_ENABLED + } break; + + default: { + } break; + } +} + +void WaylandThread::window_set_borderless(DisplayServer::WindowID p_window_id, bool p_borderless) { + // TODO: Use window IDs for multiwindow support. + WindowState &ws = main_window; + + if (ws.xdg_toplevel_decoration) { + if (p_borderless) { + // We implement borderless windows by simply asking the compositor to let + // us handle decorations (we don't). + zxdg_toplevel_decoration_v1_set_mode(ws.xdg_toplevel_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); + } else { + zxdg_toplevel_decoration_v1_set_mode(ws.xdg_toplevel_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } + } + +#ifdef LIBDECOR_ENABLED + if (ws.libdecor_frame) { + bool visible_current = libdecor_frame_is_visible(ws.libdecor_frame); + bool visible_target = !p_borderless; + + // NOTE: We have to do this otherwise we trip on a libdecor bug where it's + // possible to destroy the frame more than once, by setting the visibility + // to false multiple times and thus crashing. + if (visible_current != visible_target) { + print_verbose(vformat("Setting libdecor frame visibility to %d", visible_target)); + libdecor_frame_set_visibility(ws.libdecor_frame, visible_target); + } + } +#endif // LIBDECOR_ENABLED +} + +void WaylandThread::window_set_title(DisplayServer::WindowID p_window_id, const String &p_title) { + // TODO: Use window IDs for multiwindow support. + WindowState &ws = main_window; + +#ifdef LIBDECOR_ENABLED + if (ws.libdecor_frame) { + libdecor_frame_set_title(ws.libdecor_frame, p_title.utf8()); + } +#endif // LIBDECOR_ENABLE + + if (ws.xdg_toplevel) { + xdg_toplevel_set_title(ws.xdg_toplevel, p_title.utf8()); + } +} + +void WaylandThread::window_set_app_id(DisplayServer::WindowID p_window_id, const String &p_app_id) { + // TODO: Use window IDs for multiwindow support. + WindowState &ws = main_window; + +#ifdef LIBDECOR_ENABLED + if (ws.libdecor_frame) { + libdecor_frame_set_app_id(ws.libdecor_frame, p_app_id.utf8()); + return; + } +#endif // LIBDECOR_ENABLED + + if (ws.xdg_toplevel) { + xdg_toplevel_set_app_id(ws.xdg_toplevel, p_app_id.utf8()); + return; + } +} + +DisplayServer::WindowMode WaylandThread::window_get_mode(DisplayServer::WindowID p_window_id) const { + // TODO: Use window IDs for multiwindow support. + const WindowState &ws = main_window; + + return ws.mode; +} + +void WaylandThread::window_request_attention(DisplayServer::WindowID p_window_id) { + // TODO: Use window IDs for multiwindow support. + WindowState &ws = main_window; + + if (registry.xdg_activation) { + // Window attention requests are done through the XDG activation protocol. + xdg_activation_token_v1 *xdg_activation_token = xdg_activation_v1_get_activation_token(registry.xdg_activation); + xdg_activation_token_v1_add_listener(xdg_activation_token, &xdg_activation_token_listener, &ws); + xdg_activation_token_v1_commit(xdg_activation_token); + } +} + +void WaylandThread::window_set_idle_inhibition(DisplayServer::WindowID p_window_id, bool p_enable) { + // TODO: Use window IDs for multiwindow support. + WindowState &ws = main_window; + + if (p_enable) { + if (ws.registry->wp_idle_inhibit_manager && !ws.wp_idle_inhibitor) { + ERR_FAIL_NULL(ws.wl_surface); + ws.wp_idle_inhibitor = zwp_idle_inhibit_manager_v1_create_inhibitor(ws.registry->wp_idle_inhibit_manager, ws.wl_surface); + } + } else { + if (ws.wp_idle_inhibitor) { + zwp_idle_inhibitor_v1_destroy(ws.wp_idle_inhibitor); + ws.wp_idle_inhibitor = nullptr; + } + } +} + +bool WaylandThread::window_get_idle_inhibition(DisplayServer::WindowID p_window_id) const { + // TODO: Use window IDs for multiwindow support. + const WindowState &ws = main_window; + + return ws.wp_idle_inhibitor != nullptr; +} + +WaylandThread::ScreenData WaylandThread::screen_get_data(int p_screen) const { + ERR_FAIL_INDEX_V(p_screen, registry.wl_outputs.size(), ScreenData()); + + return wl_output_get_screen_state(registry.wl_outputs[p_screen])->data; +} + +int WaylandThread::get_screen_count() const { + return registry.wl_outputs.size(); +} + +DisplayServer::WindowID WaylandThread::pointer_get_pointed_window_id() const { + SeatState *ss = wl_seat_get_seat_state(wl_seat_current); + + if (ss) { + WindowState *ws = wl_surface_get_window_state(ss->pointed_surface); + + if (ws) { + return ws->id; + } + } + + return DisplayServer::INVALID_WINDOW_ID; +} + +void WaylandThread::pointer_set_constraint(PointerConstraint p_constraint) { + SeatState *ss = wl_seat_get_seat_state(wl_seat_current); + + if (ss) { + seat_state_unlock_pointer(ss); + + if (p_constraint == PointerConstraint::LOCKED) { + seat_state_lock_pointer(ss); + } else if (p_constraint == PointerConstraint::CONFINED) { + seat_state_confine_pointer(ss); + } + } + + pointer_constraint = p_constraint; +} + +void WaylandThread::pointer_set_hint(const Point2i &p_hint) { + SeatState *ss = wl_seat_get_seat_state(wl_seat_current); + if (!ss) { + return; + } + + WindowState *ws = wl_surface_get_window_state(ss->pointed_surface); + + int hint_x = 0; + int hint_y = 0; + + if (ws) { + // NOTE: It looks like it's not really recommended to convert from + // "godot-space" to "wayland-space" and in general I received mixed feelings + // discussing about this. I'm not really sure about the maths behind this but, + // oh well, we're setting a cursor hint. ¯\_(ツ)_/¯ + // See: https://oftc.irclog.whitequark.org/wayland/2023-08-23#1692756914-1692816818 + hint_x = round(p_hint.x / window_state_get_scale_factor(ws)); + hint_y = round(p_hint.y / window_state_get_scale_factor(ws)); + } + + if (ss) { + seat_state_set_hint(ss, hint_x, hint_y); + } +} + +WaylandThread::PointerConstraint WaylandThread::pointer_get_constraint() const { + return pointer_constraint; +} + +BitField WaylandThread::pointer_get_button_mask() const { + SeatState *ss = wl_seat_get_seat_state(wl_seat_current); + + if (ss) { + return ss->pointer_data.pressed_button_mask; + } + + return BitField(); +} + +Error WaylandThread::init() { +#ifdef SOWRAP_ENABLED +#ifdef DEBUG_ENABLED + int dylibloader_verbose = 1; +#else + int dylibloader_verbose = 0; +#endif // DEBUG_ENABLED + + if (initialize_wayland_client(dylibloader_verbose) != 0) { + WARN_PRINT("Can't load the Wayland client library."); + return ERR_CANT_CREATE; + } + + if (initialize_wayland_cursor(dylibloader_verbose) != 0) { + WARN_PRINT("Can't load the Wayland cursor library."); + return ERR_CANT_CREATE; + } + + if (initialize_xkbcommon(dylibloader_verbose) != 0) { + WARN_PRINT("Can't load the XKBcommon library."); + return ERR_CANT_CREATE; + } +#endif // SOWRAP_ENABLED + + KeyMappingXKB::initialize(); + + wl_display = wl_display_connect(nullptr); + ERR_FAIL_NULL_V_MSG(wl_display, ERR_CANT_CREATE, "Can't connect to a Wayland display."); + + thread_data.wl_display = wl_display; + + events_thread.start(_poll_events_thread, &thread_data); + + wl_registry = wl_display_get_registry(wl_display); + + ERR_FAIL_NULL_V_MSG(wl_registry, ERR_UNAVAILABLE, "Can't obtain the Wayland registry global."); + + registry.wayland_thread = this; + + wl_registry_add_listener(wl_registry, &wl_registry_listener, ®istry); + + // Wait for registry to get notified from the compositor. + wl_display_roundtrip(wl_display); + + ERR_FAIL_NULL_V_MSG(registry.wl_shm, ERR_UNAVAILABLE, "Can't obtain the Wayland shared memory global."); + ERR_FAIL_NULL_V_MSG(registry.wl_compositor, ERR_UNAVAILABLE, "Can't obtain the Wayland compositor global."); + ERR_FAIL_NULL_V_MSG(registry.wl_subcompositor, ERR_UNAVAILABLE, "Can't obtain the Wayland subcompositor global."); + ERR_FAIL_NULL_V_MSG(registry.wl_data_device_manager, ERR_UNAVAILABLE, "Can't obtain the Wayland data device manager global."); + ERR_FAIL_NULL_V_MSG(registry.wp_pointer_constraints, ERR_UNAVAILABLE, "Can't obtain the Wayland pointer constraints global."); + ERR_FAIL_NULL_V_MSG(registry.xdg_wm_base, ERR_UNAVAILABLE, "Can't obtain the Wayland XDG shell global."); + + if (!registry.xdg_decoration_manager) { +#ifdef LIBDECOR_ENABLED + WARN_PRINT("Can't obtain the XDG decoration manager. Libdecor will be used for drawing CSDs, if available."); +#else + WARN_PRINT("Can't obtain the XDG decoration manager. Decorations won't show up."); +#endif // LIBDECOR_ENABLED + } + + if (!registry.xdg_activation) { + WARN_PRINT("Can't obtain the XDG activation global. Attention requesting won't work!"); + } + +#ifndef DBUS_ENABLED + if (!registry.wp_idle_inhibit_manager) { + WARN_PRINT("Can't obtain the idle inhibition manager. The screen might turn off even after calling screen_set_keep_on()!"); + } +#endif // DBUS_ENABLED + + // Wait for seat capabilities. + wl_display_roundtrip(wl_display); + +#ifdef LIBDECOR_ENABLED + bool libdecor_found = true; + +#ifdef SOWRAP_ENABLED + if (initialize_libdecor(dylibloader_verbose) != 0) { + libdecor_found = false; + } +#endif // SOWRAP_ENABLED + + if (libdecor_found) { + libdecor_context = libdecor_new(wl_display, (struct libdecor_interface *)&libdecor_interface); + } else { + print_verbose("libdecor not found. Client-side decorations disabled."); + } +#endif // LIBDECOR_ENABLED + + cursor_theme_name = OS::get_singleton()->get_environment("XCURSOR_THEME"); + + unscaled_cursor_size = OS::get_singleton()->get_environment("XCURSOR_SIZE").to_int(); + if (unscaled_cursor_size <= 0) { + print_verbose("Detected invalid cursor size preference, defaulting to 24."); + unscaled_cursor_size = 24; + } + + // NOTE: The scale is useful here as it might've been updated by _update_scale. + bool cursor_theme_loaded = _load_cursor_theme(unscaled_cursor_size * cursor_scale); + + if (!cursor_theme_loaded) { + return ERR_CANT_CREATE; + } + + // Update the cursor. + cursor_set_shape(DisplayServer::CURSOR_ARROW); + + initialized = true; + return OK; +} + +void WaylandThread::cursor_hide() { + current_wl_cursor = nullptr; + current_custom_cursor = nullptr; + + SeatState *ss = wl_seat_get_seat_state(wl_seat_current); + ERR_FAIL_NULL(ss); + seat_state_update_cursor(ss); +} + +void WaylandThread::cursor_set_shape(DisplayServer::CursorShape p_cursor_shape) { + if (!wl_cursors[p_cursor_shape]) { + return; + } + + // The point of this method is make the current cursor a "plain" shape and, as + // the custom cursor overrides what gets set, we have to clear it too. + current_custom_cursor = nullptr; + + current_wl_cursor = wl_cursors[p_cursor_shape]; + + for (struct wl_seat *wl_seat : registry.wl_seats) { + SeatState *ss = wl_seat_get_seat_state(wl_seat); + ERR_FAIL_NULL(ss); + + seat_state_update_cursor(ss); + } + + last_cursor_shape = p_cursor_shape; +} + +void WaylandThread::cursor_set_custom_shape(DisplayServer::CursorShape p_cursor_shape) { + ERR_FAIL_COND(!custom_cursors.has(p_cursor_shape)); + + current_custom_cursor = &custom_cursors[p_cursor_shape]; + + for (struct wl_seat *wl_seat : registry.wl_seats) { + SeatState *ss = wl_seat_get_seat_state(wl_seat); + ERR_FAIL_NULL(ss); + + seat_state_update_cursor(ss); + } + + last_cursor_shape = p_cursor_shape; +} + +void WaylandThread::cursor_shape_set_custom_image(DisplayServer::CursorShape p_cursor_shape, Ref p_image, const Point2i &p_hotspot) { + ERR_FAIL_COND(!p_image.is_valid()); + + Size2i image_size = p_image->get_size(); + + // NOTE: The stride is the width of the image in bytes. + unsigned int image_stride = image_size.width * 4; + unsigned int data_size = image_stride * image_size.height; + + // We need a shared memory object file descriptor in order to create a + // wl_buffer through wl_shm. + int fd = WaylandThread::_allocate_shm_file(data_size); + ERR_FAIL_COND(fd == -1); + + CustomCursor &cursor = custom_cursors[p_cursor_shape]; + cursor.hotspot = p_hotspot; + + if (cursor.buffer_data) { + // Clean up the old buffer data. + munmap(cursor.buffer_data, cursor.buffer_data_size); + } + + cursor.buffer_data = (uint32_t *)mmap(NULL, data_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + + if (cursor.wl_buffer) { + // Clean up the old Wayland buffer. + wl_buffer_destroy(cursor.wl_buffer); + } + + // Create the Wayland buffer. + struct wl_shm_pool *wl_shm_pool = wl_shm_create_pool(registry.wl_shm, fd, image_size.height * data_size); + // TODO: Make sure that WL_SHM_FORMAT_ARGB8888 format is supported. It + // technically isn't garaunteed to be supported, but I think that'd be a + // pretty unlikely thing to stumble upon. + cursor.wl_buffer = wl_shm_pool_create_buffer(wl_shm_pool, 0, image_size.width, image_size.height, image_stride, WL_SHM_FORMAT_ARGB8888); + wl_shm_pool_destroy(wl_shm_pool); + + // Fill the cursor buffer with the image data. + for (unsigned int index = 0; index < (unsigned int)(image_size.width * image_size.height); index++) { + int row_index = floor(index / image_size.width); + int column_index = (index % int(image_size.width)); + + cursor.buffer_data[index] = p_image->get_pixel(column_index, row_index).to_argb32(); + + // Wayland buffers, unless specified, require associated alpha, so we'll just + // associate the alpha in-place. + uint8_t *pixel_data = (uint8_t *)&cursor.buffer_data[index]; + pixel_data[0] = pixel_data[0] * pixel_data[3] / 255; + pixel_data[1] = pixel_data[1] * pixel_data[3] / 255; + pixel_data[2] = pixel_data[2] * pixel_data[3] / 255; + } +} + +void WaylandThread::cursor_shape_clear_custom_image(DisplayServer::CursorShape p_cursor_shape) { + if (custom_cursors.has(p_cursor_shape)) { + CustomCursor cursor = custom_cursors[p_cursor_shape]; + custom_cursors.erase(p_cursor_shape); + + current_custom_cursor = nullptr; + + if (cursor.wl_buffer) { + wl_buffer_destroy(cursor.wl_buffer); + } + + if (cursor.buffer_data) { + munmap(cursor.buffer_data, cursor.buffer_data_size); + } + } +} + +int WaylandThread::keyboard_get_layout_count() const { + SeatState *ss = wl_seat_get_seat_state(wl_seat_current); + + if (ss && ss->xkb_keymap) { + return xkb_keymap_num_layouts(ss->xkb_keymap); + } + + return 0; +} + +int WaylandThread::keyboard_get_current_layout_index() const { + SeatState *ss = wl_seat_get_seat_state(wl_seat_current); + + if (ss) { + return ss->current_layout_index; + } + + return 0; +} + +void WaylandThread::keyboard_set_current_layout_index(int p_index) { + SeatState *ss = wl_seat_get_seat_state(wl_seat_current); + + if (ss) { + ss->current_layout_index = p_index; + } +} + +String WaylandThread::keyboard_get_layout_name(int p_index) const { + SeatState *ss = wl_seat_get_seat_state(wl_seat_current); + + if (ss && ss->xkb_keymap) { + String ret; + ret.parse_utf8(xkb_keymap_layout_get_name(ss->xkb_keymap, p_index)); + + return ret; + } + + return ""; +} + +Key WaylandThread::keyboard_get_key_from_physical(Key p_key) const { + SeatState *ss = wl_seat_get_seat_state(wl_seat_current); + + if (ss && ss->xkb_state) { + xkb_keycode_t xkb_keycode = KeyMappingXKB::get_xkb_keycode(p_key); + return KeyMappingXKB::get_keycode(xkb_state_key_get_one_sym(ss->xkb_state, xkb_keycode)); + } + + return Key::NONE; +} + +void WaylandThread::keyboard_echo_keys() { + SeatState *ss = wl_seat_get_seat_state(wl_seat_current); + + if (ss) { + seat_state_echo_keys(ss); + } +} + +void WaylandThread::selection_set_text(const String &p_text) { + SeatState *ss = wl_seat_get_seat_state(wl_seat_current); + + if (registry.wl_data_device_manager == nullptr) { + DEBUG_LOG_WAYLAND_THREAD("Couldn't set selection, wl_data_device_manager global not available."); + } + + if (ss == nullptr) { + DEBUG_LOG_WAYLAND_THREAD("Couldn't set selection, current seat not set."); + return; + } + + if (ss->wl_data_device == nullptr) { + DEBUG_LOG_WAYLAND_THREAD("Couldn't set selection, seat doesn't have wl_data_device."); + } + + ss->selection_data = p_text.to_utf8_buffer(); + + if (ss->wl_data_source_selection == nullptr) { + ss->wl_data_source_selection = wl_data_device_manager_create_data_source(registry.wl_data_device_manager); + wl_data_source_add_listener(ss->wl_data_source_selection, &wl_data_source_listener, ss); + wl_data_source_offer(ss->wl_data_source_selection, "text/plain;charset=utf-8"); + wl_data_source_offer(ss->wl_data_source_selection, "text/plain"); + } + + // TODO: Implement a good way of getting the latest serial from the user. + wl_data_device_set_selection(ss->wl_data_device, ss->wl_data_source_selection, MAX(ss->pointer_data.button_serial, ss->last_key_pressed_serial)); + + // Wait for the message to get to the server before continuing, otherwise the + // clipboard update might come with a delay. + wl_display_roundtrip(wl_display); +} + +bool WaylandThread::selection_has_mime(const String &p_mime) const { + SeatState *ss = wl_seat_get_seat_state(wl_seat_current); + + if (ss == nullptr) { + DEBUG_LOG_WAYLAND_THREAD("Couldn't get selection, current seat not set."); + return false; + } + + OfferState *os = wl_data_offer_get_offer_state(ss->wl_data_offer_selection); + if (!os) { + return false; + } + + return os->mime_types.has(p_mime); +} + +Vector WaylandThread::selection_get_mime(const String &p_mime) const { + SeatState *ss = wl_seat_get_seat_state(wl_seat_current); + if (ss == nullptr) { + DEBUG_LOG_WAYLAND_THREAD("Couldn't get selection, current seat not set."); + return Vector(); + } + + if (ss->wl_data_source_selection) { + // We have a source so the stuff we're pasting is ours. We'll have to pass the + // data directly or we'd stall waiting for Godot (ourselves) to send us the + // data :P + + OfferState *os = wl_data_offer_get_offer_state(ss->wl_data_offer_selection); + ERR_FAIL_NULL_V(os, Vector()); + + if (os->mime_types.has(p_mime)) { + // All righty, we're offering this type. Let's just return the data as is. + return ss->selection_data; + } + + // ... we don't offer that type. Oh well. + return Vector(); + } + + return _wl_data_offer_read(wl_display, p_mime.utf8(), ss->wl_data_offer_selection); +} + +bool WaylandThread::primary_has_mime(const String &p_mime) const { + SeatState *ss = wl_seat_get_seat_state(wl_seat_current); + + if (ss == nullptr) { + DEBUG_LOG_WAYLAND_THREAD("Couldn't get selection, current seat not set."); + return false; + } + + OfferState *os = wp_primary_selection_offer_get_offer_state(ss->wp_primary_selection_offer); + if (!os) { + return false; + } + + return os->mime_types.has(p_mime); +} + +Vector WaylandThread::primary_get_mime(const String &p_mime) const { + SeatState *ss = wl_seat_get_seat_state(wl_seat_current); + if (ss == nullptr) { + DEBUG_LOG_WAYLAND_THREAD("Couldn't get primary, current seat not set."); + return Vector(); + } + + if (ss->wp_primary_selection_source) { + // We have a source so the stuff we're pasting is ours. We'll have to pass the + // data directly or we'd stall waiting for Godot (ourselves) to send us the + // data :P + + OfferState *os = wp_primary_selection_offer_get_offer_state(ss->wp_primary_selection_offer); + ERR_FAIL_NULL_V(os, Vector()); + + if (os->mime_types.has(p_mime)) { + // All righty, we're offering this type. Let's just return the data as is. + return ss->selection_data; + } + + // ... we don't offer that type. Oh well. + return Vector(); + } + + return _wp_primary_selection_offer_read(wl_display, p_mime.utf8(), ss->wp_primary_selection_offer); +} + +void WaylandThread::primary_set_text(const String &p_text) { + SeatState *ss = wl_seat_get_seat_state(wl_seat_current); + + if (registry.wp_primary_selection_device_manager == nullptr) { + DEBUG_LOG_WAYLAND_THREAD("Couldn't set primary, protocol not available"); + return; + } + + if (ss == nullptr) { + DEBUG_LOG_WAYLAND_THREAD("Couldn't set primary, current seat not set."); + return; + } + + ss->primary_data = p_text.to_utf8_buffer(); + + if (ss->wp_primary_selection_source == nullptr) { + ss->wp_primary_selection_source = zwp_primary_selection_device_manager_v1_create_source(registry.wp_primary_selection_device_manager); + zwp_primary_selection_source_v1_add_listener(ss->wp_primary_selection_source, &wp_primary_selection_source_listener, ss); + zwp_primary_selection_source_v1_offer(ss->wp_primary_selection_source, "text/plain;charset=utf-8"); + zwp_primary_selection_source_v1_offer(ss->wp_primary_selection_source, "text/plain"); + } + + // TODO: Implement a good way of getting the latest serial from the user. + zwp_primary_selection_device_v1_set_selection(ss->wp_primary_selection_device, ss->wp_primary_selection_source, MAX(ss->pointer_data.button_serial, ss->last_key_pressed_serial)); + + // Wait for the message to get to the server before continuing, otherwise the + // clipboard update might come with a delay. + wl_display_roundtrip(wl_display); +} + +void WaylandThread::set_frame() { + frame = true; +} + +bool WaylandThread::get_reset_frame() { + bool old_frame = frame; + frame = false; + + return old_frame; +} + +void WaylandThread::destroy() { + if (!initialized) { + return; + } + + if (wl_display && events_thread.is_started()) { + thread_data.thread_done.set(); + + // By sending a roundtrip message we're unblocking the polling thread so that + // it can realize that it's done and also handle every event that's left. + wl_display_roundtrip(wl_display); + + events_thread.wait_to_finish(); + } + + if (main_window.wp_fractional_scale) { + wp_fractional_scale_v1_destroy(main_window.wp_fractional_scale); + } + + if (main_window.wp_viewport) { + wp_viewport_destroy(main_window.wp_viewport); + } + + if (main_window.frame_callback) { + wl_callback_destroy(main_window.frame_callback); + } + +#ifdef LIBDECOR_ENABLED + if (main_window.libdecor_frame) { + libdecor_frame_close(main_window.libdecor_frame); + } +#endif // LIBDECOR_ENABLED + + if (main_window.xdg_toplevel) { + xdg_toplevel_destroy(main_window.xdg_toplevel); + } + + if (main_window.xdg_surface) { + xdg_surface_destroy(main_window.xdg_surface); + } + + if (main_window.wl_surface) { + wl_surface_destroy(main_window.wl_surface); + } + + for (struct wl_seat *wl_seat : registry.wl_seats) { + SeatState *ss = wl_seat_get_seat_state(wl_seat); + ERR_FAIL_NULL(ss); + + wl_seat_destroy(wl_seat); + + xkb_context_unref(ss->xkb_context); + xkb_state_unref(ss->xkb_state); + xkb_keymap_unref(ss->xkb_keymap); + + if (ss->wl_keyboard) { + wl_keyboard_destroy(ss->wl_keyboard); + } + + if (ss->keymap_buffer) { + munmap((void *)ss->keymap_buffer, ss->keymap_buffer_size); + } + + if (ss->wl_pointer) { + wl_pointer_destroy(ss->wl_pointer); + } + + if (ss->cursor_frame_callback) { + // We don't need to set a null userdata for safety as the thread is done. + wl_callback_destroy(ss->cursor_frame_callback); + } + + if (ss->cursor_surface) { + wl_surface_destroy(ss->cursor_surface); + } + + if (ss->wl_data_device) { + wl_data_device_destroy(ss->wl_data_device); + } + + if (ss->wp_relative_pointer) { + zwp_relative_pointer_v1_destroy(ss->wp_relative_pointer); + } + + if (ss->wp_locked_pointer) { + zwp_locked_pointer_v1_destroy(ss->wp_locked_pointer); + } + + if (ss->wp_confined_pointer) { + zwp_confined_pointer_v1_destroy(ss->wp_confined_pointer); + } + +#if 0 + // FIXME: Broken. + if (ss->wp_tablet_seat) { + zwp_tablet_seat_v2_destroy(ss->wp_tablet_seat); + } +#endif + + for (struct zwp_tablet_tool_v2 *tool : ss->tablet_tools) { + zwp_tablet_tool_v2_destroy(tool); + } + + memdelete(ss); + } + + for (struct wl_output *wl_output : registry.wl_outputs) { + ERR_FAIL_NULL(wl_output); + + memdelete(wl_output_get_screen_state(wl_output)); + wl_output_destroy(wl_output); + } + + if (wl_cursor_theme) { + wl_cursor_theme_destroy(wl_cursor_theme); + } + + if (registry.wp_idle_inhibit_manager) { + zwp_idle_inhibit_manager_v1_destroy(registry.wp_idle_inhibit_manager); + } + + if (registry.wp_pointer_constraints) { + zwp_pointer_constraints_v1_destroy(registry.wp_pointer_constraints); + } + + if (registry.wp_pointer_gestures) { + zwp_pointer_gestures_v1_destroy(registry.wp_pointer_gestures); + } + + if (registry.wp_relative_pointer_manager) { + zwp_relative_pointer_manager_v1_destroy(registry.wp_relative_pointer_manager); + } + + if (registry.xdg_activation) { + xdg_activation_v1_destroy(registry.xdg_activation); + } + + if (registry.xdg_decoration_manager) { + zxdg_decoration_manager_v1_destroy(registry.xdg_decoration_manager); + } + + if (registry.wp_fractional_scale_manager) { + wp_fractional_scale_manager_v1_destroy(registry.wp_fractional_scale_manager); + } + + if (registry.wp_viewporter) { + wp_viewporter_destroy(registry.wp_viewporter); + } + + if (registry.xdg_wm_base) { + xdg_wm_base_destroy(registry.xdg_wm_base); + } + + if (registry.wl_shm) { + wl_shm_destroy(registry.wl_shm); + } + + if (registry.wl_subcompositor) { + wl_subcompositor_destroy(registry.wl_subcompositor); + } + + if (registry.wl_compositor) { + wl_compositor_destroy(registry.wl_compositor); + } + + if (wl_registry) { + wl_registry_destroy(wl_registry); + } + + if (wl_display) { + wl_display_disconnect(wl_display); + } +} + +#endif // WAYLAND_ENABLED diff --git a/platform/linuxbsd/wayland/wayland_thread.h b/platform/linuxbsd/wayland/wayland_thread.h new file mode 100644 index 00000000000..8591db43065 --- /dev/null +++ b/platform/linuxbsd/wayland/wayland_thread.h @@ -0,0 +1,930 @@ +/**************************************************************************/ +/* wayland_thread.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 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. */ +/**************************************************************************/ + +#ifndef WAYLAND_THREAD_H +#define WAYLAND_THREAD_H + +#ifdef WAYLAND_ENABLED + +#include "key_mapping_xkb.h" + +#ifdef SOWRAP_ENABLED +#include "wayland/dynwrappers/wayland-client-core-so_wrap.h" +#include "wayland/dynwrappers/wayland-cursor-so_wrap.h" +#include "wayland/dynwrappers/wayland-egl-core-so_wrap.h" +#include "xkbcommon-so_wrap.h" +#else +#include +#include +#include +#endif // SOWRAP_ENABLED + +// These must go after the Wayland client include to work properly. +#include "wayland/protocol/idle_inhibit.gen.h" +#include "wayland/protocol/primary_selection.gen.h" +// These three protocol headers name wl_pointer method arguments as `pointer`, +// which is the same name as X11's pointer typedef. This trips some very +// annoying shadowing warnings. A `#define` works around this issue. +#define pointer wl_pointer +#include "wayland/protocol/pointer_constraints.gen.h" +#include "wayland/protocol/pointer_gestures.gen.h" +#include "wayland/protocol/relative_pointer.gen.h" +#undef pointer +#include "wayland/protocol/fractional_scale.gen.h" +#include "wayland/protocol/tablet.gen.h" +#include "wayland/protocol/viewporter.gen.h" +#include "wayland/protocol/wayland.gen.h" +#include "wayland/protocol/xdg_activation.gen.h" +#include "wayland/protocol/xdg_decoration.gen.h" +#include "wayland/protocol/xdg_shell.gen.h" + +#ifdef LIBDECOR_ENABLED +#ifdef SOWRAP_ENABLED +#include "dynwrappers/libdecor-so_wrap.h" +#else +#include +#endif // SOWRAP_ENABLED +#endif // LIBDECOR_ENABLED + +#include "core/os/thread.h" +#include "servers/display_server.h" + +class WaylandThread { +public: + // Messages used for exchanging information between Godot's and Wayland's thread. + class Message : public RefCounted { + public: + Message() {} + virtual ~Message() = default; + }; + + // Message data for window rect changes. + class WindowRectMessage : public Message { + public: + // NOTE: This is in "scaled" terms. For example, if there's a 1920x1080 rect + // with a scale factor of 2, the actual value of `rect` will be 3840x2160. + Rect2i rect; + }; + + class WindowEventMessage : public Message { + public: + DisplayServer::WindowEvent event; + }; + + class InputEventMessage : public Message { + public: + Ref event; + }; + + class DropFilesEventMessage : public Message { + public: + Vector files; + }; + + struct RegistryState { + WaylandThread *wayland_thread; + + // Core Wayland globals. + struct wl_shm *wl_shm = nullptr; + uint32_t wl_shm_name = 0; + + struct wl_compositor *wl_compositor = nullptr; + uint32_t wl_compositor_name = 0; + + struct wl_subcompositor *wl_subcompositor = nullptr; + uint32_t wl_subcompositor_name = 0; + + struct wl_data_device_manager *wl_data_device_manager = nullptr; + uint32_t wl_data_device_manager_name = 0; + + List wl_outputs; + List wl_seats; + + // xdg-shell globals. + + struct xdg_wm_base *xdg_wm_base = nullptr; + uint32_t xdg_wm_base_name = 0; + + // wayland-protocols globals. + + struct wp_viewporter *wp_viewporter = nullptr; + uint32_t wp_viewporter_name = 0; + + struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager = nullptr; + uint32_t wp_fractional_scale_manager_name = 0; + + struct zxdg_decoration_manager_v1 *xdg_decoration_manager = nullptr; + uint32_t xdg_decoration_manager_name = 0; + + struct xdg_activation_v1 *xdg_activation = nullptr; + uint32_t xdg_activation_name = 0; + + struct zwp_primary_selection_device_manager_v1 *wp_primary_selection_device_manager = nullptr; + uint32_t wp_primary_selection_device_manager_name = 0; + + struct zwp_relative_pointer_manager_v1 *wp_relative_pointer_manager = nullptr; + uint32_t wp_relative_pointer_manager_name = 0; + + struct zwp_pointer_constraints_v1 *wp_pointer_constraints = nullptr; + uint32_t wp_pointer_constraints_name = 0; + + struct zwp_pointer_gestures_v1 *wp_pointer_gestures = nullptr; + uint32_t wp_pointer_gestures_name = 0; + + struct zwp_idle_inhibit_manager_v1 *wp_idle_inhibit_manager = nullptr; + uint32_t wp_idle_inhibit_manager_name = 0; + + struct zwp_tablet_manager_v2 *wp_tablet_manager = nullptr; + uint32_t wp_tablet_manager_name = 0; + }; + + // General Wayland-specific states. Shouldn't be accessed directly. + // TODO: Make private? + + struct WindowState { + DisplayServer::WindowID id; + + Rect2i rect; + DisplayServer::WindowMode mode = DisplayServer::WINDOW_MODE_WINDOWED; + + // These are true by default as it isn't guaranteed that we'll find an + // xdg-shell implementation with wm_capabilities available. If and once we + // receive a wm_capabilities event these will get reset and updated with + // whatever the compositor says. + bool can_minimize = false; + bool can_maximize = false; + bool can_fullscreen = false; + + HashSet wl_outputs; + + // NOTE: If for whatever reason this callback is destroyed _while_ the event + // thread is still running, it might be a good idea to set its user data to + // `nullptr`. From some initial testing of mine, it looks like it might still + // be called even after being destroyed, pointing to probably invalid window + // data by then and segfaulting hard. + struct wl_callback *frame_callback = nullptr; + + struct wl_surface *wl_surface = nullptr; + struct xdg_surface *xdg_surface = nullptr; + struct xdg_toplevel *xdg_toplevel = nullptr; + + struct wp_viewport *wp_viewport = nullptr; + struct wp_fractional_scale_v1 *wp_fractional_scale = nullptr; + + // Currently applied buffer scale. + int buffer_scale = 1; + + // Buffer scale must be applied right before rendering but _after_ committing + // everything else or otherwise we might have an inconsistent state (e.g. + // double scale and odd resolution). This flag assists with that; when set, + // on the next frame, we'll commit whatever is set in `buffer_scale`. + bool buffer_scale_changed = false; + + // NOTE: The preferred buffer scale is currently only dynamically calculated. + // It can be accessed by calling `window_state_get_preferred_buffer_scale`. + + // Override used by the fractional scale add-on object. If less or equal to 0 + // (default) then the normal output-based scale is used instead. + double fractional_scale = 0; + + // What the compositor is recommending us. + double preferred_fractional_scale = 0; + + struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration = nullptr; + + struct zwp_idle_inhibitor_v1 *wp_idle_inhibitor = nullptr; + +#ifdef LIBDECOR_ENABLED + // If this is null the xdg_* variables must be set and vice-versa. This way we + // can handle this mess gracefully enough to hopefully being able of getting + // rid of this cleanly once we have our own CSDs. + struct libdecor_frame *libdecor_frame = nullptr; + struct libdecor_configuration *pending_libdecor_configuration = nullptr; +#endif + + RegistryState *registry; + WaylandThread *wayland_thread; + }; + + // "High level" Godot-side screen data. + struct ScreenData { + // Geometry data. + Point2i position; + + String make; + String model; + + Size2i size; + Size2i physical_size; + + float refresh_rate = -1; + int scale = 1; + }; + + struct ScreenState { + uint32_t wl_output_name = 0; + + ScreenData pending_data; + ScreenData data; + + WaylandThread *wayland_thread; + }; + + enum class Gesture { + NONE, + MAGNIFY, + }; + + enum class PointerConstraint { + NONE, + LOCKED, + CONFINED, + }; + + struct PointerData { + Point2i position; + uint32_t motion_time = 0; + + // Relative motion has its own optional event and so needs its own time. + Vector2 relative_motion; + uint32_t relative_motion_time = 0; + + BitField pressed_button_mask; + + MouseButton last_button_pressed = MouseButton::NONE; + Point2i last_pressed_position; + + // This is needed to check for a new double click every time. + bool double_click_begun = false; + + uint32_t button_time = 0; + uint32_t button_serial = 0; + + uint32_t scroll_type = WL_POINTER_AXIS_SOURCE_WHEEL; + + // The amount "scrolled" in pixels, in each direction. + Vector2 scroll_vector; + + // The amount of scroll "clicks" in each direction. + Vector2i discrete_scroll_vector; + + uint32_t pinch_scale = 1; + }; + + struct TabletToolData { + Point2i position; + Vector2i tilt; + uint32_t pressure = 0; + + BitField pressed_button_mask; + + MouseButton last_button_pressed = MouseButton::NONE; + Point2i last_pressed_position; + + bool double_click_begun = false; + + // Note: the protocol doesn't have it (I guess that this isn't really meant to + // be used as a mouse...), but we'll hack one in with the current ticks. + uint64_t button_time = 0; + + bool is_eraser = false; + + bool in_proximity = false; + bool touching = false; + }; + + struct OfferState { + HashSet mime_types; + }; + + struct SeatState { + RegistryState *registry = nullptr; + + WaylandThread *wayland_thread = nullptr; + + struct wl_seat *wl_seat = nullptr; + uint32_t wl_seat_name = 0; + + // Pointer. + struct wl_pointer *wl_pointer = nullptr; + + uint32_t pointer_enter_serial = 0; + + struct wl_surface *pointed_surface = nullptr; + struct wl_surface *last_pointed_surface = nullptr; + + struct zwp_relative_pointer_v1 *wp_relative_pointer = nullptr; + struct zwp_locked_pointer_v1 *wp_locked_pointer = nullptr; + struct zwp_confined_pointer_v1 *wp_confined_pointer = nullptr; + + struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch = nullptr; + + // NOTE: According to the wp_pointer_gestures protocol specification, there + // can be only one active gesture at a time. + Gesture active_gesture = Gesture::NONE; + + // Used for delta calculations. + // NOTE: The wp_pointer_gestures protocol keeps track of the total scale of + // the pinch gesture, while godot instead wants its delta. + wl_fixed_t old_pinch_scale = 0; + + struct wl_surface *cursor_surface = nullptr; + struct wl_callback *cursor_frame_callback = nullptr; + uint32_t cursor_time_ms = 0; + + // This variable is needed to buffer all pointer changes until a + // wl_pointer.frame event, as per Wayland's specification. Everything is + // first set in `data_buffer` and then `data` is set with its contents on + // an input frame event. All methods should generally read from + // `pointer_data` and write to `data_buffer`. + PointerData pointer_data_buffer; + PointerData pointer_data; + + // Keyboard. + struct wl_keyboard *wl_keyboard = nullptr; + + struct xkb_context *xkb_context = nullptr; + struct xkb_keymap *xkb_keymap = nullptr; + struct xkb_state *xkb_state = nullptr; + + const char *keymap_buffer = nullptr; + uint32_t keymap_buffer_size = 0; + + xkb_layout_index_t current_layout_index = 0; + + int32_t repeat_key_delay_msec = 0; + int32_t repeat_start_delay_msec = 0; + + xkb_keycode_t repeating_keycode = XKB_KEYCODE_INVALID; + uint64_t last_repeat_start_msec = 0; + uint64_t last_repeat_msec = 0; + + bool shift_pressed = false; + bool ctrl_pressed = false; + bool alt_pressed = false; + bool meta_pressed = false; + + uint32_t last_key_pressed_serial = 0; + + struct wl_data_device *wl_data_device = nullptr; + + // Drag and drop. + struct wl_data_offer *wl_data_offer_dnd = nullptr; + uint32_t dnd_enter_serial = 0; + + // Clipboard. + struct wl_data_source *wl_data_source_selection = nullptr; + Vector selection_data; + + struct wl_data_offer *wl_data_offer_selection = nullptr; + + // Primary selection. + struct zwp_primary_selection_device_v1 *wp_primary_selection_device = nullptr; + + struct zwp_primary_selection_source_v1 *wp_primary_selection_source = nullptr; + Vector primary_data; + + struct zwp_primary_selection_offer_v1 *wp_primary_selection_offer = nullptr; + + // Tablet. + struct zwp_tablet_seat_v2 *wp_tablet_seat = nullptr; + + List tablet_tools; + + TabletToolData tablet_tool_data_buffer; + TabletToolData tablet_tool_data; + }; + + struct CustomCursor { + struct wl_buffer *wl_buffer = nullptr; + uint32_t *buffer_data = nullptr; + uint32_t buffer_data_size = 0; + + RID rid; + Point2i hotspot; + }; + +private: + struct ThreadData { + SafeFlag thread_done; + Mutex mutex; + + struct wl_display *wl_display = nullptr; + }; + + // FIXME: Is this the right thing to do? + inline static const char *proxy_tag = "godot"; + + Thread events_thread; + ThreadData thread_data; + + WindowState main_window; + + List> messages; + + String cursor_theme_name; + int unscaled_cursor_size = 24; + + // NOTE: Regarding screen scale handling, the cursor cache is currently + // "static", by which I mean that we try to change it as little as possible and + // thus will be as big as the largest screen. This is mainly due to the fact + // that doing it dynamically doesn't look like it's worth it to me currently, + // especially as usually screen scales don't change continuously. + int cursor_scale = 1; + + struct wl_cursor_theme *wl_cursor_theme = nullptr; + struct wl_cursor *wl_cursors[DisplayServer::CURSOR_MAX] = {}; + + HashMap custom_cursors; + + struct wl_cursor *current_wl_cursor = nullptr; + struct CustomCursor *current_custom_cursor = nullptr; + + DisplayServer::CursorShape last_cursor_shape = DisplayServer::CURSOR_ARROW; + + PointerConstraint pointer_constraint = PointerConstraint::NONE; + + struct wl_display *wl_display = nullptr; + struct wl_registry *wl_registry = nullptr; + + struct wl_seat *wl_seat_current = nullptr; + + bool frame = true; + + RegistryState registry; + + bool initialized = false; + +#ifdef LIBDECOR_ENABLED + struct libdecor *libdecor_context = nullptr; +#endif // LIBDECOR_ENABLED + + // Main polling method. + static void _poll_events_thread(void *p_data); + + // Core Wayland event handlers. + static void _wl_registry_on_global(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, uint32_t version); + static void _wl_registry_on_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name); + + static void _wl_surface_on_enter(void *data, struct wl_surface *wl_surface, struct wl_output *wl_output); + static void _wl_surface_on_leave(void *data, struct wl_surface *wl_surface, struct wl_output *wl_output); + + static void _frame_wl_callback_on_done(void *data, struct wl_callback *wl_callback, uint32_t callback_data); + + static void _wl_output_on_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char *make, const char *model, int32_t transform); + static void _wl_output_on_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh); + static void _wl_output_on_done(void *data, struct wl_output *wl_output); + static void _wl_output_on_scale(void *data, struct wl_output *wl_output, int32_t factor); + static void _wl_output_on_name(void *data, struct wl_output *wl_output, const char *name); + static void _wl_output_on_description(void *data, struct wl_output *wl_output, const char *description); + + static void _wl_seat_on_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities); + static void _wl_seat_on_name(void *data, struct wl_seat *wl_seat, const char *name); + + static void _cursor_frame_callback_on_done(void *data, struct wl_callback *wl_callback, uint32_t time_ms); + + static void _wl_pointer_on_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y); + static void _wl_pointer_on_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface); + static void _wl_pointer_on_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y); + static void _wl_pointer_on_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state); + static void _wl_pointer_on_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value); + static void _wl_pointer_on_frame(void *data, struct wl_pointer *wl_pointer); + static void _wl_pointer_on_axis_source(void *data, struct wl_pointer *wl_pointer, uint32_t axis_source); + static void _wl_pointer_on_axis_stop(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis); + static void _wl_pointer_on_axis_discrete(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete); + static void _wl_pointer_on_axis_value120(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t value120); + + static void _wl_keyboard_on_keymap(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size); + static void _wl_keyboard_on_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys); + static void _wl_keyboard_on_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface); + static void _wl_keyboard_on_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state); + static void _wl_keyboard_on_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group); + static void _wl_keyboard_on_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay); + + static void _wl_data_device_on_data_offer(void *data, struct wl_data_device *wl_data_device, struct wl_data_offer *id); + static void _wl_data_device_on_enter(void *data, struct wl_data_device *wl_data_device, uint32_t serial, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *id); + static void _wl_data_device_on_leave(void *data, struct wl_data_device *wl_data_device); + static void _wl_data_device_on_motion(void *data, struct wl_data_device *wl_data_device, uint32_t time, wl_fixed_t x, wl_fixed_t y); + static void _wl_data_device_on_drop(void *data, struct wl_data_device *wl_data_device); + static void _wl_data_device_on_selection(void *data, struct wl_data_device *wl_data_device, struct wl_data_offer *id); + + static void _wl_data_offer_on_offer(void *data, struct wl_data_offer *wl_data_offer, const char *mime_type); + static void _wl_data_offer_on_source_actions(void *data, struct wl_data_offer *wl_data_offer, uint32_t source_actions); + static void _wl_data_offer_on_action(void *data, struct wl_data_offer *wl_data_offer, uint32_t dnd_action); + + static void _wl_data_source_on_target(void *data, struct wl_data_source *wl_data_source, const char *mime_type); + static void _wl_data_source_on_send(void *data, struct wl_data_source *wl_data_source, const char *mime_type, int32_t fd); + static void _wl_data_source_on_cancelled(void *data, struct wl_data_source *wl_data_source); + static void _wl_data_source_on_dnd_drop_performed(void *data, struct wl_data_source *wl_data_source); + static void _wl_data_source_on_dnd_finished(void *data, struct wl_data_source *wl_data_source); + static void _wl_data_source_on_action(void *data, struct wl_data_source *wl_data_source, uint32_t dnd_action); + + // xdg-shell event handlers. + static void _xdg_wm_base_on_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial); + + static void _xdg_surface_on_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial); + + static void _xdg_toplevel_on_configure(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *states); + static void _xdg_toplevel_on_close(void *data, struct xdg_toplevel *xdg_toplevel); + static void _xdg_toplevel_on_configure_bounds(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height); + static void _xdg_toplevel_on_wm_capabilities(void *data, struct xdg_toplevel *xdg_toplevel, struct wl_array *capabilities); + + // wayland-protocols event handlers. + static void _wp_fractional_scale_on_preferred_scale(void *data, struct wp_fractional_scale_v1 *wp_fractional_scale_v1, uint32_t scale); + + static void _wp_relative_pointer_on_relative_motion(void *data, struct zwp_relative_pointer_v1 *wp_relative_pointer_v1, uint32_t uptime_hi, uint32_t uptime_lo, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel); + + static void _wp_pointer_gesture_pinch_on_begin(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, struct wl_surface *surface, uint32_t fingers); + static void _wp_pointer_gesture_pinch_on_update(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t time, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t scale, wl_fixed_t rotation); + static void _wp_pointer_gesture_pinch_on_end(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, int32_t cancelled); + + static void _wp_primary_selection_device_on_data_offer(void *data, struct zwp_primary_selection_device_v1 *wp_primary_selection_device_v1, struct zwp_primary_selection_offer_v1 *offer); + static void _wp_primary_selection_device_on_selection(void *data, struct zwp_primary_selection_device_v1 *wp_primary_selection_device_v1, struct zwp_primary_selection_offer_v1 *id); + + static void _wp_primary_selection_offer_on_offer(void *data, struct zwp_primary_selection_offer_v1 *zwp_primary_selection_offer_v1, const char *mime_type); + + static void _wp_primary_selection_source_on_send(void *data, struct zwp_primary_selection_source_v1 *wp_primary_selection_source_v1, const char *mime_type, int32_t fd); + static void _wp_primary_selection_source_on_cancelled(void *data, struct zwp_primary_selection_source_v1 *wp_primary_selection_source_v1); + + static void _wp_tablet_seat_on_tablet_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_v2 *id); + static void _wp_tablet_seat_on_tool_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_tool_v2 *id); + static void _wp_tablet_seat_on_pad_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_pad_v2 *id); + + static void _wp_tablet_tool_on_type(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t tool_type); + static void _wp_tablet_tool_on_hardware_serial(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t hardware_serial_hi, uint32_t hardware_serial_lo); + static void _wp_tablet_tool_on_hardware_id_wacom(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t hardware_id_hi, uint32_t hardware_id_lo); + static void _wp_tablet_tool_on_capability(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t capability); + static void _wp_tablet_tool_on_done(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2); + static void _wp_tablet_tool_on_removed(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2); + static void _wp_tablet_tool_on_proximity_in(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial, struct zwp_tablet_v2 *tablet, struct wl_surface *surface); + static void _wp_tablet_tool_on_proximity_out(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2); + static void _wp_tablet_tool_on_down(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial); + static void _wp_tablet_tool_on_up(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2); + static void _wp_tablet_tool_on_motion(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t x, wl_fixed_t y); + static void _wp_tablet_tool_on_pressure(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t pressure); + static void _wp_tablet_tool_on_distance(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t distance); + static void _wp_tablet_tool_on_tilt(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t tilt_x, wl_fixed_t tilt_y); + static void _wp_tablet_tool_on_rotation(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t degrees); + static void _wp_tablet_tool_on_slider(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, int32_t position); + static void _wp_tablet_tool_on_wheel(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t degrees, int32_t clicks); + static void _wp_tablet_tool_on_button(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial, uint32_t button, uint32_t state); + static void _wp_tablet_tool_on_frame(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t time); + + static void _xdg_toplevel_decoration_on_configure(void *data, struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration, uint32_t mode); + + static void _xdg_activation_token_on_done(void *data, struct xdg_activation_token_v1 *xdg_activation_token, const char *token); + + // Core Wayland event listeners. + static constexpr struct wl_registry_listener wl_registry_listener = { + .global = _wl_registry_on_global, + .global_remove = _wl_registry_on_global_remove, + }; + + static constexpr struct wl_surface_listener wl_surface_listener = { + .enter = _wl_surface_on_enter, + .leave = _wl_surface_on_leave, + }; + + static constexpr struct wl_callback_listener frame_wl_callback_listener { + .done = _frame_wl_callback_on_done, + }; + + static constexpr struct wl_output_listener wl_output_listener = { + .geometry = _wl_output_on_geometry, + .mode = _wl_output_on_mode, + .done = _wl_output_on_done, + .scale = _wl_output_on_scale, + .name = _wl_output_on_name, + .description = _wl_output_on_description, + }; + + static constexpr struct wl_seat_listener wl_seat_listener = { + .capabilities = _wl_seat_on_capabilities, + .name = _wl_seat_on_name, + }; + + static constexpr struct wl_callback_listener cursor_frame_callback_listener { + .done = _cursor_frame_callback_on_done, + }; + + static constexpr struct wl_pointer_listener wl_pointer_listener = { + .enter = _wl_pointer_on_enter, + .leave = _wl_pointer_on_leave, + .motion = _wl_pointer_on_motion, + .button = _wl_pointer_on_button, + .axis = _wl_pointer_on_axis, + .frame = _wl_pointer_on_frame, + .axis_source = _wl_pointer_on_axis_source, + .axis_stop = _wl_pointer_on_axis_stop, + .axis_discrete = _wl_pointer_on_axis_discrete, + .axis_value120 = _wl_pointer_on_axis_value120, + }; + + static constexpr struct wl_keyboard_listener wl_keyboard_listener = { + .keymap = _wl_keyboard_on_keymap, + .enter = _wl_keyboard_on_enter, + .leave = _wl_keyboard_on_leave, + .key = _wl_keyboard_on_key, + .modifiers = _wl_keyboard_on_modifiers, + .repeat_info = _wl_keyboard_on_repeat_info, + }; + + static constexpr struct wl_data_device_listener wl_data_device_listener = { + .data_offer = _wl_data_device_on_data_offer, + .enter = _wl_data_device_on_enter, + .leave = _wl_data_device_on_leave, + .motion = _wl_data_device_on_motion, + .drop = _wl_data_device_on_drop, + .selection = _wl_data_device_on_selection, + }; + + static constexpr struct wl_data_offer_listener wl_data_offer_listener = { + .offer = _wl_data_offer_on_offer, + .source_actions = _wl_data_offer_on_source_actions, + .action = _wl_data_offer_on_action, + }; + + static constexpr struct wl_data_source_listener wl_data_source_listener = { + .target = _wl_data_source_on_target, + .send = _wl_data_source_on_send, + .cancelled = _wl_data_source_on_cancelled, + .dnd_drop_performed = _wl_data_source_on_dnd_drop_performed, + .dnd_finished = _wl_data_source_on_dnd_finished, + .action = _wl_data_source_on_action, + }; + + // xdg-shell event listeners. + static constexpr struct xdg_wm_base_listener xdg_wm_base_listener = { + .ping = _xdg_wm_base_on_ping, + }; + + static constexpr struct xdg_surface_listener xdg_surface_listener = { + .configure = _xdg_surface_on_configure, + }; + + static constexpr struct xdg_toplevel_listener xdg_toplevel_listener = { + .configure = _xdg_toplevel_on_configure, + .close = _xdg_toplevel_on_close, + .configure_bounds = _xdg_toplevel_on_configure_bounds, + .wm_capabilities = _xdg_toplevel_on_wm_capabilities, + }; + + // wayland-protocols event listeners. + static constexpr struct wp_fractional_scale_v1_listener wp_fractional_scale_listener = { + .preferred_scale = _wp_fractional_scale_on_preferred_scale, + }; + + static constexpr struct zwp_relative_pointer_v1_listener wp_relative_pointer_listener = { + .relative_motion = _wp_relative_pointer_on_relative_motion, + }; + + static constexpr struct zwp_pointer_gesture_pinch_v1_listener wp_pointer_gesture_pinch_listener = { + .begin = _wp_pointer_gesture_pinch_on_begin, + .update = _wp_pointer_gesture_pinch_on_update, + .end = _wp_pointer_gesture_pinch_on_end, + }; + + static constexpr struct zwp_primary_selection_device_v1_listener wp_primary_selection_device_listener = { + .data_offer = _wp_primary_selection_device_on_data_offer, + .selection = _wp_primary_selection_device_on_selection, + }; + + static constexpr struct zwp_primary_selection_offer_v1_listener wp_primary_selection_offer_listener = { + .offer = _wp_primary_selection_offer_on_offer, + }; + + static constexpr struct zwp_primary_selection_source_v1_listener wp_primary_selection_source_listener = { + .send = _wp_primary_selection_source_on_send, + .cancelled = _wp_primary_selection_source_on_cancelled, + }; + + static constexpr struct zwp_tablet_seat_v2_listener wp_tablet_seat_listener = { + .tablet_added = _wp_tablet_seat_on_tablet_added, + .tool_added = _wp_tablet_seat_on_tool_added, + .pad_added = _wp_tablet_seat_on_pad_added, + }; + + static constexpr struct zwp_tablet_tool_v2_listener wp_tablet_tool_listener = { + .type = _wp_tablet_tool_on_type, + .hardware_serial = _wp_tablet_tool_on_hardware_serial, + .hardware_id_wacom = _wp_tablet_tool_on_hardware_id_wacom, + .capability = _wp_tablet_tool_on_capability, + .done = _wp_tablet_tool_on_done, + .removed = _wp_tablet_tool_on_removed, + .proximity_in = _wp_tablet_tool_on_proximity_in, + .proximity_out = _wp_tablet_tool_on_proximity_out, + .down = _wp_tablet_tool_on_down, + .up = _wp_tablet_tool_on_up, + .motion = _wp_tablet_tool_on_motion, + .pressure = _wp_tablet_tool_on_pressure, + .distance = _wp_tablet_tool_on_distance, + .tilt = _wp_tablet_tool_on_tilt, + .rotation = _wp_tablet_tool_on_rotation, + .slider = _wp_tablet_tool_on_slider, + .wheel = _wp_tablet_tool_on_wheel, + .button = _wp_tablet_tool_on_button, + .frame = _wp_tablet_tool_on_frame, + }; + + static constexpr struct zxdg_toplevel_decoration_v1_listener xdg_toplevel_decoration_listener = { + .configure = _xdg_toplevel_decoration_on_configure, + }; + + static constexpr struct xdg_activation_token_v1_listener xdg_activation_token_listener = { + .done = _xdg_activation_token_on_done, + }; + +#ifdef LIBDECOR_ENABLED + // libdecor event handlers. + static void libdecor_on_error(struct libdecor *context, enum libdecor_error error, const char *message); + + static void libdecor_frame_on_configure(struct libdecor_frame *frame, struct libdecor_configuration *configuration, void *user_data); + + static void libdecor_frame_on_close(struct libdecor_frame *frame, void *user_data); + + static void libdecor_frame_on_commit(struct libdecor_frame *frame, void *user_data); + + static void libdecor_frame_on_dismiss_popup(struct libdecor_frame *frame, const char *seat_name, void *user_data); + + // libdecor event listeners. + static constexpr struct libdecor_interface libdecor_interface = { + .error = libdecor_on_error, + .reserved0 = nullptr, + .reserved1 = nullptr, + .reserved2 = nullptr, + .reserved3 = nullptr, + .reserved4 = nullptr, + .reserved5 = nullptr, + .reserved6 = nullptr, + .reserved7 = nullptr, + .reserved8 = nullptr, + .reserved9 = nullptr, + }; + + static constexpr struct libdecor_frame_interface libdecor_frame_interface = { + .configure = libdecor_frame_on_configure, + .close = libdecor_frame_on_close, + .commit = libdecor_frame_on_commit, + .dismiss_popup = libdecor_frame_on_dismiss_popup, + .reserved0 = nullptr, + .reserved1 = nullptr, + .reserved2 = nullptr, + .reserved3 = nullptr, + .reserved4 = nullptr, + .reserved5 = nullptr, + .reserved6 = nullptr, + .reserved7 = nullptr, + .reserved8 = nullptr, + .reserved9 = nullptr, + }; +#endif // LIBDECOR_ENABLED + + static Vector _read_fd(int fd); + static int _allocate_shm_file(size_t size); + + static Vector _wl_data_offer_read(struct wl_display *wl_display, const char *p_mime, struct wl_data_offer *wl_data_offer); + static Vector _wp_primary_selection_offer_read(struct wl_display *wl_display, const char *p_mime, struct zwp_primary_selection_offer_v1 *wp_primary_selection_offer); + + static void _seat_state_set_current(WaylandThread::SeatState &p_ss); + static bool _seat_state_configure_key_event(WaylandThread::SeatState &p_seat, Ref p_event, xkb_keycode_t p_keycode, bool p_pressed); + + static void _wayland_state_update_cursor(); + + void _set_current_seat(struct wl_seat *p_seat); + + bool _load_cursor_theme(int p_cursor_size); + + void _update_scale(int p_scale); + +public: + Mutex &mutex = thread_data.mutex; + + struct wl_display *get_wl_display() const; + + // Core Wayland utilities for integrating with our own data structures. + static bool wl_proxy_is_godot(struct wl_proxy *p_proxy); + static void wl_proxy_tag_godot(struct wl_proxy *p_proxy); + + static WindowState *wl_surface_get_window_state(struct wl_surface *p_surface); + static ScreenState *wl_output_get_screen_state(struct wl_output *p_output); + static SeatState *wl_seat_get_seat_state(struct wl_seat *p_seat); + static OfferState *wl_data_offer_get_offer_state(struct wl_data_offer *p_offer); + + static OfferState *wp_primary_selection_offer_get_offer_state(struct zwp_primary_selection_offer_v1 *p_offer); + + void seat_state_unlock_pointer(SeatState *p_ss); + void seat_state_lock_pointer(SeatState *p_ss); + void seat_state_set_hint(SeatState *p_ss, int p_x, int p_y); + void seat_state_confine_pointer(SeatState *p_ss); + + static void seat_state_update_cursor(SeatState *p_ss); + + void seat_state_echo_keys(SeatState *p_ss); + + static int window_state_get_preferred_buffer_scale(WindowState *p_ws); + static double window_state_get_scale_factor(WindowState *p_ws); + static void window_state_update_size(WindowState *p_ws, int p_width, int p_height); + + static Vector2i scale_vector2i(const Vector2i &p_vector, double p_amount); + + void push_message(Ref message); + bool has_message(); + Ref pop_message(); + + void window_create(DisplayServer::WindowID p_window_id, int p_width, int p_height); + + struct wl_surface *window_get_wl_surface(DisplayServer::WindowID p_window_id) const; + + void window_set_max_size(DisplayServer::WindowID p_window_id, const Size2i &p_size); + void window_set_min_size(DisplayServer::WindowID p_window_id, const Size2i &p_size); + + bool window_can_set_mode(DisplayServer::WindowID p_window_id, DisplayServer::WindowMode p_window_mode) const; + void window_try_set_mode(DisplayServer::WindowID p_window_id, DisplayServer::WindowMode p_window_mode); + DisplayServer::WindowMode window_get_mode(DisplayServer::WindowID p_window_id) const; + + void window_set_borderless(DisplayServer::WindowID p_window_id, bool p_borderless); + void window_set_title(DisplayServer::WindowID p_window_id, const String &p_title); + void window_set_app_id(DisplayServer::WindowID p_window_id, const String &p_app_id); + + bool window_is_focused(DisplayServer::WindowID p_window_id); + + // Optional - requires xdg_activation_v1 + void window_request_attention(DisplayServer::WindowID p_window_id); + + // Optional - require idle_inhibit_unstable_v1 + void window_set_idle_inhibition(DisplayServer::WindowID p_window_id, bool p_enable); + bool window_get_idle_inhibition(DisplayServer::WindowID p_window_id) const; + + ScreenData screen_get_data(int p_screen) const; + int get_screen_count() const; + + void pointer_set_constraint(PointerConstraint p_constraint); + void pointer_set_hint(const Point2i &p_hint); + PointerConstraint pointer_get_constraint() const; + DisplayServer::WindowID pointer_get_pointed_window_id() const; + BitField pointer_get_button_mask() const; + + void cursor_hide(); + void cursor_set_shape(DisplayServer::CursorShape p_cursor_shape); + + void cursor_set_custom_shape(DisplayServer::CursorShape p_cursor_shape); + void cursor_shape_set_custom_image(DisplayServer::CursorShape p_cursor_shape, Ref p_image, const Point2i &p_hotspot); + void cursor_shape_clear_custom_image(DisplayServer::CursorShape p_cursor_shape); + + int keyboard_get_layout_count() const; + int keyboard_get_current_layout_index() const; + void keyboard_set_current_layout_index(int p_index); + String keyboard_get_layout_name(int p_index) const; + + Key keyboard_get_key_from_physical(Key p_key) const; + + void keyboard_echo_keys(); + + bool selection_has_mime(const String &p_mime) const; + Vector selection_get_mime(const String &p_mime) const; + + void selection_set_text(const String &p_text); + + // Optional primary support - requires wp_primary_selection_unstable_v1 + bool primary_has_mime(const String &p_mime) const; + Vector primary_get_mime(const String &p_mime) const; + + void primary_set_text(const String &p_text); + + void set_frame(); + bool get_reset_frame(); + + Error init(); + void destroy(); +}; + +#endif // WAYLAND_ENABLED + +#endif // WAYLAND_THREAD_H diff --git a/thirdparty/README.md b/thirdparty/README.md index 3fb990258e4..44ddc4bdd3c 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -931,6 +931,49 @@ https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/issues/318 Patches in the `patches` directory should be re-applied after updates. +## wayland + +- Upstream: https://gitlab.freedesktop.org/wayland/wayland +- Version: 1.21.0 (8135e856ebd79872f886466e9cee39affb7d9ee8, 2022) +- License: MIT + +Files extracted from upstream source: + +- `protocol/wayland.xml` +- `COPYING` + + +# wayland-protocols + +- Upstream: https://gitlab.freedesktop.org/wayland/wayland-protocols +- Version: 1.32 (681c33c8547d6aefe24455ba2bffe1c5ae11fee5, 2023) +- License: MIT + +Files extracted from upstream source: + +- `stable/viewporter/README` +- `stable/viewporter/viewporter.xml` +- `stable/xdg-shell/README` +- `stable/xdg-shell/xdg-shell.xml` +- `staging/fractional-scale/README` +- `staging/fractional-scale/fractional-scale-v1.xml` +- `staging/xdg-activation/README` +- `staging/xdg-activation/xdg-activation-v1.xml` +- `unstable/pointer-constraints/README` +- `unstable/pointer-constraints/pointer-constraints-unstable-v1.xml` +- `unstable/pointer-gestures/README` +- `unstable/pointer-gestures/pointer-gestures-unstable-v1.xml` +- `unstable/primary-selection/README` +- `unstable/primary-selection/primary-selection-unstable-v1.xml` +- `unstable/relative-pointer/README` +- `unstable/relative-pointer/relative-pointer-unstable-v1.xml` +- `unstable/tablet/README` +- `unstable/tablet/tablet-unstable-v2.xml` +- `unstable/xdg-decoration/README` +- `unstable/xdg-decoration/xdg-decoration-unstable-v1.xml` +- `COPYING` + + ## wslay - Upstream: https://github.com/tatsuhiro-t/wslay diff --git a/thirdparty/linuxbsd_headers/README.md b/thirdparty/linuxbsd_headers/README.md index 225dd62ad0d..48079806330 100644 --- a/thirdparty/linuxbsd_headers/README.md +++ b/thirdparty/linuxbsd_headers/README.md @@ -28,6 +28,13 @@ Patches in the `patches` directory should be re-applied after updates. - License: fontconfig +## libdecor + +- Upstream: https://gitlab.freedesktop.org/libdecor/libdecor/ +- Version: 0.1.1 +- License: MIT + + ## pulse - Upstream: http://pulseaudio.org/ @@ -49,6 +56,13 @@ Patches in the `patches` directory should be re-applied after updates. - License: LGPL-2.1+ +## wayland + +- Upstream: https://gitlab.freedesktop.org/wayland/wayland +- Version: 1.21.0 (8135e856ebd79872f886466e9cee39affb7d9ee8, 2022) +- License: MIT + + ## X11 - Upstream: https://x.org/wiki/ diff --git a/thirdparty/linuxbsd_headers/libdecor-0/libdecor.h b/thirdparty/linuxbsd_headers/libdecor-0/libdecor.h new file mode 100644 index 00000000000..c85d4f16a02 --- /dev/null +++ b/thirdparty/linuxbsd_headers/libdecor-0/libdecor.h @@ -0,0 +1,521 @@ +/* + * Copyright © 2017-2018 Red Hat Inc. + * Copyright © 2018 Jonas Ådahl + * + * 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. + */ + +#ifndef LIBDECOR_H +#define LIBDECOR_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__GNUC__) && __GNUC__ >= 4 +#define LIBDECOR_EXPORT __attribute__ ((visibility("default"))) +#else +#define LIBDECOR_EXPORT +#endif + +struct xdg_toplevel; + +/** \class libdecor + * + * \brief A libdecor context instance. + */ +struct libdecor; + +/** \class libdecor_frame + * + * \brief A frame used for decorating a Wayland surface. + */ +struct libdecor_frame; + +/** \class libdecor_configuration + * + * \brief An object representing a toplevel window configuration. + */ +struct libdecor_configuration; + +/** \class libdecor_state + * + * \brief An object corresponding to a configured content state. + */ +struct libdecor_state; + +enum libdecor_error { + LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE, + LIBDECOR_ERROR_INVALID_FRAME_CONFIGURATION, +}; + +enum libdecor_window_state { + LIBDECOR_WINDOW_STATE_NONE = 0, + LIBDECOR_WINDOW_STATE_ACTIVE = 1 << 0, + LIBDECOR_WINDOW_STATE_MAXIMIZED = 1 << 1, + LIBDECOR_WINDOW_STATE_FULLSCREEN = 1 << 2, + LIBDECOR_WINDOW_STATE_TILED_LEFT = 1 << 3, + LIBDECOR_WINDOW_STATE_TILED_RIGHT = 1 << 4, + LIBDECOR_WINDOW_STATE_TILED_TOP = 1 << 5, + LIBDECOR_WINDOW_STATE_TILED_BOTTOM = 1 << 6, +}; + +enum libdecor_resize_edge { + LIBDECOR_RESIZE_EDGE_NONE, + LIBDECOR_RESIZE_EDGE_TOP, + LIBDECOR_RESIZE_EDGE_BOTTOM, + LIBDECOR_RESIZE_EDGE_LEFT, + LIBDECOR_RESIZE_EDGE_TOP_LEFT, + LIBDECOR_RESIZE_EDGE_BOTTOM_LEFT, + LIBDECOR_RESIZE_EDGE_RIGHT, + LIBDECOR_RESIZE_EDGE_TOP_RIGHT, + LIBDECOR_RESIZE_EDGE_BOTTOM_RIGHT, +}; + +enum libdecor_capabilities { + LIBDECOR_ACTION_MOVE = 1 << 0, + LIBDECOR_ACTION_RESIZE = 1 << 1, + LIBDECOR_ACTION_MINIMIZE = 1 << 2, + LIBDECOR_ACTION_FULLSCREEN = 1 << 3, + LIBDECOR_ACTION_CLOSE = 1 << 4, +}; + +struct libdecor_interface { + /** + * An error event + */ + void (* error)(struct libdecor *context, + enum libdecor_error error, + const char *message); + + /* Reserved */ + void (* reserved0)(void); + void (* reserved1)(void); + void (* reserved2)(void); + void (* reserved3)(void); + void (* reserved4)(void); + void (* reserved5)(void); + void (* reserved6)(void); + void (* reserved7)(void); + void (* reserved8)(void); + void (* reserved9)(void); +}; + +/** + * Interface for integrating a Wayland surface with libdecor. + */ +struct libdecor_frame_interface { + /** + * A new configuration was received. An application should respond to + * this by creating a suitable libdecor_state, and apply it using + * libdecor_frame_commit. + */ + void (* configure)(struct libdecor_frame *frame, + struct libdecor_configuration *configuration, + void *user_data); + + /** + * The window was requested to be closed by the compositor. + */ + void (* close)(struct libdecor_frame *frame, + void *user_data); + + /** + * The window decoration asked to have the main surface to be + * committed. This is required when the decoration is implemented using + * synchronous subsurfaces. + */ + void (* commit)(struct libdecor_frame *frame, + void *user_data); + + /** + * Any mapped popup that has a grab on the given seat should be + * dismissed. + */ + void (* dismiss_popup)(struct libdecor_frame *frame, + const char *seat_name, + void *user_data); + + /* Reserved */ + void (* reserved0)(void); + void (* reserved1)(void); + void (* reserved2)(void); + void (* reserved3)(void); + void (* reserved4)(void); + void (* reserved5)(void); + void (* reserved6)(void); + void (* reserved7)(void); + void (* reserved8)(void); + void (* reserved9)(void); +}; + +/** + * Remove a reference to the libdecor instance. When the reference count + * reaches zero, it is freed. + */ +void +libdecor_unref(struct libdecor *context); + +/** + * Create a new libdecor context for the given wl_display. + */ +struct libdecor * +libdecor_new(struct wl_display *display, + struct libdecor_interface *iface); + +/** + * Get the file descriptor used by libdecor. This is similar to + * wl_display_get_fd(), thus should be polled, and when data is available, + * libdecor_dispatch() should be called. + */ +int +libdecor_get_fd(struct libdecor *context); + +/** + * Dispatch events. This function should be called when data is available on + * the file descriptor returned by libdecor_get_fd(). If timeout is zero, this + * function will never block. + */ +int +libdecor_dispatch(struct libdecor *context, + int timeout); + +/** + * Decorate the given content wl_surface. + * + * This will create an xdg_surface and an xdg_toplevel, and integrate it + * properly with the windowing system, including creating appropriate + * decorations when needed, as well as handle windowing integration events such + * as resizing, moving, maximizing, etc. + * + * The passed wl_surface should only contain actual application content, + * without any window decoration. + */ +struct libdecor_frame * +libdecor_decorate(struct libdecor *context, + struct wl_surface *surface, + struct libdecor_frame_interface *iface, + void *user_data); + +/** + * Add a reference to the frame object. + */ +void +libdecor_frame_ref(struct libdecor_frame *frame); + +/** + * Remove a reference to the frame object. When the reference count reaches + * zero, the frame object is destroyed. + */ +void +libdecor_frame_unref(struct libdecor_frame *frame); + +/** + * Set the visibility of the frame. + * + * If an application wants to be borderless, it can set the frame visibility to + * false. + */ +void +libdecor_frame_set_visibility(struct libdecor_frame *frame, + bool visible); + +/** + * Get the visibility of the frame. + */ +bool +libdecor_frame_is_visible(struct libdecor_frame *frame); + + +/** + * Set the parent of the window. + * + * This can be used to stack multiple toplevel windows above or under each + * other. + */ +void +libdecor_frame_set_parent(struct libdecor_frame *frame, + struct libdecor_frame *parent); + +/** + * Set the title of the window. + */ +void +libdecor_frame_set_title(struct libdecor_frame *frame, + const char *title); + +/** + * Get the title of the window. + */ +const char * +libdecor_frame_get_title(struct libdecor_frame *frame); + +/** + * Set the application ID of the window. + */ +void +libdecor_frame_set_app_id(struct libdecor_frame *frame, + const char *app_id); + +/** + * Set new capabilities of the window. + * + * This determines whether e.g. a window decoration should show a maximize + * button, etc. + * + * Setting a capability does not implicitly unset any other. + */ +void +libdecor_frame_set_capabilities(struct libdecor_frame *frame, + enum libdecor_capabilities capabilities); + +/** + * Unset capabilities of the window. + * + * The opposite of libdecor_frame_set_capabilities. + */ +void +libdecor_frame_unset_capabilities(struct libdecor_frame *frame, + enum libdecor_capabilities capabilities); + +/** + * Check whether the window has any of the given capabilities. + */ +bool +libdecor_frame_has_capability(struct libdecor_frame *frame, + enum libdecor_capabilities capability); + +/** + * Show the window menu. + */ +void +libdecor_frame_show_window_menu(struct libdecor_frame *frame, + struct wl_seat *wl_seat, + uint32_t serial, + int x, + int y); + +/** + * Issue a popup grab on the window. Call this when a xdg_popup is mapped, so + * that it can be properly dismissed by the decorations. + */ +void +libdecor_frame_popup_grab(struct libdecor_frame *frame, + const char *seat_name); + +/** + * Release the popup grab. Call this when you unmap a popup. + */ +void +libdecor_frame_popup_ungrab(struct libdecor_frame *frame, + const char *seat_name); + +/** + * Translate content surface local coordinates to toplevel window local + * coordinates. + * + * This can be used to translate surface coordinates to coordinates useful for + * e.g. showing the window menu, or positioning a popup. + */ +void +libdecor_frame_translate_coordinate(struct libdecor_frame *frame, + int surface_x, + int surface_y, + int *frame_x, + int *frame_y); + +/** + * Set the min content size. + * + * This translates roughly to xdg_toplevel_set_min_size(). + */ +void +libdecor_frame_set_min_content_size(struct libdecor_frame *frame, + int content_width, + int content_height); + +/** + * Set the max content size. + * + * This translates roughly to xdg_toplevel_set_max_size(). + */ +void +libdecor_frame_set_max_content_size(struct libdecor_frame *frame, + int content_width, + int content_height); + +/** + * Initiate an interactive resize. + * + * This roughly translates to xdg_toplevel_resize(). + */ +void +libdecor_frame_resize(struct libdecor_frame *frame, + struct wl_seat *wl_seat, + uint32_t serial, + enum libdecor_resize_edge edge); + +/** + * Initiate an interactive move. + * + * This roughly translates to xdg_toplevel_move(). + */ +void +libdecor_frame_move(struct libdecor_frame *frame, + struct wl_seat *wl_seat, + uint32_t serial); + +/** + * Commit a new window state. This can be called on application driven resizes + * when the window is floating, or in response to received configurations, i.e. + * from e.g. interactive resizes or state changes. + */ +void +libdecor_frame_commit(struct libdecor_frame *frame, + struct libdecor_state *state, + struct libdecor_configuration *configuration); + +/** + * Minimize the window. + * + * Roughly translates to xdg_toplevel_set_minimized(). + */ +void +libdecor_frame_set_minimized(struct libdecor_frame *frame); + +/** + * Maximize the window. + * + * Roughly translates to xdg_toplevel_set_maximized(). + */ +void +libdecor_frame_set_maximized(struct libdecor_frame *frame); + +/** + * Unmaximize the window. + * + * Roughly translates to xdg_toplevel_unset_maximized(). + */ +void +libdecor_frame_unset_maximized(struct libdecor_frame *frame); + +/** + * Fullscreen the window. + * + * Roughly translates to xdg_toplevel_set_fullscreen(). + */ +void +libdecor_frame_set_fullscreen(struct libdecor_frame *frame, + struct wl_output *output); + +/** + * Unfullscreen the window. + * + * Roughly translates to xdg_toplevel_unset_unfullscreen(). + */ +void +libdecor_frame_unset_fullscreen(struct libdecor_frame *frame); + +/** + * Return true if the window is floating. + * + * A window is floating when it's not maximized, tiled, fullscreen, or in any + * similar way with a fixed size and state. + * Note that this function uses the "applied" configuration. If this function + * is used in the 'configure' callback, the provided configuration has to be + * applied via 'libdecor_frame_commit' first, before it will reflect the current + * window state from the provided configuration. + */ +bool +libdecor_frame_is_floating(struct libdecor_frame *frame); + +/** + * Close the window. + * + * Roughly translates to xdg_toplevel_close(). + */ +void +libdecor_frame_close(struct libdecor_frame *frame); + +/** + * Map the window. + * + * This will eventually result in the initial configure event. + */ +void +libdecor_frame_map(struct libdecor_frame *frame); + +/** + * Get the associated xdg_surface for content wl_surface. + */ +struct xdg_surface * +libdecor_frame_get_xdg_surface(struct libdecor_frame *frame); + +/** + * Get the associated xdg_toplevel for the content wl_surface. + */ +struct xdg_toplevel * +libdecor_frame_get_xdg_toplevel(struct libdecor_frame *frame); + +/** + * Create a new content surface state. + */ +struct libdecor_state * +libdecor_state_new(int width, + int height); + +/** + * Free a content surface state. + */ +void +libdecor_state_free(struct libdecor_state *state); + +/** + * Get the expected size of the content for this configuration. + * + * If the configuration doesn't contain a size, false is returned. + */ +bool +libdecor_configuration_get_content_size(struct libdecor_configuration *configuration, + struct libdecor_frame *frame, + int *width, + int *height); + +/** + * Get the window state for this configuration. + * + * If the configuration doesn't contain any associated window state, false is + * returned, and the application should assume the window state remains + * unchanged. + */ +bool +libdecor_configuration_get_window_state(struct libdecor_configuration *configuration, + enum libdecor_window_state *window_state); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBDECOR_H */ diff --git a/thirdparty/linuxbsd_headers/wayland/wayland-client-core.h b/thirdparty/linuxbsd_headers/wayland/wayland-client-core.h new file mode 100644 index 00000000000..ce91a6f60a5 --- /dev/null +++ b/thirdparty/linuxbsd_headers/wayland/wayland-client-core.h @@ -0,0 +1,292 @@ +/* + * Copyright © 2008 Kristian Høgsberg + * + * 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. + */ + +#ifndef WAYLAND_CLIENT_CORE_H +#define WAYLAND_CLIENT_CORE_H + +#include +#include "wayland-util.h" +#include "wayland-version.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \class wl_proxy + * + * \brief Represents a protocol object on the client side. + * + * A wl_proxy acts as a client side proxy to an object existing in the + * compositor. The proxy is responsible for converting requests made by the + * clients with \ref wl_proxy_marshal() into Wayland's wire format. Events + * coming from the compositor are also handled by the proxy, which will in + * turn call the handler set with \ref wl_proxy_add_listener(). + * + * \note With the exception of function \ref wl_proxy_set_queue(), functions + * accessing a wl_proxy are not normally used by client code. Clients + * should normally use the higher level interface generated by the scanner to + * interact with compositor objects. + * + */ +struct wl_proxy; + +/** \class wl_display + * + * \brief Represents a connection to the compositor and acts as a proxy to + * the wl_display singleton object. + * + * A wl_display object represents a client connection to a Wayland + * compositor. It is created with either \ref wl_display_connect() or + * \ref wl_display_connect_to_fd(). A connection is terminated using + * \ref wl_display_disconnect(). + * + * A wl_display is also used as the \ref wl_proxy for the wl_display + * singleton object on the compositor side. + * + * A wl_display object handles all the data sent from and to the + * compositor. When a \ref wl_proxy marshals a request, it will write its wire + * representation to the display's write buffer. The data is sent to the + * compositor when the client calls \ref wl_display_flush(). + * + * Incoming data is handled in two steps: queueing and dispatching. In the + * queue step, the data coming from the display fd is interpreted and + * added to a queue. On the dispatch step, the handler for the incoming + * event set by the client on the corresponding \ref wl_proxy is called. + * + * A wl_display has at least one event queue, called the default + * queue. Clients can create additional event queues with \ref + * wl_display_create_queue() and assign \ref wl_proxy's to it. Events + * occurring in a particular proxy are always queued in its assigned queue. + * A client can ensure that a certain assumption, such as holding a lock + * or running from a given thread, is true when a proxy event handler is + * called by assigning that proxy to an event queue and making sure that + * this queue is only dispatched when the assumption holds. + * + * The default queue is dispatched by calling \ref wl_display_dispatch(). + * This will dispatch any events queued on the default queue and attempt + * to read from the display fd if it's empty. Events read are then queued + * on the appropriate queues according to the proxy assignment. + * + * A user created queue is dispatched with \ref wl_display_dispatch_queue(). + * This function behaves exactly the same as wl_display_dispatch() + * but it dispatches given queue instead of the default queue. + * + * A real world example of event queue usage is Mesa's implementation of + * eglSwapBuffers() for the Wayland platform. This function might need + * to block until a frame callback is received, but dispatching the default + * queue could cause an event handler on the client to start drawing + * again. This problem is solved using another event queue, so that only + * the events handled by the EGL code are dispatched during the block. + * + * This creates a problem where a thread dispatches a non-default + * queue, reading all the data from the display fd. If the application + * would call \em poll(2) after that it would block, even though there + * might be events queued on the default queue. Those events should be + * dispatched with \ref wl_display_dispatch_pending() or \ref + * wl_display_dispatch_queue_pending() before flushing and blocking. + */ +struct wl_display; + +/** \class wl_event_queue + * + * \brief A queue for \ref wl_proxy object events. + * + * Event queues allows the events on a display to be handled in a thread-safe + * manner. See \ref wl_display for details. + * + */ +struct wl_event_queue; + +/** Destroy proxy after marshalling + * @ingroup wl_proxy + */ +#define WL_MARSHAL_FLAG_DESTROY (1 << 0) + +void +wl_event_queue_destroy(struct wl_event_queue *queue); + +struct wl_proxy * +wl_proxy_marshal_flags(struct wl_proxy *proxy, uint32_t opcode, + const struct wl_interface *interface, + uint32_t version, + uint32_t flags, ...); + +struct wl_proxy * +wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode, + const struct wl_interface *interface, + uint32_t version, + uint32_t flags, + union wl_argument *args); + +void +wl_proxy_marshal(struct wl_proxy *p, uint32_t opcode, ...); + +void +wl_proxy_marshal_array(struct wl_proxy *p, uint32_t opcode, + union wl_argument *args); + +struct wl_proxy * +wl_proxy_create(struct wl_proxy *factory, + const struct wl_interface *interface); + +void * +wl_proxy_create_wrapper(void *proxy); + +void +wl_proxy_wrapper_destroy(void *proxy_wrapper); + +struct wl_proxy * +wl_proxy_marshal_constructor(struct wl_proxy *proxy, + uint32_t opcode, + const struct wl_interface *interface, + ...); + +struct wl_proxy * +wl_proxy_marshal_constructor_versioned(struct wl_proxy *proxy, + uint32_t opcode, + const struct wl_interface *interface, + uint32_t version, + ...); + +struct wl_proxy * +wl_proxy_marshal_array_constructor(struct wl_proxy *proxy, + uint32_t opcode, union wl_argument *args, + const struct wl_interface *interface); + +struct wl_proxy * +wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy, + uint32_t opcode, + union wl_argument *args, + const struct wl_interface *interface, + uint32_t version); + +void +wl_proxy_destroy(struct wl_proxy *proxy); + +int +wl_proxy_add_listener(struct wl_proxy *proxy, + void (**implementation)(void), void *data); + +const void * +wl_proxy_get_listener(struct wl_proxy *proxy); + +int +wl_proxy_add_dispatcher(struct wl_proxy *proxy, + wl_dispatcher_func_t dispatcher_func, + const void * dispatcher_data, void *data); + +void +wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data); + +void * +wl_proxy_get_user_data(struct wl_proxy *proxy); + +uint32_t +wl_proxy_get_version(struct wl_proxy *proxy); + +uint32_t +wl_proxy_get_id(struct wl_proxy *proxy); + +void +wl_proxy_set_tag(struct wl_proxy *proxy, + const char * const *tag); + +const char * const * +wl_proxy_get_tag(struct wl_proxy *proxy); + +const char * +wl_proxy_get_class(struct wl_proxy *proxy); + +void +wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue); + +struct wl_display * +wl_display_connect(const char *name); + +struct wl_display * +wl_display_connect_to_fd(int fd); + +void +wl_display_disconnect(struct wl_display *display); + +int +wl_display_get_fd(struct wl_display *display); + +int +wl_display_dispatch(struct wl_display *display); + +int +wl_display_dispatch_queue(struct wl_display *display, + struct wl_event_queue *queue); + +int +wl_display_dispatch_queue_pending(struct wl_display *display, + struct wl_event_queue *queue); + +int +wl_display_dispatch_pending(struct wl_display *display); + +int +wl_display_get_error(struct wl_display *display); + +uint32_t +wl_display_get_protocol_error(struct wl_display *display, + const struct wl_interface **interface, + uint32_t *id); + +int +wl_display_flush(struct wl_display *display); + +int +wl_display_roundtrip_queue(struct wl_display *display, + struct wl_event_queue *queue); + +int +wl_display_roundtrip(struct wl_display *display); + +struct wl_event_queue * +wl_display_create_queue(struct wl_display *display); + +int +wl_display_prepare_read_queue(struct wl_display *display, + struct wl_event_queue *queue); + +int +wl_display_prepare_read(struct wl_display *display); + +void +wl_display_cancel_read(struct wl_display *display); + +int +wl_display_read_events(struct wl_display *display); + +void +wl_log_set_handler_client(wl_log_func_t handler); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/linuxbsd_headers/wayland/wayland-client-protocol.h b/thirdparty/linuxbsd_headers/wayland/wayland-client-protocol.h new file mode 100644 index 00000000000..1f3481c7fa8 --- /dev/null +++ b/thirdparty/linuxbsd_headers/wayland/wayland-client-protocol.h @@ -0,0 +1,6106 @@ +/* Generated by wayland-scanner 1.21.0 */ + +#ifndef WAYLAND_CLIENT_PROTOCOL_H +#define WAYLAND_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_wayland The wayland protocol + * @section page_ifaces_wayland Interfaces + * - @subpage page_iface_wl_display - core global object + * - @subpage page_iface_wl_registry - global registry object + * - @subpage page_iface_wl_callback - callback object + * - @subpage page_iface_wl_compositor - the compositor singleton + * - @subpage page_iface_wl_shm_pool - a shared memory pool + * - @subpage page_iface_wl_shm - shared memory support + * - @subpage page_iface_wl_buffer - content for a wl_surface + * - @subpage page_iface_wl_data_offer - offer to transfer data + * - @subpage page_iface_wl_data_source - offer to transfer data + * - @subpage page_iface_wl_data_device - data transfer device + * - @subpage page_iface_wl_data_device_manager - data transfer interface + * - @subpage page_iface_wl_shell - create desktop-style surfaces + * - @subpage page_iface_wl_shell_surface - desktop-style metadata interface + * - @subpage page_iface_wl_surface - an onscreen surface + * - @subpage page_iface_wl_seat - group of input devices + * - @subpage page_iface_wl_pointer - pointer input device + * - @subpage page_iface_wl_keyboard - keyboard input device + * - @subpage page_iface_wl_touch - touchscreen input device + * - @subpage page_iface_wl_output - compositor output region + * - @subpage page_iface_wl_region - region interface + * - @subpage page_iface_wl_subcompositor - sub-surface compositing + * - @subpage page_iface_wl_subsurface - sub-surface interface to a wl_surface + * @section page_copyright_wayland Copyright + *
+ *
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2010-2011 Intel Corporation
+ * Copyright © 2012-2013 Collabora, Ltd.
+ *
+ * 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.
+ * 
+ */ +struct wl_buffer; +struct wl_callback; +struct wl_compositor; +struct wl_data_device; +struct wl_data_device_manager; +struct wl_data_offer; +struct wl_data_source; +struct wl_display; +struct wl_keyboard; +struct wl_output; +struct wl_pointer; +struct wl_region; +struct wl_registry; +struct wl_seat; +struct wl_shell; +struct wl_shell_surface; +struct wl_shm; +struct wl_shm_pool; +struct wl_subcompositor; +struct wl_subsurface; +struct wl_surface; +struct wl_touch; + +#ifndef WL_DISPLAY_INTERFACE +#define WL_DISPLAY_INTERFACE +/** + * @page page_iface_wl_display wl_display + * @section page_iface_wl_display_desc Description + * + * The core global object. This is a special singleton object. It + * is used for internal Wayland protocol features. + * @section page_iface_wl_display_api API + * See @ref iface_wl_display. + */ +/** + * @defgroup iface_wl_display The wl_display interface + * + * The core global object. This is a special singleton object. It + * is used for internal Wayland protocol features. + */ +extern const struct wl_interface wl_display_interface; +#endif +#ifndef WL_REGISTRY_INTERFACE +#define WL_REGISTRY_INTERFACE +/** + * @page page_iface_wl_registry wl_registry + * @section page_iface_wl_registry_desc Description + * + * The singleton global registry object. The server has a number of + * global objects that are available to all clients. These objects + * typically represent an actual object in the server (for example, + * an input device) or they are singleton objects that provide + * extension functionality. + * + * When a client creates a registry object, the registry object + * will emit a global event for each global currently in the + * registry. Globals come and go as a result of device or + * monitor hotplugs, reconfiguration or other events, and the + * registry will send out global and global_remove events to + * keep the client up to date with the changes. To mark the end + * of the initial burst of events, the client can use the + * wl_display.sync request immediately after calling + * wl_display.get_registry. + * + * A client can bind to a global object by using the bind + * request. This creates a client-side handle that lets the object + * emit events to the client and lets the client invoke requests on + * the object. + * @section page_iface_wl_registry_api API + * See @ref iface_wl_registry. + */ +/** + * @defgroup iface_wl_registry The wl_registry interface + * + * The singleton global registry object. The server has a number of + * global objects that are available to all clients. These objects + * typically represent an actual object in the server (for example, + * an input device) or they are singleton objects that provide + * extension functionality. + * + * When a client creates a registry object, the registry object + * will emit a global event for each global currently in the + * registry. Globals come and go as a result of device or + * monitor hotplugs, reconfiguration or other events, and the + * registry will send out global and global_remove events to + * keep the client up to date with the changes. To mark the end + * of the initial burst of events, the client can use the + * wl_display.sync request immediately after calling + * wl_display.get_registry. + * + * A client can bind to a global object by using the bind + * request. This creates a client-side handle that lets the object + * emit events to the client and lets the client invoke requests on + * the object. + */ +extern const struct wl_interface wl_registry_interface; +#endif +#ifndef WL_CALLBACK_INTERFACE +#define WL_CALLBACK_INTERFACE +/** + * @page page_iface_wl_callback wl_callback + * @section page_iface_wl_callback_desc Description + * + * Clients can handle the 'done' event to get notified when + * the related request is done. + * @section page_iface_wl_callback_api API + * See @ref iface_wl_callback. + */ +/** + * @defgroup iface_wl_callback The wl_callback interface + * + * Clients can handle the 'done' event to get notified when + * the related request is done. + */ +extern const struct wl_interface wl_callback_interface; +#endif +#ifndef WL_COMPOSITOR_INTERFACE +#define WL_COMPOSITOR_INTERFACE +/** + * @page page_iface_wl_compositor wl_compositor + * @section page_iface_wl_compositor_desc Description + * + * A compositor. This object is a singleton global. The + * compositor is in charge of combining the contents of multiple + * surfaces into one displayable output. + * @section page_iface_wl_compositor_api API + * See @ref iface_wl_compositor. + */ +/** + * @defgroup iface_wl_compositor The wl_compositor interface + * + * A compositor. This object is a singleton global. The + * compositor is in charge of combining the contents of multiple + * surfaces into one displayable output. + */ +extern const struct wl_interface wl_compositor_interface; +#endif +#ifndef WL_SHM_POOL_INTERFACE +#define WL_SHM_POOL_INTERFACE +/** + * @page page_iface_wl_shm_pool wl_shm_pool + * @section page_iface_wl_shm_pool_desc Description + * + * The wl_shm_pool object encapsulates a piece of memory shared + * between the compositor and client. Through the wl_shm_pool + * object, the client can allocate shared memory wl_buffer objects. + * All objects created through the same pool share the same + * underlying mapped memory. Reusing the mapped memory avoids the + * setup/teardown overhead and is useful when interactively resizing + * a surface or for many small buffers. + * @section page_iface_wl_shm_pool_api API + * See @ref iface_wl_shm_pool. + */ +/** + * @defgroup iface_wl_shm_pool The wl_shm_pool interface + * + * The wl_shm_pool object encapsulates a piece of memory shared + * between the compositor and client. Through the wl_shm_pool + * object, the client can allocate shared memory wl_buffer objects. + * All objects created through the same pool share the same + * underlying mapped memory. Reusing the mapped memory avoids the + * setup/teardown overhead and is useful when interactively resizing + * a surface or for many small buffers. + */ +extern const struct wl_interface wl_shm_pool_interface; +#endif +#ifndef WL_SHM_INTERFACE +#define WL_SHM_INTERFACE +/** + * @page page_iface_wl_shm wl_shm + * @section page_iface_wl_shm_desc Description + * + * A singleton global object that provides support for shared + * memory. + * + * Clients can create wl_shm_pool objects using the create_pool + * request. + * + * On binding the wl_shm object one or more format events + * are emitted to inform clients about the valid pixel formats + * that can be used for buffers. + * @section page_iface_wl_shm_api API + * See @ref iface_wl_shm. + */ +/** + * @defgroup iface_wl_shm The wl_shm interface + * + * A singleton global object that provides support for shared + * memory. + * + * Clients can create wl_shm_pool objects using the create_pool + * request. + * + * On binding the wl_shm object one or more format events + * are emitted to inform clients about the valid pixel formats + * that can be used for buffers. + */ +extern const struct wl_interface wl_shm_interface; +#endif +#ifndef WL_BUFFER_INTERFACE +#define WL_BUFFER_INTERFACE +/** + * @page page_iface_wl_buffer wl_buffer + * @section page_iface_wl_buffer_desc Description + * + * A buffer provides the content for a wl_surface. Buffers are + * created through factory interfaces such as wl_shm, wp_linux_buffer_params + * (from the linux-dmabuf protocol extension) or similar. It has a width and + * a height and can be attached to a wl_surface, but the mechanism by which a + * client provides and updates the contents is defined by the buffer factory + * interface. + * + * If the buffer uses a format that has an alpha channel, the alpha channel + * is assumed to be premultiplied in the color channels unless otherwise + * specified. + * @section page_iface_wl_buffer_api API + * See @ref iface_wl_buffer. + */ +/** + * @defgroup iface_wl_buffer The wl_buffer interface + * + * A buffer provides the content for a wl_surface. Buffers are + * created through factory interfaces such as wl_shm, wp_linux_buffer_params + * (from the linux-dmabuf protocol extension) or similar. It has a width and + * a height and can be attached to a wl_surface, but the mechanism by which a + * client provides and updates the contents is defined by the buffer factory + * interface. + * + * If the buffer uses a format that has an alpha channel, the alpha channel + * is assumed to be premultiplied in the color channels unless otherwise + * specified. + */ +extern const struct wl_interface wl_buffer_interface; +#endif +#ifndef WL_DATA_OFFER_INTERFACE +#define WL_DATA_OFFER_INTERFACE +/** + * @page page_iface_wl_data_offer wl_data_offer + * @section page_iface_wl_data_offer_desc Description + * + * A wl_data_offer represents a piece of data offered for transfer + * by another client (the source client). It is used by the + * copy-and-paste and drag-and-drop mechanisms. The offer + * describes the different mime types that the data can be + * converted to and provides the mechanism for transferring the + * data directly from the source client. + * @section page_iface_wl_data_offer_api API + * See @ref iface_wl_data_offer. + */ +/** + * @defgroup iface_wl_data_offer The wl_data_offer interface + * + * A wl_data_offer represents a piece of data offered for transfer + * by another client (the source client). It is used by the + * copy-and-paste and drag-and-drop mechanisms. The offer + * describes the different mime types that the data can be + * converted to and provides the mechanism for transferring the + * data directly from the source client. + */ +extern const struct wl_interface wl_data_offer_interface; +#endif +#ifndef WL_DATA_SOURCE_INTERFACE +#define WL_DATA_SOURCE_INTERFACE +/** + * @page page_iface_wl_data_source wl_data_source + * @section page_iface_wl_data_source_desc Description + * + * The wl_data_source object is the source side of a wl_data_offer. + * It is created by the source client in a data transfer and + * provides a way to describe the offered data and a way to respond + * to requests to transfer the data. + * @section page_iface_wl_data_source_api API + * See @ref iface_wl_data_source. + */ +/** + * @defgroup iface_wl_data_source The wl_data_source interface + * + * The wl_data_source object is the source side of a wl_data_offer. + * It is created by the source client in a data transfer and + * provides a way to describe the offered data and a way to respond + * to requests to transfer the data. + */ +extern const struct wl_interface wl_data_source_interface; +#endif +#ifndef WL_DATA_DEVICE_INTERFACE +#define WL_DATA_DEVICE_INTERFACE +/** + * @page page_iface_wl_data_device wl_data_device + * @section page_iface_wl_data_device_desc Description + * + * There is one wl_data_device per seat which can be obtained + * from the global wl_data_device_manager singleton. + * + * A wl_data_device provides access to inter-client data transfer + * mechanisms such as copy-and-paste and drag-and-drop. + * @section page_iface_wl_data_device_api API + * See @ref iface_wl_data_device. + */ +/** + * @defgroup iface_wl_data_device The wl_data_device interface + * + * There is one wl_data_device per seat which can be obtained + * from the global wl_data_device_manager singleton. + * + * A wl_data_device provides access to inter-client data transfer + * mechanisms such as copy-and-paste and drag-and-drop. + */ +extern const struct wl_interface wl_data_device_interface; +#endif +#ifndef WL_DATA_DEVICE_MANAGER_INTERFACE +#define WL_DATA_DEVICE_MANAGER_INTERFACE +/** + * @page page_iface_wl_data_device_manager wl_data_device_manager + * @section page_iface_wl_data_device_manager_desc Description + * + * The wl_data_device_manager is a singleton global object that + * provides access to inter-client data transfer mechanisms such as + * copy-and-paste and drag-and-drop. These mechanisms are tied to + * a wl_seat and this interface lets a client get a wl_data_device + * corresponding to a wl_seat. + * + * Depending on the version bound, the objects created from the bound + * wl_data_device_manager object will have different requirements for + * functioning properly. See wl_data_source.set_actions, + * wl_data_offer.accept and wl_data_offer.finish for details. + * @section page_iface_wl_data_device_manager_api API + * See @ref iface_wl_data_device_manager. + */ +/** + * @defgroup iface_wl_data_device_manager The wl_data_device_manager interface + * + * The wl_data_device_manager is a singleton global object that + * provides access to inter-client data transfer mechanisms such as + * copy-and-paste and drag-and-drop. These mechanisms are tied to + * a wl_seat and this interface lets a client get a wl_data_device + * corresponding to a wl_seat. + * + * Depending on the version bound, the objects created from the bound + * wl_data_device_manager object will have different requirements for + * functioning properly. See wl_data_source.set_actions, + * wl_data_offer.accept and wl_data_offer.finish for details. + */ +extern const struct wl_interface wl_data_device_manager_interface; +#endif +#ifndef WL_SHELL_INTERFACE +#define WL_SHELL_INTERFACE +/** + * @page page_iface_wl_shell wl_shell + * @section page_iface_wl_shell_desc Description + * + * This interface is implemented by servers that provide + * desktop-style user interfaces. + * + * It allows clients to associate a wl_shell_surface with + * a basic surface. + * + * Note! This protocol is deprecated and not intended for production use. + * For desktop-style user interfaces, use xdg_shell. Compositors and clients + * should not implement this interface. + * @section page_iface_wl_shell_api API + * See @ref iface_wl_shell. + */ +/** + * @defgroup iface_wl_shell The wl_shell interface + * + * This interface is implemented by servers that provide + * desktop-style user interfaces. + * + * It allows clients to associate a wl_shell_surface with + * a basic surface. + * + * Note! This protocol is deprecated and not intended for production use. + * For desktop-style user interfaces, use xdg_shell. Compositors and clients + * should not implement this interface. + */ +extern const struct wl_interface wl_shell_interface; +#endif +#ifndef WL_SHELL_SURFACE_INTERFACE +#define WL_SHELL_SURFACE_INTERFACE +/** + * @page page_iface_wl_shell_surface wl_shell_surface + * @section page_iface_wl_shell_surface_desc Description + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides requests to treat surfaces like toplevel, fullscreen + * or popup windows, move, resize or maximize them, associate + * metadata like title and class, etc. + * + * On the server side the object is automatically destroyed when + * the related wl_surface is destroyed. On the client side, + * wl_shell_surface_destroy() must be called before destroying + * the wl_surface object. + * @section page_iface_wl_shell_surface_api API + * See @ref iface_wl_shell_surface. + */ +/** + * @defgroup iface_wl_shell_surface The wl_shell_surface interface + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides requests to treat surfaces like toplevel, fullscreen + * or popup windows, move, resize or maximize them, associate + * metadata like title and class, etc. + * + * On the server side the object is automatically destroyed when + * the related wl_surface is destroyed. On the client side, + * wl_shell_surface_destroy() must be called before destroying + * the wl_surface object. + */ +extern const struct wl_interface wl_shell_surface_interface; +#endif +#ifndef WL_SURFACE_INTERFACE +#define WL_SURFACE_INTERFACE +/** + * @page page_iface_wl_surface wl_surface + * @section page_iface_wl_surface_desc Description + * + * A surface is a rectangular area that may be displayed on zero + * or more outputs, and shown any number of times at the compositor's + * discretion. They can present wl_buffers, receive user input, and + * define a local coordinate system. + * + * The size of a surface (and relative positions on it) is described + * in surface-local coordinates, which may differ from the buffer + * coordinates of the pixel content, in case a buffer_transform + * or a buffer_scale is used. + * + * A surface without a "role" is fairly useless: a compositor does + * not know where, when or how to present it. The role is the + * purpose of a wl_surface. Examples of roles are a cursor for a + * pointer (as set by wl_pointer.set_cursor), a drag icon + * (wl_data_device.start_drag), a sub-surface + * (wl_subcompositor.get_subsurface), and a window as defined by a + * shell protocol (e.g. wl_shell.get_shell_surface). + * + * A surface can have only one role at a time. Initially a + * wl_surface does not have a role. Once a wl_surface is given a + * role, it is set permanently for the whole lifetime of the + * wl_surface object. Giving the current role again is allowed, + * unless explicitly forbidden by the relevant interface + * specification. + * + * Surface roles are given by requests in other interfaces such as + * wl_pointer.set_cursor. The request should explicitly mention + * that this request gives a role to a wl_surface. Often, this + * request also creates a new protocol object that represents the + * role and adds additional functionality to wl_surface. When a + * client wants to destroy a wl_surface, they must destroy this 'role + * object' before the wl_surface. + * + * Destroying the role object does not remove the role from the + * wl_surface, but it may stop the wl_surface from "playing the role". + * For instance, if a wl_subsurface object is destroyed, the wl_surface + * it was created for will be unmapped and forget its position and + * z-order. It is allowed to create a wl_subsurface for the same + * wl_surface again, but it is not allowed to use the wl_surface as + * a cursor (cursor is a different role than sub-surface, and role + * switching is not allowed). + * @section page_iface_wl_surface_api API + * See @ref iface_wl_surface. + */ +/** + * @defgroup iface_wl_surface The wl_surface interface + * + * A surface is a rectangular area that may be displayed on zero + * or more outputs, and shown any number of times at the compositor's + * discretion. They can present wl_buffers, receive user input, and + * define a local coordinate system. + * + * The size of a surface (and relative positions on it) is described + * in surface-local coordinates, which may differ from the buffer + * coordinates of the pixel content, in case a buffer_transform + * or a buffer_scale is used. + * + * A surface without a "role" is fairly useless: a compositor does + * not know where, when or how to present it. The role is the + * purpose of a wl_surface. Examples of roles are a cursor for a + * pointer (as set by wl_pointer.set_cursor), a drag icon + * (wl_data_device.start_drag), a sub-surface + * (wl_subcompositor.get_subsurface), and a window as defined by a + * shell protocol (e.g. wl_shell.get_shell_surface). + * + * A surface can have only one role at a time. Initially a + * wl_surface does not have a role. Once a wl_surface is given a + * role, it is set permanently for the whole lifetime of the + * wl_surface object. Giving the current role again is allowed, + * unless explicitly forbidden by the relevant interface + * specification. + * + * Surface roles are given by requests in other interfaces such as + * wl_pointer.set_cursor. The request should explicitly mention + * that this request gives a role to a wl_surface. Often, this + * request also creates a new protocol object that represents the + * role and adds additional functionality to wl_surface. When a + * client wants to destroy a wl_surface, they must destroy this 'role + * object' before the wl_surface. + * + * Destroying the role object does not remove the role from the + * wl_surface, but it may stop the wl_surface from "playing the role". + * For instance, if a wl_subsurface object is destroyed, the wl_surface + * it was created for will be unmapped and forget its position and + * z-order. It is allowed to create a wl_subsurface for the same + * wl_surface again, but it is not allowed to use the wl_surface as + * a cursor (cursor is a different role than sub-surface, and role + * switching is not allowed). + */ +extern const struct wl_interface wl_surface_interface; +#endif +#ifndef WL_SEAT_INTERFACE +#define WL_SEAT_INTERFACE +/** + * @page page_iface_wl_seat wl_seat + * @section page_iface_wl_seat_desc Description + * + * A seat is a group of keyboards, pointer and touch devices. This + * object is published as a global during start up, or when such a + * device is hot plugged. A seat typically has a pointer and + * maintains a keyboard focus and a pointer focus. + * @section page_iface_wl_seat_api API + * See @ref iface_wl_seat. + */ +/** + * @defgroup iface_wl_seat The wl_seat interface + * + * A seat is a group of keyboards, pointer and touch devices. This + * object is published as a global during start up, or when such a + * device is hot plugged. A seat typically has a pointer and + * maintains a keyboard focus and a pointer focus. + */ +extern const struct wl_interface wl_seat_interface; +#endif +#ifndef WL_POINTER_INTERFACE +#define WL_POINTER_INTERFACE +/** + * @page page_iface_wl_pointer wl_pointer + * @section page_iface_wl_pointer_desc Description + * + * The wl_pointer interface represents one or more input devices, + * such as mice, which control the pointer location and pointer_focus + * of a seat. + * + * The wl_pointer interface generates motion, enter and leave + * events for the surfaces that the pointer is located over, + * and button and axis events for button presses, button releases + * and scrolling. + * @section page_iface_wl_pointer_api API + * See @ref iface_wl_pointer. + */ +/** + * @defgroup iface_wl_pointer The wl_pointer interface + * + * The wl_pointer interface represents one or more input devices, + * such as mice, which control the pointer location and pointer_focus + * of a seat. + * + * The wl_pointer interface generates motion, enter and leave + * events for the surfaces that the pointer is located over, + * and button and axis events for button presses, button releases + * and scrolling. + */ +extern const struct wl_interface wl_pointer_interface; +#endif +#ifndef WL_KEYBOARD_INTERFACE +#define WL_KEYBOARD_INTERFACE +/** + * @page page_iface_wl_keyboard wl_keyboard + * @section page_iface_wl_keyboard_desc Description + * + * The wl_keyboard interface represents one or more keyboards + * associated with a seat. + * @section page_iface_wl_keyboard_api API + * See @ref iface_wl_keyboard. + */ +/** + * @defgroup iface_wl_keyboard The wl_keyboard interface + * + * The wl_keyboard interface represents one or more keyboards + * associated with a seat. + */ +extern const struct wl_interface wl_keyboard_interface; +#endif +#ifndef WL_TOUCH_INTERFACE +#define WL_TOUCH_INTERFACE +/** + * @page page_iface_wl_touch wl_touch + * @section page_iface_wl_touch_desc Description + * + * The wl_touch interface represents a touchscreen + * associated with a seat. + * + * Touch interactions can consist of one or more contacts. + * For each contact, a series of events is generated, starting + * with a down event, followed by zero or more motion events, + * and ending with an up event. Events relating to the same + * contact point can be identified by the ID of the sequence. + * @section page_iface_wl_touch_api API + * See @ref iface_wl_touch. + */ +/** + * @defgroup iface_wl_touch The wl_touch interface + * + * The wl_touch interface represents a touchscreen + * associated with a seat. + * + * Touch interactions can consist of one or more contacts. + * For each contact, a series of events is generated, starting + * with a down event, followed by zero or more motion events, + * and ending with an up event. Events relating to the same + * contact point can be identified by the ID of the sequence. + */ +extern const struct wl_interface wl_touch_interface; +#endif +#ifndef WL_OUTPUT_INTERFACE +#define WL_OUTPUT_INTERFACE +/** + * @page page_iface_wl_output wl_output + * @section page_iface_wl_output_desc Description + * + * An output describes part of the compositor geometry. The + * compositor works in the 'compositor coordinate system' and an + * output corresponds to a rectangular area in that space that is + * actually visible. This typically corresponds to a monitor that + * displays part of the compositor space. This object is published + * as global during start up, or when a monitor is hotplugged. + * @section page_iface_wl_output_api API + * See @ref iface_wl_output. + */ +/** + * @defgroup iface_wl_output The wl_output interface + * + * An output describes part of the compositor geometry. The + * compositor works in the 'compositor coordinate system' and an + * output corresponds to a rectangular area in that space that is + * actually visible. This typically corresponds to a monitor that + * displays part of the compositor space. This object is published + * as global during start up, or when a monitor is hotplugged. + */ +extern const struct wl_interface wl_output_interface; +#endif +#ifndef WL_REGION_INTERFACE +#define WL_REGION_INTERFACE +/** + * @page page_iface_wl_region wl_region + * @section page_iface_wl_region_desc Description + * + * A region object describes an area. + * + * Region objects are used to describe the opaque and input + * regions of a surface. + * @section page_iface_wl_region_api API + * See @ref iface_wl_region. + */ +/** + * @defgroup iface_wl_region The wl_region interface + * + * A region object describes an area. + * + * Region objects are used to describe the opaque and input + * regions of a surface. + */ +extern const struct wl_interface wl_region_interface; +#endif +#ifndef WL_SUBCOMPOSITOR_INTERFACE +#define WL_SUBCOMPOSITOR_INTERFACE +/** + * @page page_iface_wl_subcompositor wl_subcompositor + * @section page_iface_wl_subcompositor_desc Description + * + * The global interface exposing sub-surface compositing capabilities. + * A wl_surface, that has sub-surfaces associated, is called the + * parent surface. Sub-surfaces can be arbitrarily nested and create + * a tree of sub-surfaces. + * + * The root surface in a tree of sub-surfaces is the main + * surface. The main surface cannot be a sub-surface, because + * sub-surfaces must always have a parent. + * + * A main surface with its sub-surfaces forms a (compound) window. + * For window management purposes, this set of wl_surface objects is + * to be considered as a single window, and it should also behave as + * such. + * + * The aim of sub-surfaces is to offload some of the compositing work + * within a window from clients to the compositor. A prime example is + * a video player with decorations and video in separate wl_surface + * objects. This should allow the compositor to pass YUV video buffer + * processing to dedicated overlay hardware when possible. + * @section page_iface_wl_subcompositor_api API + * See @ref iface_wl_subcompositor. + */ +/** + * @defgroup iface_wl_subcompositor The wl_subcompositor interface + * + * The global interface exposing sub-surface compositing capabilities. + * A wl_surface, that has sub-surfaces associated, is called the + * parent surface. Sub-surfaces can be arbitrarily nested and create + * a tree of sub-surfaces. + * + * The root surface in a tree of sub-surfaces is the main + * surface. The main surface cannot be a sub-surface, because + * sub-surfaces must always have a parent. + * + * A main surface with its sub-surfaces forms a (compound) window. + * For window management purposes, this set of wl_surface objects is + * to be considered as a single window, and it should also behave as + * such. + * + * The aim of sub-surfaces is to offload some of the compositing work + * within a window from clients to the compositor. A prime example is + * a video player with decorations and video in separate wl_surface + * objects. This should allow the compositor to pass YUV video buffer + * processing to dedicated overlay hardware when possible. + */ +extern const struct wl_interface wl_subcompositor_interface; +#endif +#ifndef WL_SUBSURFACE_INTERFACE +#define WL_SUBSURFACE_INTERFACE +/** + * @page page_iface_wl_subsurface wl_subsurface + * @section page_iface_wl_subsurface_desc Description + * + * An additional interface to a wl_surface object, which has been + * made a sub-surface. A sub-surface has one parent surface. A + * sub-surface's size and position are not limited to that of the parent. + * Particularly, a sub-surface is not automatically clipped to its + * parent's area. + * + * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied + * and the parent surface is mapped. The order of which one happens + * first is irrelevant. A sub-surface is hidden if the parent becomes + * hidden, or if a NULL wl_buffer is applied. These rules apply + * recursively through the tree of surfaces. + * + * The behaviour of a wl_surface.commit request on a sub-surface + * depends on the sub-surface's mode. The possible modes are + * synchronized and desynchronized, see methods + * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized + * mode caches the wl_surface state to be applied when the parent's + * state gets applied, and desynchronized mode applies the pending + * wl_surface state directly. A sub-surface is initially in the + * synchronized mode. + * + * Sub-surfaces also have another kind of state, which is managed by + * wl_subsurface requests, as opposed to wl_surface requests. This + * state includes the sub-surface position relative to the parent + * surface (wl_subsurface.set_position), and the stacking order of + * the parent and its sub-surfaces (wl_subsurface.place_above and + * .place_below). This state is applied when the parent surface's + * wl_surface state is applied, regardless of the sub-surface's mode. + * As the exception, set_sync and set_desync are effective immediately. + * + * The main surface can be thought to be always in desynchronized mode, + * since it does not have a parent in the sub-surfaces sense. + * + * Even if a sub-surface is in desynchronized mode, it will behave as + * in synchronized mode, if its parent surface behaves as in + * synchronized mode. This rule is applied recursively throughout the + * tree of surfaces. This means, that one can set a sub-surface into + * synchronized mode, and then assume that all its child and grand-child + * sub-surfaces are synchronized, too, without explicitly setting them. + * + * If the wl_surface associated with the wl_subsurface is destroyed, the + * wl_subsurface object becomes inert. Note, that destroying either object + * takes effect immediately. If you need to synchronize the removal + * of a sub-surface to the parent surface update, unmap the sub-surface + * first by attaching a NULL wl_buffer, update parent, and then destroy + * the sub-surface. + * + * If the parent wl_surface object is destroyed, the sub-surface is + * unmapped. + * @section page_iface_wl_subsurface_api API + * See @ref iface_wl_subsurface. + */ +/** + * @defgroup iface_wl_subsurface The wl_subsurface interface + * + * An additional interface to a wl_surface object, which has been + * made a sub-surface. A sub-surface has one parent surface. A + * sub-surface's size and position are not limited to that of the parent. + * Particularly, a sub-surface is not automatically clipped to its + * parent's area. + * + * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied + * and the parent surface is mapped. The order of which one happens + * first is irrelevant. A sub-surface is hidden if the parent becomes + * hidden, or if a NULL wl_buffer is applied. These rules apply + * recursively through the tree of surfaces. + * + * The behaviour of a wl_surface.commit request on a sub-surface + * depends on the sub-surface's mode. The possible modes are + * synchronized and desynchronized, see methods + * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized + * mode caches the wl_surface state to be applied when the parent's + * state gets applied, and desynchronized mode applies the pending + * wl_surface state directly. A sub-surface is initially in the + * synchronized mode. + * + * Sub-surfaces also have another kind of state, which is managed by + * wl_subsurface requests, as opposed to wl_surface requests. This + * state includes the sub-surface position relative to the parent + * surface (wl_subsurface.set_position), and the stacking order of + * the parent and its sub-surfaces (wl_subsurface.place_above and + * .place_below). This state is applied when the parent surface's + * wl_surface state is applied, regardless of the sub-surface's mode. + * As the exception, set_sync and set_desync are effective immediately. + * + * The main surface can be thought to be always in desynchronized mode, + * since it does not have a parent in the sub-surfaces sense. + * + * Even if a sub-surface is in desynchronized mode, it will behave as + * in synchronized mode, if its parent surface behaves as in + * synchronized mode. This rule is applied recursively throughout the + * tree of surfaces. This means, that one can set a sub-surface into + * synchronized mode, and then assume that all its child and grand-child + * sub-surfaces are synchronized, too, without explicitly setting them. + * + * If the wl_surface associated with the wl_subsurface is destroyed, the + * wl_subsurface object becomes inert. Note, that destroying either object + * takes effect immediately. If you need to synchronize the removal + * of a sub-surface to the parent surface update, unmap the sub-surface + * first by attaching a NULL wl_buffer, update parent, and then destroy + * the sub-surface. + * + * If the parent wl_surface object is destroyed, the sub-surface is + * unmapped. + */ +extern const struct wl_interface wl_subsurface_interface; +#endif + +#ifndef WL_DISPLAY_ERROR_ENUM +#define WL_DISPLAY_ERROR_ENUM +/** + * @ingroup iface_wl_display + * global error values + * + * These errors are global and can be emitted in response to any + * server request. + */ +enum wl_display_error { + /** + * server couldn't find object + */ + WL_DISPLAY_ERROR_INVALID_OBJECT = 0, + /** + * method doesn't exist on the specified interface or malformed request + */ + WL_DISPLAY_ERROR_INVALID_METHOD = 1, + /** + * server is out of memory + */ + WL_DISPLAY_ERROR_NO_MEMORY = 2, + /** + * implementation error in compositor + */ + WL_DISPLAY_ERROR_IMPLEMENTATION = 3, +}; +#endif /* WL_DISPLAY_ERROR_ENUM */ + +/** + * @ingroup iface_wl_display + * @struct wl_display_listener + */ +struct wl_display_listener { + /** + * fatal error event + * + * The error event is sent out when a fatal (non-recoverable) + * error has occurred. The object_id argument is the object where + * the error occurred, most often in response to a request to that + * object. The code identifies the error and is defined by the + * object interface. As such, each interface defines its own set of + * error codes. The message is a brief description of the error, + * for (debugging) convenience. + * @param object_id object where the error occurred + * @param code error code + * @param message error description + */ + void (*error)(void *data, + struct wl_display *wl_display, + void *object_id, + uint32_t code, + const char *message); + /** + * acknowledge object ID deletion + * + * This event is used internally by the object ID management + * logic. When a client deletes an object that it had created, the + * server will send this event to acknowledge that it has seen the + * delete request. When the client receives this event, it will + * know that it can safely reuse the object ID. + * @param id deleted object ID + */ + void (*delete_id)(void *data, + struct wl_display *wl_display, + uint32_t id); +}; + +/** + * @ingroup iface_wl_display + */ +static inline int +wl_display_add_listener(struct wl_display *wl_display, + const struct wl_display_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_display, + (void (**)(void)) listener, data); +} + +#define WL_DISPLAY_SYNC 0 +#define WL_DISPLAY_GET_REGISTRY 1 + +/** + * @ingroup iface_wl_display + */ +#define WL_DISPLAY_ERROR_SINCE_VERSION 1 +/** + * @ingroup iface_wl_display + */ +#define WL_DISPLAY_DELETE_ID_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_display + */ +#define WL_DISPLAY_SYNC_SINCE_VERSION 1 +/** + * @ingroup iface_wl_display + */ +#define WL_DISPLAY_GET_REGISTRY_SINCE_VERSION 1 + +/** @ingroup iface_wl_display */ +static inline void +wl_display_set_user_data(struct wl_display *wl_display, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_display, user_data); +} + +/** @ingroup iface_wl_display */ +static inline void * +wl_display_get_user_data(struct wl_display *wl_display) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_display); +} + +static inline uint32_t +wl_display_get_version(struct wl_display *wl_display) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_display); +} + +/** + * @ingroup iface_wl_display + * + * The sync request asks the server to emit the 'done' event + * on the returned wl_callback object. Since requests are + * handled in-order and events are delivered in-order, this can + * be used as a barrier to ensure all previous requests and the + * resulting events have been handled. + * + * The object returned by this request will be destroyed by the + * compositor after the callback is fired and as such the client must not + * attempt to use it after that point. + * + * The callback_data passed in the callback is the event serial. + */ +static inline struct wl_callback * +wl_display_sync(struct wl_display *wl_display) +{ + struct wl_proxy *callback; + + callback = wl_proxy_marshal_flags((struct wl_proxy *) wl_display, + WL_DISPLAY_SYNC, &wl_callback_interface, wl_proxy_get_version((struct wl_proxy *) wl_display), 0, NULL); + + return (struct wl_callback *) callback; +} + +/** + * @ingroup iface_wl_display + * + * This request creates a registry object that allows the client + * to list and bind the global objects available from the + * compositor. + * + * It should be noted that the server side resources consumed in + * response to a get_registry request can only be released when the + * client disconnects, not when the client side proxy is destroyed. + * Therefore, clients should invoke get_registry as infrequently as + * possible to avoid wasting memory. + */ +static inline struct wl_registry * +wl_display_get_registry(struct wl_display *wl_display) +{ + struct wl_proxy *registry; + + registry = wl_proxy_marshal_flags((struct wl_proxy *) wl_display, + WL_DISPLAY_GET_REGISTRY, &wl_registry_interface, wl_proxy_get_version((struct wl_proxy *) wl_display), 0, NULL); + + return (struct wl_registry *) registry; +} + +/** + * @ingroup iface_wl_registry + * @struct wl_registry_listener + */ +struct wl_registry_listener { + /** + * announce global object + * + * Notify the client of global objects. + * + * The event notifies the client that a global object with the + * given name is now available, and it implements the given version + * of the given interface. + * @param name numeric name of the global object + * @param interface interface implemented by the object + * @param version interface version + */ + void (*global)(void *data, + struct wl_registry *wl_registry, + uint32_t name, + const char *interface, + uint32_t version); + /** + * announce removal of global object + * + * Notify the client of removed global objects. + * + * This event notifies the client that the global identified by + * name is no longer available. If the client bound to the global + * using the bind request, the client should now destroy that + * object. + * + * The object remains valid and requests to the object will be + * ignored until the client destroys it, to avoid races between the + * global going away and a client sending a request to it. + * @param name numeric name of the global object + */ + void (*global_remove)(void *data, + struct wl_registry *wl_registry, + uint32_t name); +}; + +/** + * @ingroup iface_wl_registry + */ +static inline int +wl_registry_add_listener(struct wl_registry *wl_registry, + const struct wl_registry_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_registry, + (void (**)(void)) listener, data); +} + +#define WL_REGISTRY_BIND 0 + +/** + * @ingroup iface_wl_registry + */ +#define WL_REGISTRY_GLOBAL_SINCE_VERSION 1 +/** + * @ingroup iface_wl_registry + */ +#define WL_REGISTRY_GLOBAL_REMOVE_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_registry + */ +#define WL_REGISTRY_BIND_SINCE_VERSION 1 + +/** @ingroup iface_wl_registry */ +static inline void +wl_registry_set_user_data(struct wl_registry *wl_registry, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_registry, user_data); +} + +/** @ingroup iface_wl_registry */ +static inline void * +wl_registry_get_user_data(struct wl_registry *wl_registry) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_registry); +} + +static inline uint32_t +wl_registry_get_version(struct wl_registry *wl_registry) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_registry); +} + +/** @ingroup iface_wl_registry */ +static inline void +wl_registry_destroy(struct wl_registry *wl_registry) +{ + wl_proxy_destroy((struct wl_proxy *) wl_registry); +} + +/** + * @ingroup iface_wl_registry + * + * Binds a new, client-created object to the server using the + * specified name as the identifier. + */ +static inline void * +wl_registry_bind(struct wl_registry *wl_registry, uint32_t name, const struct wl_interface *interface, uint32_t version) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_registry, + WL_REGISTRY_BIND, interface, version, 0, name, interface->name, version, NULL); + + return (void *) id; +} + +/** + * @ingroup iface_wl_callback + * @struct wl_callback_listener + */ +struct wl_callback_listener { + /** + * done event + * + * Notify the client when the related request is done. + * @param callback_data request-specific data for the callback + */ + void (*done)(void *data, + struct wl_callback *wl_callback, + uint32_t callback_data); +}; + +/** + * @ingroup iface_wl_callback + */ +static inline int +wl_callback_add_listener(struct wl_callback *wl_callback, + const struct wl_callback_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_callback, + (void (**)(void)) listener, data); +} + +/** + * @ingroup iface_wl_callback + */ +#define WL_CALLBACK_DONE_SINCE_VERSION 1 + + +/** @ingroup iface_wl_callback */ +static inline void +wl_callback_set_user_data(struct wl_callback *wl_callback, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_callback, user_data); +} + +/** @ingroup iface_wl_callback */ +static inline void * +wl_callback_get_user_data(struct wl_callback *wl_callback) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_callback); +} + +static inline uint32_t +wl_callback_get_version(struct wl_callback *wl_callback) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_callback); +} + +/** @ingroup iface_wl_callback */ +static inline void +wl_callback_destroy(struct wl_callback *wl_callback) +{ + wl_proxy_destroy((struct wl_proxy *) wl_callback); +} + +#define WL_COMPOSITOR_CREATE_SURFACE 0 +#define WL_COMPOSITOR_CREATE_REGION 1 + + +/** + * @ingroup iface_wl_compositor + */ +#define WL_COMPOSITOR_CREATE_SURFACE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_compositor + */ +#define WL_COMPOSITOR_CREATE_REGION_SINCE_VERSION 1 + +/** @ingroup iface_wl_compositor */ +static inline void +wl_compositor_set_user_data(struct wl_compositor *wl_compositor, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_compositor, user_data); +} + +/** @ingroup iface_wl_compositor */ +static inline void * +wl_compositor_get_user_data(struct wl_compositor *wl_compositor) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_compositor); +} + +static inline uint32_t +wl_compositor_get_version(struct wl_compositor *wl_compositor) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_compositor); +} + +/** @ingroup iface_wl_compositor */ +static inline void +wl_compositor_destroy(struct wl_compositor *wl_compositor) +{ + wl_proxy_destroy((struct wl_proxy *) wl_compositor); +} + +/** + * @ingroup iface_wl_compositor + * + * Ask the compositor to create a new surface. + */ +static inline struct wl_surface * +wl_compositor_create_surface(struct wl_compositor *wl_compositor) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_compositor, + WL_COMPOSITOR_CREATE_SURFACE, &wl_surface_interface, wl_proxy_get_version((struct wl_proxy *) wl_compositor), 0, NULL); + + return (struct wl_surface *) id; +} + +/** + * @ingroup iface_wl_compositor + * + * Ask the compositor to create a new region. + */ +static inline struct wl_region * +wl_compositor_create_region(struct wl_compositor *wl_compositor) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_compositor, + WL_COMPOSITOR_CREATE_REGION, &wl_region_interface, wl_proxy_get_version((struct wl_proxy *) wl_compositor), 0, NULL); + + return (struct wl_region *) id; +} + +#define WL_SHM_POOL_CREATE_BUFFER 0 +#define WL_SHM_POOL_DESTROY 1 +#define WL_SHM_POOL_RESIZE 2 + + +/** + * @ingroup iface_wl_shm_pool + */ +#define WL_SHM_POOL_CREATE_BUFFER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shm_pool + */ +#define WL_SHM_POOL_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shm_pool + */ +#define WL_SHM_POOL_RESIZE_SINCE_VERSION 1 + +/** @ingroup iface_wl_shm_pool */ +static inline void +wl_shm_pool_set_user_data(struct wl_shm_pool *wl_shm_pool, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_shm_pool, user_data); +} + +/** @ingroup iface_wl_shm_pool */ +static inline void * +wl_shm_pool_get_user_data(struct wl_shm_pool *wl_shm_pool) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_shm_pool); +} + +static inline uint32_t +wl_shm_pool_get_version(struct wl_shm_pool *wl_shm_pool) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_shm_pool); +} + +/** + * @ingroup iface_wl_shm_pool + * + * Create a wl_buffer object from the pool. + * + * The buffer is created offset bytes into the pool and has + * width and height as specified. The stride argument specifies + * the number of bytes from the beginning of one row to the beginning + * of the next. The format is the pixel format of the buffer and + * must be one of those advertised through the wl_shm.format event. + * + * A buffer will keep a reference to the pool it was created from + * so it is valid to destroy the pool immediately after creating + * a buffer from it. + */ +static inline struct wl_buffer * +wl_shm_pool_create_buffer(struct wl_shm_pool *wl_shm_pool, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool, + WL_SHM_POOL_CREATE_BUFFER, &wl_buffer_interface, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), 0, NULL, offset, width, height, stride, format); + + return (struct wl_buffer *) id; +} + +/** + * @ingroup iface_wl_shm_pool + * + * Destroy the shared memory pool. + * + * The mmapped memory will be released when all + * buffers that have been created from this pool + * are gone. + */ +static inline void +wl_shm_pool_destroy(struct wl_shm_pool *wl_shm_pool) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool, + WL_SHM_POOL_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wl_shm_pool + * + * This request will cause the server to remap the backing memory + * for the pool from the file descriptor passed when the pool was + * created, but using the new size. This request can only be + * used to make the pool bigger. + * + * This request only changes the amount of bytes that are mmapped + * by the server and does not touch the file corresponding to the + * file descriptor passed at creation time. It is the client's + * responsibility to ensure that the file is at least as big as + * the new pool size. + */ +static inline void +wl_shm_pool_resize(struct wl_shm_pool *wl_shm_pool, int32_t size) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool, + WL_SHM_POOL_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), 0, size); +} + +#ifndef WL_SHM_ERROR_ENUM +#define WL_SHM_ERROR_ENUM +/** + * @ingroup iface_wl_shm + * wl_shm error values + * + * These errors can be emitted in response to wl_shm requests. + */ +enum wl_shm_error { + /** + * buffer format is not known + */ + WL_SHM_ERROR_INVALID_FORMAT = 0, + /** + * invalid size or stride during pool or buffer creation + */ + WL_SHM_ERROR_INVALID_STRIDE = 1, + /** + * mmapping the file descriptor failed + */ + WL_SHM_ERROR_INVALID_FD = 2, +}; +#endif /* WL_SHM_ERROR_ENUM */ + +#ifndef WL_SHM_FORMAT_ENUM +#define WL_SHM_FORMAT_ENUM +/** + * @ingroup iface_wl_shm + * pixel formats + * + * This describes the memory layout of an individual pixel. + * + * All renderers should support argb8888 and xrgb8888 but any other + * formats are optional and may not be supported by the particular + * renderer in use. + * + * The drm format codes match the macros defined in drm_fourcc.h, except + * argb8888 and xrgb8888. The formats actually supported by the compositor + * will be reported by the format event. + * + * For all wl_shm formats and unless specified in another protocol + * extension, pre-multiplied alpha is used for pixel values. + */ +enum wl_shm_format { + /** + * 32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian + */ + WL_SHM_FORMAT_ARGB8888 = 0, + /** + * 32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian + */ + WL_SHM_FORMAT_XRGB8888 = 1, + /** + * 8-bit color index format, [7:0] C + */ + WL_SHM_FORMAT_C8 = 0x20203843, + /** + * 8-bit RGB format, [7:0] R:G:B 3:3:2 + */ + WL_SHM_FORMAT_RGB332 = 0x38424752, + /** + * 8-bit BGR format, [7:0] B:G:R 2:3:3 + */ + WL_SHM_FORMAT_BGR233 = 0x38524742, + /** + * 16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian + */ + WL_SHM_FORMAT_XRGB4444 = 0x32315258, + /** + * 16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian + */ + WL_SHM_FORMAT_XBGR4444 = 0x32314258, + /** + * 16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian + */ + WL_SHM_FORMAT_RGBX4444 = 0x32315852, + /** + * 16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian + */ + WL_SHM_FORMAT_BGRX4444 = 0x32315842, + /** + * 16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian + */ + WL_SHM_FORMAT_ARGB4444 = 0x32315241, + /** + * 16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian + */ + WL_SHM_FORMAT_ABGR4444 = 0x32314241, + /** + * 16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian + */ + WL_SHM_FORMAT_RGBA4444 = 0x32314152, + /** + * 16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian + */ + WL_SHM_FORMAT_BGRA4444 = 0x32314142, + /** + * 16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian + */ + WL_SHM_FORMAT_XRGB1555 = 0x35315258, + /** + * 16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian + */ + WL_SHM_FORMAT_XBGR1555 = 0x35314258, + /** + * 16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian + */ + WL_SHM_FORMAT_RGBX5551 = 0x35315852, + /** + * 16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian + */ + WL_SHM_FORMAT_BGRX5551 = 0x35315842, + /** + * 16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian + */ + WL_SHM_FORMAT_ARGB1555 = 0x35315241, + /** + * 16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian + */ + WL_SHM_FORMAT_ABGR1555 = 0x35314241, + /** + * 16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian + */ + WL_SHM_FORMAT_RGBA5551 = 0x35314152, + /** + * 16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian + */ + WL_SHM_FORMAT_BGRA5551 = 0x35314142, + /** + * 16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian + */ + WL_SHM_FORMAT_RGB565 = 0x36314752, + /** + * 16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian + */ + WL_SHM_FORMAT_BGR565 = 0x36314742, + /** + * 24-bit RGB format, [23:0] R:G:B little endian + */ + WL_SHM_FORMAT_RGB888 = 0x34324752, + /** + * 24-bit BGR format, [23:0] B:G:R little endian + */ + WL_SHM_FORMAT_BGR888 = 0x34324742, + /** + * 32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian + */ + WL_SHM_FORMAT_XBGR8888 = 0x34324258, + /** + * 32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian + */ + WL_SHM_FORMAT_RGBX8888 = 0x34325852, + /** + * 32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian + */ + WL_SHM_FORMAT_BGRX8888 = 0x34325842, + /** + * 32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian + */ + WL_SHM_FORMAT_ABGR8888 = 0x34324241, + /** + * 32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian + */ + WL_SHM_FORMAT_RGBA8888 = 0x34324152, + /** + * 32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian + */ + WL_SHM_FORMAT_BGRA8888 = 0x34324142, + /** + * 32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian + */ + WL_SHM_FORMAT_XRGB2101010 = 0x30335258, + /** + * 32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian + */ + WL_SHM_FORMAT_XBGR2101010 = 0x30334258, + /** + * 32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian + */ + WL_SHM_FORMAT_RGBX1010102 = 0x30335852, + /** + * 32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian + */ + WL_SHM_FORMAT_BGRX1010102 = 0x30335842, + /** + * 32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian + */ + WL_SHM_FORMAT_ARGB2101010 = 0x30335241, + /** + * 32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian + */ + WL_SHM_FORMAT_ABGR2101010 = 0x30334241, + /** + * 32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian + */ + WL_SHM_FORMAT_RGBA1010102 = 0x30334152, + /** + * 32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian + */ + WL_SHM_FORMAT_BGRA1010102 = 0x30334142, + /** + * packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian + */ + WL_SHM_FORMAT_YUYV = 0x56595559, + /** + * packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian + */ + WL_SHM_FORMAT_YVYU = 0x55595659, + /** + * packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian + */ + WL_SHM_FORMAT_UYVY = 0x59565955, + /** + * packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian + */ + WL_SHM_FORMAT_VYUY = 0x59555956, + /** + * packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian + */ + WL_SHM_FORMAT_AYUV = 0x56555941, + /** + * 2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane + */ + WL_SHM_FORMAT_NV12 = 0x3231564e, + /** + * 2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane + */ + WL_SHM_FORMAT_NV21 = 0x3132564e, + /** + * 2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane + */ + WL_SHM_FORMAT_NV16 = 0x3631564e, + /** + * 2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane + */ + WL_SHM_FORMAT_NV61 = 0x3136564e, + /** + * 3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV410 = 0x39565559, + /** + * 3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU410 = 0x39555659, + /** + * 3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV411 = 0x31315559, + /** + * 3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU411 = 0x31315659, + /** + * 3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV420 = 0x32315559, + /** + * 3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU420 = 0x32315659, + /** + * 3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV422 = 0x36315559, + /** + * 3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU422 = 0x36315659, + /** + * 3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes + */ + WL_SHM_FORMAT_YUV444 = 0x34325559, + /** + * 3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes + */ + WL_SHM_FORMAT_YVU444 = 0x34325659, + /** + * [7:0] R + */ + WL_SHM_FORMAT_R8 = 0x20203852, + /** + * [15:0] R little endian + */ + WL_SHM_FORMAT_R16 = 0x20363152, + /** + * [15:0] R:G 8:8 little endian + */ + WL_SHM_FORMAT_RG88 = 0x38384752, + /** + * [15:0] G:R 8:8 little endian + */ + WL_SHM_FORMAT_GR88 = 0x38385247, + /** + * [31:0] R:G 16:16 little endian + */ + WL_SHM_FORMAT_RG1616 = 0x32334752, + /** + * [31:0] G:R 16:16 little endian + */ + WL_SHM_FORMAT_GR1616 = 0x32335247, + /** + * [63:0] x:R:G:B 16:16:16:16 little endian + */ + WL_SHM_FORMAT_XRGB16161616F = 0x48345258, + /** + * [63:0] x:B:G:R 16:16:16:16 little endian + */ + WL_SHM_FORMAT_XBGR16161616F = 0x48344258, + /** + * [63:0] A:R:G:B 16:16:16:16 little endian + */ + WL_SHM_FORMAT_ARGB16161616F = 0x48345241, + /** + * [63:0] A:B:G:R 16:16:16:16 little endian + */ + WL_SHM_FORMAT_ABGR16161616F = 0x48344241, + /** + * [31:0] X:Y:Cb:Cr 8:8:8:8 little endian + */ + WL_SHM_FORMAT_XYUV8888 = 0x56555958, + /** + * [23:0] Cr:Cb:Y 8:8:8 little endian + */ + WL_SHM_FORMAT_VUY888 = 0x34325556, + /** + * Y followed by U then V, 10:10:10. Non-linear modifier only + */ + WL_SHM_FORMAT_VUY101010 = 0x30335556, + /** + * [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 10:6:10:6:10:6:10:6 little endian per 2 Y pixels + */ + WL_SHM_FORMAT_Y210 = 0x30313259, + /** + * [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 12:4:12:4:12:4:12:4 little endian per 2 Y pixels + */ + WL_SHM_FORMAT_Y212 = 0x32313259, + /** + * [63:0] Cr0:Y1:Cb0:Y0 16:16:16:16 little endian per 2 Y pixels + */ + WL_SHM_FORMAT_Y216 = 0x36313259, + /** + * [31:0] A:Cr:Y:Cb 2:10:10:10 little endian + */ + WL_SHM_FORMAT_Y410 = 0x30313459, + /** + * [63:0] A:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian + */ + WL_SHM_FORMAT_Y412 = 0x32313459, + /** + * [63:0] A:Cr:Y:Cb 16:16:16:16 little endian + */ + WL_SHM_FORMAT_Y416 = 0x36313459, + /** + * [31:0] X:Cr:Y:Cb 2:10:10:10 little endian + */ + WL_SHM_FORMAT_XVYU2101010 = 0x30335658, + /** + * [63:0] X:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian + */ + WL_SHM_FORMAT_XVYU12_16161616 = 0x36335658, + /** + * [63:0] X:Cr:Y:Cb 16:16:16:16 little endian + */ + WL_SHM_FORMAT_XVYU16161616 = 0x38345658, + /** + * [63:0] A3:A2:Y3:0:Cr0:0:Y2:0:A1:A0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian + */ + WL_SHM_FORMAT_Y0L0 = 0x304c3059, + /** + * [63:0] X3:X2:Y3:0:Cr0:0:Y2:0:X1:X0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian + */ + WL_SHM_FORMAT_X0L0 = 0x304c3058, + /** + * [63:0] A3:A2:Y3:Cr0:Y2:A1:A0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian + */ + WL_SHM_FORMAT_Y0L2 = 0x324c3059, + /** + * [63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian + */ + WL_SHM_FORMAT_X0L2 = 0x324c3058, + WL_SHM_FORMAT_YUV420_8BIT = 0x38305559, + WL_SHM_FORMAT_YUV420_10BIT = 0x30315559, + WL_SHM_FORMAT_XRGB8888_A8 = 0x38415258, + WL_SHM_FORMAT_XBGR8888_A8 = 0x38414258, + WL_SHM_FORMAT_RGBX8888_A8 = 0x38415852, + WL_SHM_FORMAT_BGRX8888_A8 = 0x38415842, + WL_SHM_FORMAT_RGB888_A8 = 0x38413852, + WL_SHM_FORMAT_BGR888_A8 = 0x38413842, + WL_SHM_FORMAT_RGB565_A8 = 0x38413552, + WL_SHM_FORMAT_BGR565_A8 = 0x38413542, + /** + * non-subsampled Cr:Cb plane + */ + WL_SHM_FORMAT_NV24 = 0x3432564e, + /** + * non-subsampled Cb:Cr plane + */ + WL_SHM_FORMAT_NV42 = 0x3234564e, + /** + * 2x1 subsampled Cr:Cb plane, 10 bit per channel + */ + WL_SHM_FORMAT_P210 = 0x30313250, + /** + * 2x2 subsampled Cr:Cb plane 10 bits per channel + */ + WL_SHM_FORMAT_P010 = 0x30313050, + /** + * 2x2 subsampled Cr:Cb plane 12 bits per channel + */ + WL_SHM_FORMAT_P012 = 0x32313050, + /** + * 2x2 subsampled Cr:Cb plane 16 bits per channel + */ + WL_SHM_FORMAT_P016 = 0x36313050, + /** + * [63:0] A:x:B:x:G:x:R:x 10:6:10:6:10:6:10:6 little endian + */ + WL_SHM_FORMAT_AXBXGXRX106106106106 = 0x30314241, + /** + * 2x2 subsampled Cr:Cb plane + */ + WL_SHM_FORMAT_NV15 = 0x3531564e, + WL_SHM_FORMAT_Q410 = 0x30313451, + WL_SHM_FORMAT_Q401 = 0x31303451, + /** + * [63:0] x:R:G:B 16:16:16:16 little endian + */ + WL_SHM_FORMAT_XRGB16161616 = 0x38345258, + /** + * [63:0] x:B:G:R 16:16:16:16 little endian + */ + WL_SHM_FORMAT_XBGR16161616 = 0x38344258, + /** + * [63:0] A:R:G:B 16:16:16:16 little endian + */ + WL_SHM_FORMAT_ARGB16161616 = 0x38345241, + /** + * [63:0] A:B:G:R 16:16:16:16 little endian + */ + WL_SHM_FORMAT_ABGR16161616 = 0x38344241, +}; +#endif /* WL_SHM_FORMAT_ENUM */ + +/** + * @ingroup iface_wl_shm + * @struct wl_shm_listener + */ +struct wl_shm_listener { + /** + * pixel format description + * + * Informs the client about a valid pixel format that can be used + * for buffers. Known formats include argb8888 and xrgb8888. + * @param format buffer pixel format + */ + void (*format)(void *data, + struct wl_shm *wl_shm, + uint32_t format); +}; + +/** + * @ingroup iface_wl_shm + */ +static inline int +wl_shm_add_listener(struct wl_shm *wl_shm, + const struct wl_shm_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_shm, + (void (**)(void)) listener, data); +} + +#define WL_SHM_CREATE_POOL 0 + +/** + * @ingroup iface_wl_shm + */ +#define WL_SHM_FORMAT_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_shm + */ +#define WL_SHM_CREATE_POOL_SINCE_VERSION 1 + +/** @ingroup iface_wl_shm */ +static inline void +wl_shm_set_user_data(struct wl_shm *wl_shm, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_shm, user_data); +} + +/** @ingroup iface_wl_shm */ +static inline void * +wl_shm_get_user_data(struct wl_shm *wl_shm) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_shm); +} + +static inline uint32_t +wl_shm_get_version(struct wl_shm *wl_shm) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_shm); +} + +/** @ingroup iface_wl_shm */ +static inline void +wl_shm_destroy(struct wl_shm *wl_shm) +{ + wl_proxy_destroy((struct wl_proxy *) wl_shm); +} + +/** + * @ingroup iface_wl_shm + * + * Create a new wl_shm_pool object. + * + * The pool can be used to create shared memory based buffer + * objects. The server will mmap size bytes of the passed file + * descriptor, to use as backing memory for the pool. + */ +static inline struct wl_shm_pool * +wl_shm_create_pool(struct wl_shm *wl_shm, int32_t fd, int32_t size) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shm, + WL_SHM_CREATE_POOL, &wl_shm_pool_interface, wl_proxy_get_version((struct wl_proxy *) wl_shm), 0, NULL, fd, size); + + return (struct wl_shm_pool *) id; +} + +/** + * @ingroup iface_wl_buffer + * @struct wl_buffer_listener + */ +struct wl_buffer_listener { + /** + * compositor releases buffer + * + * Sent when this wl_buffer is no longer used by the compositor. + * The client is now free to reuse or destroy this buffer and its + * backing storage. + * + * If a client receives a release event before the frame callback + * requested in the same wl_surface.commit that attaches this + * wl_buffer to a surface, then the client is immediately free to + * reuse the buffer and its backing storage, and does not need a + * second buffer for the next surface content update. Typically + * this is possible, when the compositor maintains a copy of the + * wl_surface contents, e.g. as a GL texture. This is an important + * optimization for GL(ES) compositors with wl_shm clients. + */ + void (*release)(void *data, + struct wl_buffer *wl_buffer); +}; + +/** + * @ingroup iface_wl_buffer + */ +static inline int +wl_buffer_add_listener(struct wl_buffer *wl_buffer, + const struct wl_buffer_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_buffer, + (void (**)(void)) listener, data); +} + +#define WL_BUFFER_DESTROY 0 + +/** + * @ingroup iface_wl_buffer + */ +#define WL_BUFFER_RELEASE_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_buffer + */ +#define WL_BUFFER_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_wl_buffer */ +static inline void +wl_buffer_set_user_data(struct wl_buffer *wl_buffer, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_buffer, user_data); +} + +/** @ingroup iface_wl_buffer */ +static inline void * +wl_buffer_get_user_data(struct wl_buffer *wl_buffer) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_buffer); +} + +static inline uint32_t +wl_buffer_get_version(struct wl_buffer *wl_buffer) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_buffer); +} + +/** + * @ingroup iface_wl_buffer + * + * Destroy a buffer. If and how you need to release the backing + * storage is defined by the buffer factory interface. + * + * For possible side-effects to a surface, see wl_surface.attach. + */ +static inline void +wl_buffer_destroy(struct wl_buffer *wl_buffer) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_buffer, + WL_BUFFER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_buffer), WL_MARSHAL_FLAG_DESTROY); +} + +#ifndef WL_DATA_OFFER_ERROR_ENUM +#define WL_DATA_OFFER_ERROR_ENUM +enum wl_data_offer_error { + /** + * finish request was called untimely + */ + WL_DATA_OFFER_ERROR_INVALID_FINISH = 0, + /** + * action mask contains invalid values + */ + WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK = 1, + /** + * action argument has an invalid value + */ + WL_DATA_OFFER_ERROR_INVALID_ACTION = 2, + /** + * offer doesn't accept this request + */ + WL_DATA_OFFER_ERROR_INVALID_OFFER = 3, +}; +#endif /* WL_DATA_OFFER_ERROR_ENUM */ + +/** + * @ingroup iface_wl_data_offer + * @struct wl_data_offer_listener + */ +struct wl_data_offer_listener { + /** + * advertise offered mime type + * + * Sent immediately after creating the wl_data_offer object. One + * event per offered mime type. + * @param mime_type offered mime type + */ + void (*offer)(void *data, + struct wl_data_offer *wl_data_offer, + const char *mime_type); + /** + * notify the source-side available actions + * + * This event indicates the actions offered by the data source. + * It will be sent right after wl_data_device.enter, or anytime the + * source side changes its offered actions through + * wl_data_source.set_actions. + * @param source_actions actions offered by the data source + * @since 3 + */ + void (*source_actions)(void *data, + struct wl_data_offer *wl_data_offer, + uint32_t source_actions); + /** + * notify the selected action + * + * This event indicates the action selected by the compositor + * after matching the source/destination side actions. Only one + * action (or none) will be offered here. + * + * This event can be emitted multiple times during the + * drag-and-drop operation in response to destination side action + * changes through wl_data_offer.set_actions. + * + * This event will no longer be emitted after wl_data_device.drop + * happened on the drag-and-drop destination, the client must honor + * the last action received, or the last preferred one set through + * wl_data_offer.set_actions when handling an "ask" action. + * + * Compositors may also change the selected action on the fly, + * mainly in response to keyboard modifier changes during the + * drag-and-drop operation. + * + * The most recent action received is always the valid one. Prior + * to receiving wl_data_device.drop, the chosen action may change + * (e.g. due to keyboard modifiers being pressed). At the time of + * receiving wl_data_device.drop the drag-and-drop destination must + * honor the last action received. + * + * Action changes may still happen after wl_data_device.drop, + * especially on "ask" actions, where the drag-and-drop destination + * may choose another action afterwards. Action changes happening + * at this stage are always the result of inter-client negotiation, + * the compositor shall no longer be able to induce a different + * action. + * + * Upon "ask" actions, it is expected that the drag-and-drop + * destination may potentially choose a different action and/or + * mime type, based on wl_data_offer.source_actions and finally + * chosen by the user (e.g. popping up a menu with the available + * options). The final wl_data_offer.set_actions and + * wl_data_offer.accept requests must happen before the call to + * wl_data_offer.finish. + * @param dnd_action action selected by the compositor + * @since 3 + */ + void (*action)(void *data, + struct wl_data_offer *wl_data_offer, + uint32_t dnd_action); +}; + +/** + * @ingroup iface_wl_data_offer + */ +static inline int +wl_data_offer_add_listener(struct wl_data_offer *wl_data_offer, + const struct wl_data_offer_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_data_offer, + (void (**)(void)) listener, data); +} + +#define WL_DATA_OFFER_ACCEPT 0 +#define WL_DATA_OFFER_RECEIVE 1 +#define WL_DATA_OFFER_DESTROY 2 +#define WL_DATA_OFFER_FINISH 3 +#define WL_DATA_OFFER_SET_ACTIONS 4 + +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_OFFER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION 3 +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_ACTION_SINCE_VERSION 3 + +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_ACCEPT_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_RECEIVE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_FINISH_SINCE_VERSION 3 +/** + * @ingroup iface_wl_data_offer + */ +#define WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION 3 + +/** @ingroup iface_wl_data_offer */ +static inline void +wl_data_offer_set_user_data(struct wl_data_offer *wl_data_offer, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_data_offer, user_data); +} + +/** @ingroup iface_wl_data_offer */ +static inline void * +wl_data_offer_get_user_data(struct wl_data_offer *wl_data_offer) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_data_offer); +} + +static inline uint32_t +wl_data_offer_get_version(struct wl_data_offer *wl_data_offer) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_data_offer); +} + +/** + * @ingroup iface_wl_data_offer + * + * Indicate that the client can accept the given mime type, or + * NULL for not accepted. + * + * For objects of version 2 or older, this request is used by the + * client to give feedback whether the client can receive the given + * mime type, or NULL if none is accepted; the feedback does not + * determine whether the drag-and-drop operation succeeds or not. + * + * For objects of version 3 or newer, this request determines the + * final result of the drag-and-drop operation. If the end result + * is that no mime types were accepted, the drag-and-drop operation + * will be cancelled and the corresponding drag source will receive + * wl_data_source.cancelled. Clients may still use this event in + * conjunction with wl_data_source.action for feedback. + */ +static inline void +wl_data_offer_accept(struct wl_data_offer *wl_data_offer, uint32_t serial, const char *mime_type) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, + WL_DATA_OFFER_ACCEPT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, serial, mime_type); +} + +/** + * @ingroup iface_wl_data_offer + * + * To transfer the offered data, the client issues this request + * and indicates the mime type it wants to receive. The transfer + * happens through the passed file descriptor (typically created + * with the pipe system call). The source client writes the data + * in the mime type representation requested and then closes the + * file descriptor. + * + * The receiving client reads from the read end of the pipe until + * EOF and then closes its end, at which point the transfer is + * complete. + * + * This request may happen multiple times for different mime types, + * both before and after wl_data_device.drop. Drag-and-drop destination + * clients may preemptively fetch data or examine it more closely to + * determine acceptance. + */ +static inline void +wl_data_offer_receive(struct wl_data_offer *wl_data_offer, const char *mime_type, int32_t fd) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, + WL_DATA_OFFER_RECEIVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, mime_type, fd); +} + +/** + * @ingroup iface_wl_data_offer + * + * Destroy the data offer. + */ +static inline void +wl_data_offer_destroy(struct wl_data_offer *wl_data_offer) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, + WL_DATA_OFFER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wl_data_offer + * + * Notifies the compositor that the drag destination successfully + * finished the drag-and-drop operation. + * + * Upon receiving this request, the compositor will emit + * wl_data_source.dnd_finished on the drag source client. + * + * It is a client error to perform other requests than + * wl_data_offer.destroy after this one. It is also an error to perform + * this request after a NULL mime type has been set in + * wl_data_offer.accept or no action was received through + * wl_data_offer.action. + * + * If wl_data_offer.finish request is received for a non drag and drop + * operation, the invalid_finish protocol error is raised. + */ +static inline void +wl_data_offer_finish(struct wl_data_offer *wl_data_offer) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, + WL_DATA_OFFER_FINISH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0); +} + +/** + * @ingroup iface_wl_data_offer + * + * Sets the actions that the destination side client supports for + * this operation. This request may trigger the emission of + * wl_data_source.action and wl_data_offer.action events if the compositor + * needs to change the selected action. + * + * This request can be called multiple times throughout the + * drag-and-drop operation, typically in response to wl_data_device.enter + * or wl_data_device.motion events. + * + * This request determines the final result of the drag-and-drop + * operation. If the end result is that no action is accepted, + * the drag source will receive wl_data_source.cancelled. + * + * The dnd_actions argument must contain only values expressed in the + * wl_data_device_manager.dnd_actions enum, and the preferred_action + * argument must only contain one of those values set, otherwise it + * will result in a protocol error. + * + * While managing an "ask" action, the destination drag-and-drop client + * may perform further wl_data_offer.receive requests, and is expected + * to perform one last wl_data_offer.set_actions request with a preferred + * action other than "ask" (and optionally wl_data_offer.accept) before + * requesting wl_data_offer.finish, in order to convey the action selected + * by the user. If the preferred action is not in the + * wl_data_offer.source_actions mask, an error will be raised. + * + * If the "ask" action is dismissed (e.g. user cancellation), the client + * is expected to perform wl_data_offer.destroy right away. + * + * This request can only be made on drag-and-drop offers, a protocol error + * will be raised otherwise. + */ +static inline void +wl_data_offer_set_actions(struct wl_data_offer *wl_data_offer, uint32_t dnd_actions, uint32_t preferred_action) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, + WL_DATA_OFFER_SET_ACTIONS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, dnd_actions, preferred_action); +} + +#ifndef WL_DATA_SOURCE_ERROR_ENUM +#define WL_DATA_SOURCE_ERROR_ENUM +enum wl_data_source_error { + /** + * action mask contains invalid values + */ + WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK = 0, + /** + * source doesn't accept this request + */ + WL_DATA_SOURCE_ERROR_INVALID_SOURCE = 1, +}; +#endif /* WL_DATA_SOURCE_ERROR_ENUM */ + +/** + * @ingroup iface_wl_data_source + * @struct wl_data_source_listener + */ +struct wl_data_source_listener { + /** + * a target accepts an offered mime type + * + * Sent when a target accepts pointer_focus or motion events. If + * a target does not accept any of the offered types, type is NULL. + * + * Used for feedback during drag-and-drop. + * @param mime_type mime type accepted by the target + */ + void (*target)(void *data, + struct wl_data_source *wl_data_source, + const char *mime_type); + /** + * send the data + * + * Request for data from the client. Send the data as the + * specified mime type over the passed file descriptor, then close + * it. + * @param mime_type mime type for the data + * @param fd file descriptor for the data + */ + void (*send)(void *data, + struct wl_data_source *wl_data_source, + const char *mime_type, + int32_t fd); + /** + * selection was cancelled + * + * This data source is no longer valid. There are several reasons + * why this could happen: + * + * - The data source has been replaced by another data source. - + * The drag-and-drop operation was performed, but the drop + * destination did not accept any of the mime types offered through + * wl_data_source.target. - The drag-and-drop operation was + * performed, but the drop destination did not select any of the + * actions present in the mask offered through + * wl_data_source.action. - The drag-and-drop operation was + * performed but didn't happen over a surface. - The compositor + * cancelled the drag-and-drop operation (e.g. compositor dependent + * timeouts to avoid stale drag-and-drop transfers). + * + * The client should clean up and destroy this data source. + * + * For objects of version 2 or older, wl_data_source.cancelled will + * only be emitted if the data source was replaced by another data + * source. + */ + void (*cancelled)(void *data, + struct wl_data_source *wl_data_source); + /** + * the drag-and-drop operation physically finished + * + * The user performed the drop action. This event does not + * indicate acceptance, wl_data_source.cancelled may still be + * emitted afterwards if the drop destination does not accept any + * mime type. + * + * However, this event might however not be received if the + * compositor cancelled the drag-and-drop operation before this + * event could happen. + * + * Note that the data_source may still be used in the future and + * should not be destroyed here. + * @since 3 + */ + void (*dnd_drop_performed)(void *data, + struct wl_data_source *wl_data_source); + /** + * the drag-and-drop operation concluded + * + * The drop destination finished interoperating with this data + * source, so the client is now free to destroy this data source + * and free all associated data. + * + * If the action used to perform the operation was "move", the + * source can now delete the transferred data. + * @since 3 + */ + void (*dnd_finished)(void *data, + struct wl_data_source *wl_data_source); + /** + * notify the selected action + * + * This event indicates the action selected by the compositor + * after matching the source/destination side actions. Only one + * action (or none) will be offered here. + * + * This event can be emitted multiple times during the + * drag-and-drop operation, mainly in response to destination side + * changes through wl_data_offer.set_actions, and as the data + * device enters/leaves surfaces. + * + * It is only possible to receive this event after + * wl_data_source.dnd_drop_performed if the drag-and-drop operation + * ended in an "ask" action, in which case the final + * wl_data_source.action event will happen immediately before + * wl_data_source.dnd_finished. + * + * Compositors may also change the selected action on the fly, + * mainly in response to keyboard modifier changes during the + * drag-and-drop operation. + * + * The most recent action received is always the valid one. The + * chosen action may change alongside negotiation (e.g. an "ask" + * action can turn into a "move" operation), so the effects of the + * final action must always be applied in + * wl_data_offer.dnd_finished. + * + * Clients can trigger cursor surface changes from this point, so + * they reflect the current action. + * @param dnd_action action selected by the compositor + * @since 3 + */ + void (*action)(void *data, + struct wl_data_source *wl_data_source, + uint32_t dnd_action); +}; + +/** + * @ingroup iface_wl_data_source + */ +static inline int +wl_data_source_add_listener(struct wl_data_source *wl_data_source, + const struct wl_data_source_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_data_source, + (void (**)(void)) listener, data); +} + +#define WL_DATA_SOURCE_OFFER 0 +#define WL_DATA_SOURCE_DESTROY 1 +#define WL_DATA_SOURCE_SET_ACTIONS 2 + +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_TARGET_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_SEND_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_CANCELLED_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION 3 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION 3 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_ACTION_SINCE_VERSION 3 + +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_OFFER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_source + */ +#define WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION 3 + +/** @ingroup iface_wl_data_source */ +static inline void +wl_data_source_set_user_data(struct wl_data_source *wl_data_source, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_data_source, user_data); +} + +/** @ingroup iface_wl_data_source */ +static inline void * +wl_data_source_get_user_data(struct wl_data_source *wl_data_source) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_data_source); +} + +static inline uint32_t +wl_data_source_get_version(struct wl_data_source *wl_data_source) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_data_source); +} + +/** + * @ingroup iface_wl_data_source + * + * This request adds a mime type to the set of mime types + * advertised to targets. Can be called several times to offer + * multiple types. + */ +static inline void +wl_data_source_offer(struct wl_data_source *wl_data_source, const char *mime_type) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source, + WL_DATA_SOURCE_OFFER, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), 0, mime_type); +} + +/** + * @ingroup iface_wl_data_source + * + * Destroy the data source. + */ +static inline void +wl_data_source_destroy(struct wl_data_source *wl_data_source) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source, + WL_DATA_SOURCE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wl_data_source + * + * Sets the actions that the source side client supports for this + * operation. This request may trigger wl_data_source.action and + * wl_data_offer.action events if the compositor needs to change the + * selected action. + * + * The dnd_actions argument must contain only values expressed in the + * wl_data_device_manager.dnd_actions enum, otherwise it will result + * in a protocol error. + * + * This request must be made once only, and can only be made on sources + * used in drag-and-drop, so it must be performed before + * wl_data_device.start_drag. Attempting to use the source other than + * for drag-and-drop will raise a protocol error. + */ +static inline void +wl_data_source_set_actions(struct wl_data_source *wl_data_source, uint32_t dnd_actions) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source, + WL_DATA_SOURCE_SET_ACTIONS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), 0, dnd_actions); +} + +#ifndef WL_DATA_DEVICE_ERROR_ENUM +#define WL_DATA_DEVICE_ERROR_ENUM +enum wl_data_device_error { + /** + * given wl_surface has another role + */ + WL_DATA_DEVICE_ERROR_ROLE = 0, +}; +#endif /* WL_DATA_DEVICE_ERROR_ENUM */ + +/** + * @ingroup iface_wl_data_device + * @struct wl_data_device_listener + */ +struct wl_data_device_listener { + /** + * introduce a new wl_data_offer + * + * The data_offer event introduces a new wl_data_offer object, + * which will subsequently be used in either the data_device.enter + * event (for drag-and-drop) or the data_device.selection event + * (for selections). Immediately following the + * data_device.data_offer event, the new data_offer object will + * send out data_offer.offer events to describe the mime types it + * offers. + * @param id the new data_offer object + */ + void (*data_offer)(void *data, + struct wl_data_device *wl_data_device, + struct wl_data_offer *id); + /** + * initiate drag-and-drop session + * + * This event is sent when an active drag-and-drop pointer enters + * a surface owned by the client. The position of the pointer at + * enter time is provided by the x and y arguments, in + * surface-local coordinates. + * @param serial serial number of the enter event + * @param surface client surface entered + * @param x surface-local x coordinate + * @param y surface-local y coordinate + * @param id source data_offer object + */ + void (*enter)(void *data, + struct wl_data_device *wl_data_device, + uint32_t serial, + struct wl_surface *surface, + wl_fixed_t x, + wl_fixed_t y, + struct wl_data_offer *id); + /** + * end drag-and-drop session + * + * This event is sent when the drag-and-drop pointer leaves the + * surface and the session ends. The client must destroy the + * wl_data_offer introduced at enter time at this point. + */ + void (*leave)(void *data, + struct wl_data_device *wl_data_device); + /** + * drag-and-drop session motion + * + * This event is sent when the drag-and-drop pointer moves within + * the currently focused surface. The new position of the pointer + * is provided by the x and y arguments, in surface-local + * coordinates. + * @param time timestamp with millisecond granularity + * @param x surface-local x coordinate + * @param y surface-local y coordinate + */ + void (*motion)(void *data, + struct wl_data_device *wl_data_device, + uint32_t time, + wl_fixed_t x, + wl_fixed_t y); + /** + * end drag-and-drop session successfully + * + * The event is sent when a drag-and-drop operation is ended + * because the implicit grab is removed. + * + * The drag-and-drop destination is expected to honor the last + * action received through wl_data_offer.action, if the resulting + * action is "copy" or "move", the destination can still perform + * wl_data_offer.receive requests, and is expected to end all + * transfers with a wl_data_offer.finish request. + * + * If the resulting action is "ask", the action will not be + * considered final. The drag-and-drop destination is expected to + * perform one last wl_data_offer.set_actions request, or + * wl_data_offer.destroy in order to cancel the operation. + */ + void (*drop)(void *data, + struct wl_data_device *wl_data_device); + /** + * advertise new selection + * + * The selection event is sent out to notify the client of a new + * wl_data_offer for the selection for this device. The + * data_device.data_offer and the data_offer.offer events are sent + * out immediately before this event to introduce the data offer + * object. The selection event is sent to a client immediately + * before receiving keyboard focus and when a new selection is set + * while the client has keyboard focus. The data_offer is valid + * until a new data_offer or NULL is received or until the client + * loses keyboard focus. Switching surface with keyboard focus + * within the same client doesn't mean a new selection will be + * sent. The client must destroy the previous selection data_offer, + * if any, upon receiving this event. + * @param id selection data_offer object + */ + void (*selection)(void *data, + struct wl_data_device *wl_data_device, + struct wl_data_offer *id); +}; + +/** + * @ingroup iface_wl_data_device + */ +static inline int +wl_data_device_add_listener(struct wl_data_device *wl_data_device, + const struct wl_data_device_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_data_device, + (void (**)(void)) listener, data); +} + +#define WL_DATA_DEVICE_START_DRAG 0 +#define WL_DATA_DEVICE_SET_SELECTION 1 +#define WL_DATA_DEVICE_RELEASE 2 + +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_DATA_OFFER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_ENTER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_LEAVE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_MOTION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_DROP_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_SELECTION_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_START_DRAG_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_SET_SELECTION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device + */ +#define WL_DATA_DEVICE_RELEASE_SINCE_VERSION 2 + +/** @ingroup iface_wl_data_device */ +static inline void +wl_data_device_set_user_data(struct wl_data_device *wl_data_device, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_data_device, user_data); +} + +/** @ingroup iface_wl_data_device */ +static inline void * +wl_data_device_get_user_data(struct wl_data_device *wl_data_device) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_data_device); +} + +static inline uint32_t +wl_data_device_get_version(struct wl_data_device *wl_data_device) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_data_device); +} + +/** @ingroup iface_wl_data_device */ +static inline void +wl_data_device_destroy(struct wl_data_device *wl_data_device) +{ + wl_proxy_destroy((struct wl_proxy *) wl_data_device); +} + +/** + * @ingroup iface_wl_data_device + * + * This request asks the compositor to start a drag-and-drop + * operation on behalf of the client. + * + * The source argument is the data source that provides the data + * for the eventual data transfer. If source is NULL, enter, leave + * and motion events are sent only to the client that initiated the + * drag and the client is expected to handle the data passing + * internally. If source is destroyed, the drag-and-drop session will be + * cancelled. + * + * The origin surface is the surface where the drag originates and + * the client must have an active implicit grab that matches the + * serial. + * + * The icon surface is an optional (can be NULL) surface that + * provides an icon to be moved around with the cursor. Initially, + * the top-left corner of the icon surface is placed at the cursor + * hotspot, but subsequent wl_surface.attach request can move the + * relative position. Attach requests must be confirmed with + * wl_surface.commit as usual. The icon surface is given the role of + * a drag-and-drop icon. If the icon surface already has another role, + * it raises a protocol error. + * + * The current and pending input regions of the icon wl_surface are + * cleared, and wl_surface.set_input_region is ignored until the + * wl_surface is no longer used as the icon surface. When the use + * as an icon ends, the current and pending input regions become + * undefined, and the wl_surface is unmapped. + */ +static inline void +wl_data_device_start_drag(struct wl_data_device *wl_data_device, struct wl_data_source *source, struct wl_surface *origin, struct wl_surface *icon, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device, + WL_DATA_DEVICE_START_DRAG, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), 0, source, origin, icon, serial); +} + +/** + * @ingroup iface_wl_data_device + * + * This request asks the compositor to set the selection + * to the data from the source on behalf of the client. + * + * To unset the selection, set the source to NULL. + */ +static inline void +wl_data_device_set_selection(struct wl_data_device *wl_data_device, struct wl_data_source *source, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device, + WL_DATA_DEVICE_SET_SELECTION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), 0, source, serial); +} + +/** + * @ingroup iface_wl_data_device + * + * This request destroys the data device. + */ +static inline void +wl_data_device_release(struct wl_data_device *wl_data_device) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device, + WL_DATA_DEVICE_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), WL_MARSHAL_FLAG_DESTROY); +} + +#ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM +#define WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM +/** + * @ingroup iface_wl_data_device_manager + * drag and drop actions + * + * This is a bitmask of the available/preferred actions in a + * drag-and-drop operation. + * + * In the compositor, the selected action is a result of matching the + * actions offered by the source and destination sides. "action" events + * with a "none" action will be sent to both source and destination if + * there is no match. All further checks will effectively happen on + * (source actions ∩ destination actions). + * + * In addition, compositors may also pick different actions in + * reaction to key modifiers being pressed. One common design that + * is used in major toolkits (and the behavior recommended for + * compositors) is: + * + * - If no modifiers are pressed, the first match (in bit order) + * will be used. + * - Pressing Shift selects "move", if enabled in the mask. + * - Pressing Control selects "copy", if enabled in the mask. + * + * Behavior beyond that is considered implementation-dependent. + * Compositors may for example bind other modifiers (like Alt/Meta) + * or drags initiated with other buttons than BTN_LEFT to specific + * actions (e.g. "ask"). + */ +enum wl_data_device_manager_dnd_action { + /** + * no action + */ + WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE = 0, + /** + * copy action + */ + WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY = 1, + /** + * move action + */ + WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE = 2, + /** + * ask action + */ + WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4, +}; +#endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */ + +#define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE 0 +#define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE 1 + + +/** + * @ingroup iface_wl_data_device_manager + */ +#define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_data_device_manager + */ +#define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE_SINCE_VERSION 1 + +/** @ingroup iface_wl_data_device_manager */ +static inline void +wl_data_device_manager_set_user_data(struct wl_data_device_manager *wl_data_device_manager, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_data_device_manager, user_data); +} + +/** @ingroup iface_wl_data_device_manager */ +static inline void * +wl_data_device_manager_get_user_data(struct wl_data_device_manager *wl_data_device_manager) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_data_device_manager); +} + +static inline uint32_t +wl_data_device_manager_get_version(struct wl_data_device_manager *wl_data_device_manager) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager); +} + +/** @ingroup iface_wl_data_device_manager */ +static inline void +wl_data_device_manager_destroy(struct wl_data_device_manager *wl_data_device_manager) +{ + wl_proxy_destroy((struct wl_proxy *) wl_data_device_manager); +} + +/** + * @ingroup iface_wl_data_device_manager + * + * Create a new data source. + */ +static inline struct wl_data_source * +wl_data_device_manager_create_data_source(struct wl_data_device_manager *wl_data_device_manager) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device_manager, + WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE, &wl_data_source_interface, wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager), 0, NULL); + + return (struct wl_data_source *) id; +} + +/** + * @ingroup iface_wl_data_device_manager + * + * Create a new data device for a given seat. + */ +static inline struct wl_data_device * +wl_data_device_manager_get_data_device(struct wl_data_device_manager *wl_data_device_manager, struct wl_seat *seat) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device_manager, + WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE, &wl_data_device_interface, wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager), 0, NULL, seat); + + return (struct wl_data_device *) id; +} + +#ifndef WL_SHELL_ERROR_ENUM +#define WL_SHELL_ERROR_ENUM +enum wl_shell_error { + /** + * given wl_surface has another role + */ + WL_SHELL_ERROR_ROLE = 0, +}; +#endif /* WL_SHELL_ERROR_ENUM */ + +#define WL_SHELL_GET_SHELL_SURFACE 0 + + +/** + * @ingroup iface_wl_shell + */ +#define WL_SHELL_GET_SHELL_SURFACE_SINCE_VERSION 1 + +/** @ingroup iface_wl_shell */ +static inline void +wl_shell_set_user_data(struct wl_shell *wl_shell, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_shell, user_data); +} + +/** @ingroup iface_wl_shell */ +static inline void * +wl_shell_get_user_data(struct wl_shell *wl_shell) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_shell); +} + +static inline uint32_t +wl_shell_get_version(struct wl_shell *wl_shell) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_shell); +} + +/** @ingroup iface_wl_shell */ +static inline void +wl_shell_destroy(struct wl_shell *wl_shell) +{ + wl_proxy_destroy((struct wl_proxy *) wl_shell); +} + +/** + * @ingroup iface_wl_shell + * + * Create a shell surface for an existing surface. This gives + * the wl_surface the role of a shell surface. If the wl_surface + * already has another role, it raises a protocol error. + * + * Only one shell surface can be associated with a given surface. + */ +static inline struct wl_shell_surface * +wl_shell_get_shell_surface(struct wl_shell *wl_shell, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shell, + WL_SHELL_GET_SHELL_SURFACE, &wl_shell_surface_interface, wl_proxy_get_version((struct wl_proxy *) wl_shell), 0, NULL, surface); + + return (struct wl_shell_surface *) id; +} + +#ifndef WL_SHELL_SURFACE_RESIZE_ENUM +#define WL_SHELL_SURFACE_RESIZE_ENUM +/** + * @ingroup iface_wl_shell_surface + * edge values for resizing + * + * These values are used to indicate which edge of a surface + * is being dragged in a resize operation. The server may + * use this information to adapt its behavior, e.g. choose + * an appropriate cursor image. + */ +enum wl_shell_surface_resize { + /** + * no edge + */ + WL_SHELL_SURFACE_RESIZE_NONE = 0, + /** + * top edge + */ + WL_SHELL_SURFACE_RESIZE_TOP = 1, + /** + * bottom edge + */ + WL_SHELL_SURFACE_RESIZE_BOTTOM = 2, + /** + * left edge + */ + WL_SHELL_SURFACE_RESIZE_LEFT = 4, + /** + * top and left edges + */ + WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5, + /** + * bottom and left edges + */ + WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6, + /** + * right edge + */ + WL_SHELL_SURFACE_RESIZE_RIGHT = 8, + /** + * top and right edges + */ + WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9, + /** + * bottom and right edges + */ + WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10, +}; +#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */ + +#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM +#define WL_SHELL_SURFACE_TRANSIENT_ENUM +/** + * @ingroup iface_wl_shell_surface + * details of transient behaviour + * + * These flags specify details of the expected behaviour + * of transient surfaces. Used in the set_transient request. + */ +enum wl_shell_surface_transient { + /** + * do not set keyboard focus + */ + WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1, +}; +#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */ + +#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM +#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM +/** + * @ingroup iface_wl_shell_surface + * different method to set the surface fullscreen + * + * Hints to indicate to the compositor how to deal with a conflict + * between the dimensions of the surface and the dimensions of the + * output. The compositor is free to ignore this parameter. + */ +enum wl_shell_surface_fullscreen_method { + /** + * no preference, apply default policy + */ + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0, + /** + * scale, preserve the surface's aspect ratio and center on output + */ + WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1, + /** + * switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch + */ + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2, + /** + * no upscaling, center on output and add black borders to compensate size mismatch + */ + WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3, +}; +#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */ + +/** + * @ingroup iface_wl_shell_surface + * @struct wl_shell_surface_listener + */ +struct wl_shell_surface_listener { + /** + * ping client + * + * Ping a client to check if it is receiving events and sending + * requests. A client is expected to reply with a pong request. + * @param serial serial number of the ping + */ + void (*ping)(void *data, + struct wl_shell_surface *wl_shell_surface, + uint32_t serial); + /** + * suggest resize + * + * The configure event asks the client to resize its surface. + * + * The size is a hint, in the sense that the client is free to + * ignore it if it doesn't resize, pick a smaller size (to satisfy + * aspect ratio or resize in steps of NxM pixels). + * + * The edges parameter provides a hint about how the surface was + * resized. The client may use this information to decide how to + * adjust its content to the new size (e.g. a scrolling area might + * adjust its content position to leave the viewable content + * unmoved). + * + * The client is free to dismiss all but the last configure event + * it received. + * + * The width and height arguments specify the size of the window in + * surface-local coordinates. + * @param edges how the surface was resized + * @param width new width of the surface + * @param height new height of the surface + */ + void (*configure)(void *data, + struct wl_shell_surface *wl_shell_surface, + uint32_t edges, + int32_t width, + int32_t height); + /** + * popup interaction is done + * + * The popup_done event is sent out when a popup grab is broken, + * that is, when the user clicks a surface that doesn't belong to + * the client owning the popup surface. + */ + void (*popup_done)(void *data, + struct wl_shell_surface *wl_shell_surface); +}; + +/** + * @ingroup iface_wl_shell_surface + */ +static inline int +wl_shell_surface_add_listener(struct wl_shell_surface *wl_shell_surface, + const struct wl_shell_surface_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_shell_surface, + (void (**)(void)) listener, data); +} + +#define WL_SHELL_SURFACE_PONG 0 +#define WL_SHELL_SURFACE_MOVE 1 +#define WL_SHELL_SURFACE_RESIZE 2 +#define WL_SHELL_SURFACE_SET_TOPLEVEL 3 +#define WL_SHELL_SURFACE_SET_TRANSIENT 4 +#define WL_SHELL_SURFACE_SET_FULLSCREEN 5 +#define WL_SHELL_SURFACE_SET_POPUP 6 +#define WL_SHELL_SURFACE_SET_MAXIMIZED 7 +#define WL_SHELL_SURFACE_SET_TITLE 8 +#define WL_SHELL_SURFACE_SET_CLASS 9 + +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_PING_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_POPUP_DONE_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_PONG_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_MOVE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_RESIZE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_TOPLEVEL_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_TRANSIENT_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_POPUP_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_TITLE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_shell_surface + */ +#define WL_SHELL_SURFACE_SET_CLASS_SINCE_VERSION 1 + +/** @ingroup iface_wl_shell_surface */ +static inline void +wl_shell_surface_set_user_data(struct wl_shell_surface *wl_shell_surface, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_shell_surface, user_data); +} + +/** @ingroup iface_wl_shell_surface */ +static inline void * +wl_shell_surface_get_user_data(struct wl_shell_surface *wl_shell_surface) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_shell_surface); +} + +static inline uint32_t +wl_shell_surface_get_version(struct wl_shell_surface *wl_shell_surface) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_shell_surface); +} + +/** @ingroup iface_wl_shell_surface */ +static inline void +wl_shell_surface_destroy(struct wl_shell_surface *wl_shell_surface) +{ + wl_proxy_destroy((struct wl_proxy *) wl_shell_surface); +} + +/** + * @ingroup iface_wl_shell_surface + * + * A client must respond to a ping event with a pong request or + * the client may be deemed unresponsive. + */ +static inline void +wl_shell_surface_pong(struct wl_shell_surface *wl_shell_surface, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_PONG, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, serial); +} + +/** + * @ingroup iface_wl_shell_surface + * + * Start a pointer-driven move of the surface. + * + * This request must be used in response to a button press event. + * The server may ignore move requests depending on the state of + * the surface (e.g. fullscreen or maximized). + */ +static inline void +wl_shell_surface_move(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial); +} + +/** + * @ingroup iface_wl_shell_surface + * + * Start a pointer-driven resizing of the surface. + * + * This request must be used in response to a button press event. + * The server may ignore resize requests depending on the state of + * the surface (e.g. fullscreen or maximized). + */ +static inline void +wl_shell_surface_resize(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, uint32_t edges) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial, edges); +} + +/** + * @ingroup iface_wl_shell_surface + * + * Map the surface as a toplevel surface. + * + * A toplevel surface is not fullscreen, maximized or transient. + */ +static inline void +wl_shell_surface_set_toplevel(struct wl_shell_surface *wl_shell_surface) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_TOPLEVEL, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0); +} + +/** + * @ingroup iface_wl_shell_surface + * + * Map the surface relative to an existing surface. + * + * The x and y arguments specify the location of the upper left + * corner of the surface relative to the upper left corner of the + * parent surface, in surface-local coordinates. + * + * The flags argument controls details of the transient behaviour. + */ +static inline void +wl_shell_surface_set_transient(struct wl_shell_surface *wl_shell_surface, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_TRANSIENT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, parent, x, y, flags); +} + +/** + * @ingroup iface_wl_shell_surface + * + * Map the surface as a fullscreen surface. + * + * If an output parameter is given then the surface will be made + * fullscreen on that output. If the client does not specify the + * output then the compositor will apply its policy - usually + * choosing the output on which the surface has the biggest surface + * area. + * + * The client may specify a method to resolve a size conflict + * between the output size and the surface size - this is provided + * through the method parameter. + * + * The framerate parameter is used only when the method is set + * to "driver", to indicate the preferred framerate. A value of 0 + * indicates that the client does not care about framerate. The + * framerate is specified in mHz, that is framerate of 60000 is 60Hz. + * + * A method of "scale" or "driver" implies a scaling operation of + * the surface, either via a direct scaling operation or a change of + * the output mode. This will override any kind of output scaling, so + * that mapping a surface with a buffer size equal to the mode can + * fill the screen independent of buffer_scale. + * + * A method of "fill" means we don't scale up the buffer, however + * any output scale is applied. This means that you may run into + * an edge case where the application maps a buffer with the same + * size of the output mode but buffer_scale 1 (thus making a + * surface larger than the output). In this case it is allowed to + * downscale the results to fit the screen. + * + * The compositor must reply to this request with a configure event + * with the dimensions for the output on which the surface will + * be made fullscreen. + */ +static inline void +wl_shell_surface_set_fullscreen(struct wl_shell_surface *wl_shell_surface, uint32_t method, uint32_t framerate, struct wl_output *output) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, method, framerate, output); +} + +/** + * @ingroup iface_wl_shell_surface + * + * Map the surface as a popup. + * + * A popup surface is a transient surface with an added pointer + * grab. + * + * An existing implicit grab will be changed to owner-events mode, + * and the popup grab will continue after the implicit grab ends + * (i.e. releasing the mouse button does not cause the popup to + * be unmapped). + * + * The popup grab continues until the window is destroyed or a + * mouse button is pressed in any other client's window. A click + * in any of the client's surfaces is reported as normal, however, + * clicks in other clients' surfaces will be discarded and trigger + * the callback. + * + * The x and y arguments specify the location of the upper left + * corner of the surface relative to the upper left corner of the + * parent surface, in surface-local coordinates. + */ +static inline void +wl_shell_surface_set_popup(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_POPUP, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial, parent, x, y, flags); +} + +/** + * @ingroup iface_wl_shell_surface + * + * Map the surface as a maximized surface. + * + * If an output parameter is given then the surface will be + * maximized on that output. If the client does not specify the + * output then the compositor will apply its policy - usually + * choosing the output on which the surface has the biggest surface + * area. + * + * The compositor will reply with a configure event telling + * the expected new surface size. The operation is completed + * on the next buffer attach to this surface. + * + * A maximized surface typically fills the entire output it is + * bound to, except for desktop elements such as panels. This is + * the main difference between a maximized shell surface and a + * fullscreen shell surface. + * + * The details depend on the compositor implementation. + */ +static inline void +wl_shell_surface_set_maximized(struct wl_shell_surface *wl_shell_surface, struct wl_output *output) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, output); +} + +/** + * @ingroup iface_wl_shell_surface + * + * Set a short title for the surface. + * + * This string may be used to identify the surface in a task bar, + * window list, or other user interface elements provided by the + * compositor. + * + * The string must be encoded in UTF-8. + */ +static inline void +wl_shell_surface_set_title(struct wl_shell_surface *wl_shell_surface, const char *title) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_TITLE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, title); +} + +/** + * @ingroup iface_wl_shell_surface + * + * Set a class for the surface. + * + * The surface class identifies the general class of applications + * to which the surface belongs. A common convention is to use the + * file name (or the full path if it is a non-standard location) of + * the application's .desktop file as the class. + */ +static inline void +wl_shell_surface_set_class(struct wl_shell_surface *wl_shell_surface, const char *class_) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, + WL_SHELL_SURFACE_SET_CLASS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, class_); +} + +#ifndef WL_SURFACE_ERROR_ENUM +#define WL_SURFACE_ERROR_ENUM +/** + * @ingroup iface_wl_surface + * wl_surface error values + * + * These errors can be emitted in response to wl_surface requests. + */ +enum wl_surface_error { + /** + * buffer scale value is invalid + */ + WL_SURFACE_ERROR_INVALID_SCALE = 0, + /** + * buffer transform value is invalid + */ + WL_SURFACE_ERROR_INVALID_TRANSFORM = 1, + /** + * buffer size is invalid + */ + WL_SURFACE_ERROR_INVALID_SIZE = 2, + /** + * buffer offset is invalid + */ + WL_SURFACE_ERROR_INVALID_OFFSET = 3, +}; +#endif /* WL_SURFACE_ERROR_ENUM */ + +/** + * @ingroup iface_wl_surface + * @struct wl_surface_listener + */ +struct wl_surface_listener { + /** + * surface enters an output + * + * This is emitted whenever a surface's creation, movement, or + * resizing results in some part of it being within the scanout + * region of an output. + * + * Note that a surface may be overlapping with zero or more + * outputs. + * @param output output entered by the surface + */ + void (*enter)(void *data, + struct wl_surface *wl_surface, + struct wl_output *output); + /** + * surface leaves an output + * + * This is emitted whenever a surface's creation, movement, or + * resizing results in it no longer having any part of it within + * the scanout region of an output. + * + * Clients should not use the number of outputs the surface is on + * for frame throttling purposes. The surface might be hidden even + * if no leave event has been sent, and the compositor might expect + * new surface content updates even if no enter event has been + * sent. The frame event should be used instead. + * @param output output left by the surface + */ + void (*leave)(void *data, + struct wl_surface *wl_surface, + struct wl_output *output); +}; + +/** + * @ingroup iface_wl_surface + */ +static inline int +wl_surface_add_listener(struct wl_surface *wl_surface, + const struct wl_surface_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_surface, + (void (**)(void)) listener, data); +} + +#define WL_SURFACE_DESTROY 0 +#define WL_SURFACE_ATTACH 1 +#define WL_SURFACE_DAMAGE 2 +#define WL_SURFACE_FRAME 3 +#define WL_SURFACE_SET_OPAQUE_REGION 4 +#define WL_SURFACE_SET_INPUT_REGION 5 +#define WL_SURFACE_COMMIT 6 +#define WL_SURFACE_SET_BUFFER_TRANSFORM 7 +#define WL_SURFACE_SET_BUFFER_SCALE 8 +#define WL_SURFACE_DAMAGE_BUFFER 9 +#define WL_SURFACE_OFFSET 10 + +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_ENTER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_LEAVE_SINCE_VERSION 1 + +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_ATTACH_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_DAMAGE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_FRAME_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_SET_OPAQUE_REGION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_SET_INPUT_REGION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_COMMIT_SINCE_VERSION 1 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_SET_BUFFER_TRANSFORM_SINCE_VERSION 2 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION 3 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION 4 +/** + * @ingroup iface_wl_surface + */ +#define WL_SURFACE_OFFSET_SINCE_VERSION 5 + +/** @ingroup iface_wl_surface */ +static inline void +wl_surface_set_user_data(struct wl_surface *wl_surface, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_surface, user_data); +} + +/** @ingroup iface_wl_surface */ +static inline void * +wl_surface_get_user_data(struct wl_surface *wl_surface) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_surface); +} + +static inline uint32_t +wl_surface_get_version(struct wl_surface *wl_surface) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_surface); +} + +/** + * @ingroup iface_wl_surface + * + * Deletes the surface and invalidates its object ID. + */ +static inline void +wl_surface_destroy(struct wl_surface *wl_surface) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wl_surface + * + * Set a buffer as the content of this surface. + * + * The new size of the surface is calculated based on the buffer + * size transformed by the inverse buffer_transform and the + * inverse buffer_scale. This means that at commit time the supplied + * buffer size must be an integer multiple of the buffer_scale. If + * that's not the case, an invalid_size error is sent. + * + * The x and y arguments specify the location of the new pending + * buffer's upper left corner, relative to the current buffer's upper + * left corner, in surface-local coordinates. In other words, the + * x and y, combined with the new surface size define in which + * directions the surface's size changes. Setting anything other than 0 + * as x and y arguments is discouraged, and should instead be replaced + * with using the separate wl_surface.offset request. + * + * When the bound wl_surface version is 5 or higher, passing any + * non-zero x or y is a protocol violation, and will result in an + * 'invalid_offset' error being raised. To achieve equivalent semantics, + * use wl_surface.offset. + * + * Surface contents are double-buffered state, see wl_surface.commit. + * + * The initial surface contents are void; there is no content. + * wl_surface.attach assigns the given wl_buffer as the pending + * wl_buffer. wl_surface.commit makes the pending wl_buffer the new + * surface contents, and the size of the surface becomes the size + * calculated from the wl_buffer, as described above. After commit, + * there is no pending buffer until the next attach. + * + * Committing a pending wl_buffer allows the compositor to read the + * pixels in the wl_buffer. The compositor may access the pixels at + * any time after the wl_surface.commit request. When the compositor + * will not access the pixels anymore, it will send the + * wl_buffer.release event. Only after receiving wl_buffer.release, + * the client may reuse the wl_buffer. A wl_buffer that has been + * attached and then replaced by another attach instead of committed + * will not receive a release event, and is not used by the + * compositor. + * + * If a pending wl_buffer has been committed to more than one wl_surface, + * the delivery of wl_buffer.release events becomes undefined. A well + * behaved client should not rely on wl_buffer.release events in this + * case. Alternatively, a client could create multiple wl_buffer objects + * from the same backing storage or use wp_linux_buffer_release. + * + * Destroying the wl_buffer after wl_buffer.release does not change + * the surface contents. Destroying the wl_buffer before wl_buffer.release + * is allowed as long as the underlying buffer storage isn't re-used (this + * can happen e.g. on client process termination). However, if the client + * destroys the wl_buffer before receiving the wl_buffer.release event and + * mutates the underlying buffer storage, the surface contents become + * undefined immediately. + * + * If wl_surface.attach is sent with a NULL wl_buffer, the + * following wl_surface.commit will remove the surface content. + */ +static inline void +wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer, int32_t x, int32_t y) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_ATTACH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, buffer, x, y); +} + +/** + * @ingroup iface_wl_surface + * + * This request is used to describe the regions where the pending + * buffer is different from the current surface contents, and where + * the surface therefore needs to be repainted. The compositor + * ignores the parts of the damage that fall outside of the surface. + * + * Damage is double-buffered state, see wl_surface.commit. + * + * The damage rectangle is specified in surface-local coordinates, + * where x and y specify the upper left corner of the damage rectangle. + * + * The initial value for pending damage is empty: no damage. + * wl_surface.damage adds pending damage: the new pending damage + * is the union of old pending damage and the given rectangle. + * + * wl_surface.commit assigns pending damage as the current damage, + * and clears pending damage. The server will clear the current + * damage as it repaints the surface. + * + * Note! New clients should not use this request. Instead damage can be + * posted with wl_surface.damage_buffer which uses buffer coordinates + * instead of surface coordinates. + */ +static inline void +wl_surface_damage(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_DAMAGE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y, width, height); +} + +/** + * @ingroup iface_wl_surface + * + * Request a notification when it is a good time to start drawing a new + * frame, by creating a frame callback. This is useful for throttling + * redrawing operations, and driving animations. + * + * When a client is animating on a wl_surface, it can use the 'frame' + * request to get notified when it is a good time to draw and commit the + * next frame of animation. If the client commits an update earlier than + * that, it is likely that some updates will not make it to the display, + * and the client is wasting resources by drawing too often. + * + * The frame request will take effect on the next wl_surface.commit. + * The notification will only be posted for one frame unless + * requested again. For a wl_surface, the notifications are posted in + * the order the frame requests were committed. + * + * The server must send the notifications so that a client + * will not send excessive updates, while still allowing + * the highest possible update rate for clients that wait for the reply + * before drawing again. The server should give some time for the client + * to draw and commit after sending the frame callback events to let it + * hit the next output refresh. + * + * A server should avoid signaling the frame callbacks if the + * surface is not visible in any way, e.g. the surface is off-screen, + * or completely obscured by other opaque surfaces. + * + * The object returned by this request will be destroyed by the + * compositor after the callback is fired and as such the client must not + * attempt to use it after that point. + * + * The callback_data passed in the callback is the current time, in + * milliseconds, with an undefined base. + */ +static inline struct wl_callback * +wl_surface_frame(struct wl_surface *wl_surface) +{ + struct wl_proxy *callback; + + callback = wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_FRAME, &wl_callback_interface, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, NULL); + + return (struct wl_callback *) callback; +} + +/** + * @ingroup iface_wl_surface + * + * This request sets the region of the surface that contains + * opaque content. + * + * The opaque region is an optimization hint for the compositor + * that lets it optimize the redrawing of content behind opaque + * regions. Setting an opaque region is not required for correct + * behaviour, but marking transparent content as opaque will result + * in repaint artifacts. + * + * The opaque region is specified in surface-local coordinates. + * + * The compositor ignores the parts of the opaque region that fall + * outside of the surface. + * + * Opaque region is double-buffered state, see wl_surface.commit. + * + * wl_surface.set_opaque_region changes the pending opaque region. + * wl_surface.commit copies the pending region to the current region. + * Otherwise, the pending and current regions are never changed. + * + * The initial value for an opaque region is empty. Setting the pending + * opaque region has copy semantics, and the wl_region object can be + * destroyed immediately. A NULL wl_region causes the pending opaque + * region to be set to empty. + */ +static inline void +wl_surface_set_opaque_region(struct wl_surface *wl_surface, struct wl_region *region) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_SET_OPAQUE_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, region); +} + +/** + * @ingroup iface_wl_surface + * + * This request sets the region of the surface that can receive + * pointer and touch events. + * + * Input events happening outside of this region will try the next + * surface in the server surface stack. The compositor ignores the + * parts of the input region that fall outside of the surface. + * + * The input region is specified in surface-local coordinates. + * + * Input region is double-buffered state, see wl_surface.commit. + * + * wl_surface.set_input_region changes the pending input region. + * wl_surface.commit copies the pending region to the current region. + * Otherwise the pending and current regions are never changed, + * except cursor and icon surfaces are special cases, see + * wl_pointer.set_cursor and wl_data_device.start_drag. + * + * The initial value for an input region is infinite. That means the + * whole surface will accept input. Setting the pending input region + * has copy semantics, and the wl_region object can be destroyed + * immediately. A NULL wl_region causes the input region to be set + * to infinite. + */ +static inline void +wl_surface_set_input_region(struct wl_surface *wl_surface, struct wl_region *region) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_SET_INPUT_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, region); +} + +/** + * @ingroup iface_wl_surface + * + * Surface state (input, opaque, and damage regions, attached buffers, + * etc.) is double-buffered. Protocol requests modify the pending state, + * as opposed to the current state in use by the compositor. A commit + * request atomically applies all pending state, replacing the current + * state. After commit, the new pending state is as documented for each + * related request. + * + * On commit, a pending wl_buffer is applied first, and all other state + * second. This means that all coordinates in double-buffered state are + * relative to the new wl_buffer coming into use, except for + * wl_surface.attach itself. If there is no pending wl_buffer, the + * coordinates are relative to the current surface contents. + * + * All requests that need a commit to become effective are documented + * to affect double-buffered state. + * + * Other interfaces may add further double-buffered surface state. + */ +static inline void +wl_surface_commit(struct wl_surface *wl_surface) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_COMMIT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0); +} + +/** + * @ingroup iface_wl_surface + * + * This request sets an optional transformation on how the compositor + * interprets the contents of the buffer attached to the surface. The + * accepted values for the transform parameter are the values for + * wl_output.transform. + * + * Buffer transform is double-buffered state, see wl_surface.commit. + * + * A newly created surface has its buffer transformation set to normal. + * + * wl_surface.set_buffer_transform changes the pending buffer + * transformation. wl_surface.commit copies the pending buffer + * transformation to the current one. Otherwise, the pending and current + * values are never changed. + * + * The purpose of this request is to allow clients to render content + * according to the output transform, thus permitting the compositor to + * use certain optimizations even if the display is rotated. Using + * hardware overlays and scanning out a client buffer for fullscreen + * surfaces are examples of such optimizations. Those optimizations are + * highly dependent on the compositor implementation, so the use of this + * request should be considered on a case-by-case basis. + * + * Note that if the transform value includes 90 or 270 degree rotation, + * the width of the buffer will become the surface height and the height + * of the buffer will become the surface width. + * + * If transform is not one of the values from the + * wl_output.transform enum the invalid_transform protocol error + * is raised. + */ +static inline void +wl_surface_set_buffer_transform(struct wl_surface *wl_surface, int32_t transform) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_SET_BUFFER_TRANSFORM, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, transform); +} + +/** + * @ingroup iface_wl_surface + * + * This request sets an optional scaling factor on how the compositor + * interprets the contents of the buffer attached to the window. + * + * Buffer scale is double-buffered state, see wl_surface.commit. + * + * A newly created surface has its buffer scale set to 1. + * + * wl_surface.set_buffer_scale changes the pending buffer scale. + * wl_surface.commit copies the pending buffer scale to the current one. + * Otherwise, the pending and current values are never changed. + * + * The purpose of this request is to allow clients to supply higher + * resolution buffer data for use on high resolution outputs. It is + * intended that you pick the same buffer scale as the scale of the + * output that the surface is displayed on. This means the compositor + * can avoid scaling when rendering the surface on that output. + * + * Note that if the scale is larger than 1, then you have to attach + * a buffer that is larger (by a factor of scale in each dimension) + * than the desired surface size. + * + * If scale is not positive the invalid_scale protocol error is + * raised. + */ +static inline void +wl_surface_set_buffer_scale(struct wl_surface *wl_surface, int32_t scale) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_SET_BUFFER_SCALE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, scale); +} + +/** + * @ingroup iface_wl_surface + * + * This request is used to describe the regions where the pending + * buffer is different from the current surface contents, and where + * the surface therefore needs to be repainted. The compositor + * ignores the parts of the damage that fall outside of the surface. + * + * Damage is double-buffered state, see wl_surface.commit. + * + * The damage rectangle is specified in buffer coordinates, + * where x and y specify the upper left corner of the damage rectangle. + * + * The initial value for pending damage is empty: no damage. + * wl_surface.damage_buffer adds pending damage: the new pending + * damage is the union of old pending damage and the given rectangle. + * + * wl_surface.commit assigns pending damage as the current damage, + * and clears pending damage. The server will clear the current + * damage as it repaints the surface. + * + * This request differs from wl_surface.damage in only one way - it + * takes damage in buffer coordinates instead of surface-local + * coordinates. While this generally is more intuitive than surface + * coordinates, it is especially desirable when using wp_viewport + * or when a drawing library (like EGL) is unaware of buffer scale + * and buffer transform. + * + * Note: Because buffer transformation changes and damage requests may + * be interleaved in the protocol stream, it is impossible to determine + * the actual mapping between surface and buffer damage until + * wl_surface.commit time. Therefore, compositors wishing to take both + * kinds of damage into account will have to accumulate damage from the + * two requests separately and only transform from one to the other + * after receiving the wl_surface.commit. + */ +static inline void +wl_surface_damage_buffer(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_DAMAGE_BUFFER, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y, width, height); +} + +/** + * @ingroup iface_wl_surface + * + * The x and y arguments specify the location of the new pending + * buffer's upper left corner, relative to the current buffer's upper + * left corner, in surface-local coordinates. In other words, the + * x and y, combined with the new surface size define in which + * directions the surface's size changes. + * + * Surface location offset is double-buffered state, see + * wl_surface.commit. + * + * This request is semantically equivalent to and the replaces the x and y + * arguments in the wl_surface.attach request in wl_surface versions prior + * to 5. See wl_surface.attach for details. + */ +static inline void +wl_surface_offset(struct wl_surface *wl_surface, int32_t x, int32_t y) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_OFFSET, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y); +} + +#ifndef WL_SEAT_CAPABILITY_ENUM +#define WL_SEAT_CAPABILITY_ENUM +/** + * @ingroup iface_wl_seat + * seat capability bitmask + * + * This is a bitmask of capabilities this seat has; if a member is + * set, then it is present on the seat. + */ +enum wl_seat_capability { + /** + * the seat has pointer devices + */ + WL_SEAT_CAPABILITY_POINTER = 1, + /** + * the seat has one or more keyboards + */ + WL_SEAT_CAPABILITY_KEYBOARD = 2, + /** + * the seat has touch devices + */ + WL_SEAT_CAPABILITY_TOUCH = 4, +}; +#endif /* WL_SEAT_CAPABILITY_ENUM */ + +#ifndef WL_SEAT_ERROR_ENUM +#define WL_SEAT_ERROR_ENUM +/** + * @ingroup iface_wl_seat + * wl_seat error values + * + * These errors can be emitted in response to wl_seat requests. + */ +enum wl_seat_error { + /** + * get_pointer, get_keyboard or get_touch called on seat without the matching capability + */ + WL_SEAT_ERROR_MISSING_CAPABILITY = 0, +}; +#endif /* WL_SEAT_ERROR_ENUM */ + +/** + * @ingroup iface_wl_seat + * @struct wl_seat_listener + */ +struct wl_seat_listener { + /** + * seat capabilities changed + * + * This is emitted whenever a seat gains or loses the pointer, + * keyboard or touch capabilities. The argument is a capability + * enum containing the complete set of capabilities this seat has. + * + * When the pointer capability is added, a client may create a + * wl_pointer object using the wl_seat.get_pointer request. This + * object will receive pointer events until the capability is + * removed in the future. + * + * When the pointer capability is removed, a client should destroy + * the wl_pointer objects associated with the seat where the + * capability was removed, using the wl_pointer.release request. No + * further pointer events will be received on these objects. + * + * In some compositors, if a seat regains the pointer capability + * and a client has a previously obtained wl_pointer object of + * version 4 or less, that object may start sending pointer events + * again. This behavior is considered a misinterpretation of the + * intended behavior and must not be relied upon by the client. + * wl_pointer objects of version 5 or later must not send events if + * created before the most recent event notifying the client of an + * added pointer capability. + * + * The above behavior also applies to wl_keyboard and wl_touch with + * the keyboard and touch capabilities, respectively. + * @param capabilities capabilities of the seat + */ + void (*capabilities)(void *data, + struct wl_seat *wl_seat, + uint32_t capabilities); + /** + * unique identifier for this seat + * + * In a multi-seat configuration the seat name can be used by + * clients to help identify which physical devices the seat + * represents. + * + * The seat name is a UTF-8 string with no convention defined for + * its contents. Each name is unique among all wl_seat globals. The + * name is only guaranteed to be unique for the current compositor + * instance. + * + * The same seat names are used for all clients. Thus, the name can + * be shared across processes to refer to a specific wl_seat + * global. + * + * The name event is sent after binding to the seat global. This + * event is only sent once per seat object, and the name does not + * change over the lifetime of the wl_seat global. + * + * Compositors may re-use the same seat name if the wl_seat global + * is destroyed and re-created later. + * @param name seat identifier + * @since 2 + */ + void (*name)(void *data, + struct wl_seat *wl_seat, + const char *name); +}; + +/** + * @ingroup iface_wl_seat + */ +static inline int +wl_seat_add_listener(struct wl_seat *wl_seat, + const struct wl_seat_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_seat, + (void (**)(void)) listener, data); +} + +#define WL_SEAT_GET_POINTER 0 +#define WL_SEAT_GET_KEYBOARD 1 +#define WL_SEAT_GET_TOUCH 2 +#define WL_SEAT_RELEASE 3 + +/** + * @ingroup iface_wl_seat + */ +#define WL_SEAT_CAPABILITIES_SINCE_VERSION 1 +/** + * @ingroup iface_wl_seat + */ +#define WL_SEAT_NAME_SINCE_VERSION 2 + +/** + * @ingroup iface_wl_seat + */ +#define WL_SEAT_GET_POINTER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_seat + */ +#define WL_SEAT_GET_KEYBOARD_SINCE_VERSION 1 +/** + * @ingroup iface_wl_seat + */ +#define WL_SEAT_GET_TOUCH_SINCE_VERSION 1 +/** + * @ingroup iface_wl_seat + */ +#define WL_SEAT_RELEASE_SINCE_VERSION 5 + +/** @ingroup iface_wl_seat */ +static inline void +wl_seat_set_user_data(struct wl_seat *wl_seat, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_seat, user_data); +} + +/** @ingroup iface_wl_seat */ +static inline void * +wl_seat_get_user_data(struct wl_seat *wl_seat) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_seat); +} + +static inline uint32_t +wl_seat_get_version(struct wl_seat *wl_seat) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_seat); +} + +/** @ingroup iface_wl_seat */ +static inline void +wl_seat_destroy(struct wl_seat *wl_seat) +{ + wl_proxy_destroy((struct wl_proxy *) wl_seat); +} + +/** + * @ingroup iface_wl_seat + * + * The ID provided will be initialized to the wl_pointer interface + * for this seat. + * + * This request only takes effect if the seat has the pointer + * capability, or has had the pointer capability in the past. + * It is a protocol violation to issue this request on a seat that has + * never had the pointer capability. The missing_capability error will + * be sent in this case. + */ +static inline struct wl_pointer * +wl_seat_get_pointer(struct wl_seat *wl_seat) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, + WL_SEAT_GET_POINTER, &wl_pointer_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL); + + return (struct wl_pointer *) id; +} + +/** + * @ingroup iface_wl_seat + * + * The ID provided will be initialized to the wl_keyboard interface + * for this seat. + * + * This request only takes effect if the seat has the keyboard + * capability, or has had the keyboard capability in the past. + * It is a protocol violation to issue this request on a seat that has + * never had the keyboard capability. The missing_capability error will + * be sent in this case. + */ +static inline struct wl_keyboard * +wl_seat_get_keyboard(struct wl_seat *wl_seat) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, + WL_SEAT_GET_KEYBOARD, &wl_keyboard_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL); + + return (struct wl_keyboard *) id; +} + +/** + * @ingroup iface_wl_seat + * + * The ID provided will be initialized to the wl_touch interface + * for this seat. + * + * This request only takes effect if the seat has the touch + * capability, or has had the touch capability in the past. + * It is a protocol violation to issue this request on a seat that has + * never had the touch capability. The missing_capability error will + * be sent in this case. + */ +static inline struct wl_touch * +wl_seat_get_touch(struct wl_seat *wl_seat) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, + WL_SEAT_GET_TOUCH, &wl_touch_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL); + + return (struct wl_touch *) id; +} + +/** + * @ingroup iface_wl_seat + * + * Using this request a client can tell the server that it is not going to + * use the seat object anymore. + */ +static inline void +wl_seat_release(struct wl_seat *wl_seat) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, + WL_SEAT_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_seat), WL_MARSHAL_FLAG_DESTROY); +} + +#ifndef WL_POINTER_ERROR_ENUM +#define WL_POINTER_ERROR_ENUM +enum wl_pointer_error { + /** + * given wl_surface has another role + */ + WL_POINTER_ERROR_ROLE = 0, +}; +#endif /* WL_POINTER_ERROR_ENUM */ + +#ifndef WL_POINTER_BUTTON_STATE_ENUM +#define WL_POINTER_BUTTON_STATE_ENUM +/** + * @ingroup iface_wl_pointer + * physical button state + * + * Describes the physical state of a button that produced the button + * event. + */ +enum wl_pointer_button_state { + /** + * the button is not pressed + */ + WL_POINTER_BUTTON_STATE_RELEASED = 0, + /** + * the button is pressed + */ + WL_POINTER_BUTTON_STATE_PRESSED = 1, +}; +#endif /* WL_POINTER_BUTTON_STATE_ENUM */ + +#ifndef WL_POINTER_AXIS_ENUM +#define WL_POINTER_AXIS_ENUM +/** + * @ingroup iface_wl_pointer + * axis types + * + * Describes the axis types of scroll events. + */ +enum wl_pointer_axis { + /** + * vertical axis + */ + WL_POINTER_AXIS_VERTICAL_SCROLL = 0, + /** + * horizontal axis + */ + WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1, +}; +#endif /* WL_POINTER_AXIS_ENUM */ + +#ifndef WL_POINTER_AXIS_SOURCE_ENUM +#define WL_POINTER_AXIS_SOURCE_ENUM +/** + * @ingroup iface_wl_pointer + * axis source types + * + * Describes the source types for axis events. This indicates to the + * client how an axis event was physically generated; a client may + * adjust the user interface accordingly. For example, scroll events + * from a "finger" source may be in a smooth coordinate space with + * kinetic scrolling whereas a "wheel" source may be in discrete steps + * of a number of lines. + * + * The "continuous" axis source is a device generating events in a + * continuous coordinate space, but using something other than a + * finger. One example for this source is button-based scrolling where + * the vertical motion of a device is converted to scroll events while + * a button is held down. + * + * The "wheel tilt" axis source indicates that the actual device is a + * wheel but the scroll event is not caused by a rotation but a + * (usually sideways) tilt of the wheel. + */ +enum wl_pointer_axis_source { + /** + * a physical wheel rotation + */ + WL_POINTER_AXIS_SOURCE_WHEEL = 0, + /** + * finger on a touch surface + */ + WL_POINTER_AXIS_SOURCE_FINGER = 1, + /** + * continuous coordinate space + */ + WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2, + /** + * a physical wheel tilt + * @since 6 + */ + WL_POINTER_AXIS_SOURCE_WHEEL_TILT = 3, +}; +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION 6 +#endif /* WL_POINTER_AXIS_SOURCE_ENUM */ + +/** + * @ingroup iface_wl_pointer + * @struct wl_pointer_listener + */ +struct wl_pointer_listener { + /** + * enter event + * + * Notification that this seat's pointer is focused on a certain + * surface. + * + * When a seat's focus enters a surface, the pointer image is + * undefined and a client should respond to this event by setting + * an appropriate pointer image with the set_cursor request. + * @param serial serial number of the enter event + * @param surface surface entered by the pointer + * @param surface_x surface-local x coordinate + * @param surface_y surface-local y coordinate + */ + void (*enter)(void *data, + struct wl_pointer *wl_pointer, + uint32_t serial, + struct wl_surface *surface, + wl_fixed_t surface_x, + wl_fixed_t surface_y); + /** + * leave event + * + * Notification that this seat's pointer is no longer focused on + * a certain surface. + * + * The leave notification is sent before the enter notification for + * the new focus. + * @param serial serial number of the leave event + * @param surface surface left by the pointer + */ + void (*leave)(void *data, + struct wl_pointer *wl_pointer, + uint32_t serial, + struct wl_surface *surface); + /** + * pointer motion event + * + * Notification of pointer location change. The arguments + * surface_x and surface_y are the location relative to the focused + * surface. + * @param time timestamp with millisecond granularity + * @param surface_x surface-local x coordinate + * @param surface_y surface-local y coordinate + */ + void (*motion)(void *data, + struct wl_pointer *wl_pointer, + uint32_t time, + wl_fixed_t surface_x, + wl_fixed_t surface_y); + /** + * pointer button event + * + * Mouse button click and release notifications. + * + * The location of the click is given by the last motion or enter + * event. The time argument is a timestamp with millisecond + * granularity, with an undefined base. + * + * The button is a button code as defined in the Linux kernel's + * linux/input-event-codes.h header file, e.g. BTN_LEFT. + * + * Any 16-bit button code value is reserved for future additions to + * the kernel's event code list. All other button codes above + * 0xFFFF are currently undefined but may be used in future + * versions of this protocol. + * @param serial serial number of the button event + * @param time timestamp with millisecond granularity + * @param button button that produced the event + * @param state physical state of the button + */ + void (*button)(void *data, + struct wl_pointer *wl_pointer, + uint32_t serial, + uint32_t time, + uint32_t button, + uint32_t state); + /** + * axis event + * + * Scroll and other axis notifications. + * + * For scroll events (vertical and horizontal scroll axes), the + * value parameter is the length of a vector along the specified + * axis in a coordinate space identical to those of motion events, + * representing a relative movement along the specified axis. + * + * For devices that support movements non-parallel to axes multiple + * axis events will be emitted. + * + * When applicable, for example for touch pads, the server can + * choose to emit scroll events where the motion vector is + * equivalent to a motion event vector. + * + * When applicable, a client can transform its content relative to + * the scroll distance. + * @param time timestamp with millisecond granularity + * @param axis axis type + * @param value length of vector in surface-local coordinate space + */ + void (*axis)(void *data, + struct wl_pointer *wl_pointer, + uint32_t time, + uint32_t axis, + wl_fixed_t value); + /** + * end of a pointer event sequence + * + * Indicates the end of a set of events that logically belong + * together. A client is expected to accumulate the data in all + * events within the frame before proceeding. + * + * All wl_pointer events before a wl_pointer.frame event belong + * logically together. For example, in a diagonal scroll motion the + * compositor will send an optional wl_pointer.axis_source event, + * two wl_pointer.axis events (horizontal and vertical) and finally + * a wl_pointer.frame event. The client may use this information to + * calculate a diagonal vector for scrolling. + * + * When multiple wl_pointer.axis events occur within the same + * frame, the motion vector is the combined motion of all events. + * When a wl_pointer.axis and a wl_pointer.axis_stop event occur + * within the same frame, this indicates that axis movement in one + * axis has stopped but continues in the other axis. When multiple + * wl_pointer.axis_stop events occur within the same frame, this + * indicates that these axes stopped in the same instance. + * + * A wl_pointer.frame event is sent for every logical event group, + * even if the group only contains a single wl_pointer event. + * Specifically, a client may get a sequence: motion, frame, + * button, frame, axis, frame, axis_stop, frame. + * + * The wl_pointer.enter and wl_pointer.leave events are logical + * events generated by the compositor and not the hardware. These + * events are also grouped by a wl_pointer.frame. When a pointer + * moves from one surface to another, a compositor should group the + * wl_pointer.leave event within the same wl_pointer.frame. + * However, a client must not rely on wl_pointer.leave and + * wl_pointer.enter being in the same wl_pointer.frame. + * Compositor-specific policies may require the wl_pointer.leave + * and wl_pointer.enter event being split across multiple + * wl_pointer.frame groups. + * @since 5 + */ + void (*frame)(void *data, + struct wl_pointer *wl_pointer); + /** + * axis source event + * + * Source information for scroll and other axes. + * + * This event does not occur on its own. It is sent before a + * wl_pointer.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 wl_pointer.axis_source.finger, a wl_pointer.axis_stop event + * will be sent when the user lifts the finger off the device. + * + * If the source is wl_pointer.axis_source.wheel, + * wl_pointer.axis_source.wheel_tilt or + * wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event + * may or may not be sent. Whether a compositor sends an axis_stop + * event for these sources is hardware-specific and + * implementation-dependent; clients must not rely on receiving an + * axis_stop event for these scroll sources and should treat scroll + * sequences from these scroll sources as unterminated by default. + * + * This event is optional. If the source is unknown for a + * particular axis event sequence, no event is sent. Only one + * wl_pointer.axis_source event is permitted per frame. + * + * The order of wl_pointer.axis_discrete and wl_pointer.axis_source + * is not guaranteed. + * @param axis_source source of the axis event + * @since 5 + */ + void (*axis_source)(void *data, + struct wl_pointer *wl_pointer, + uint32_t axis_source); + /** + * axis stop event + * + * Stop notification for scroll and other axes. + * + * For some wl_pointer.axis_source types, a wl_pointer.axis_stop + * event is sent to notify a client that the axis sequence has + * terminated. This enables the client to implement kinetic + * scrolling. See the wl_pointer.axis_source documentation for + * information on when this event may be generated. + * + * Any wl_pointer.axis events with the same axis_source after this + * event should be considered as the start of a new axis motion. + * + * The timestamp is to be interpreted identical to the timestamp in + * the wl_pointer.axis event. The timestamp value may be the same + * as a preceding wl_pointer.axis event. + * @param time timestamp with millisecond granularity + * @param axis the axis stopped with this event + * @since 5 + */ + void (*axis_stop)(void *data, + struct wl_pointer *wl_pointer, + uint32_t time, + uint32_t axis); + /** + * axis click event + * + * Discrete step information for scroll and other axes. + * + * This event carries the axis value of the wl_pointer.axis event + * in discrete steps (e.g. mouse wheel clicks). + * + * This event is deprecated with wl_pointer version 8 - this event + * is not sent to clients supporting version 8 or later. + * + * This event does not occur on its own, it is coupled with a + * wl_pointer.axis event that represents this axis value on a + * continuous scale. The protocol guarantees that each + * axis_discrete event is always followed by exactly one axis event + * with the same axis number within the same wl_pointer.frame. Note + * that the protocol allows for other events to occur between the + * axis_discrete and its coupled axis event, including other + * axis_discrete or axis events. A wl_pointer.frame must not + * contain more than one axis_discrete event per axis type. + * + * This event is optional; continuous scrolling devices like + * two-finger scrolling on touchpads do not have discrete steps and + * do not generate this event. + * + * The discrete value carries the directional information. e.g. a + * value of -2 is two steps towards the negative direction of this + * axis. + * + * The axis number is identical to the axis number in the + * associated axis event. + * + * The order of wl_pointer.axis_discrete and wl_pointer.axis_source + * is not guaranteed. + * @param axis axis type + * @param discrete number of steps + * @since 5 + */ + void (*axis_discrete)(void *data, + struct wl_pointer *wl_pointer, + uint32_t axis, + int32_t discrete); + /** + * axis high-resolution scroll event + * + * Discrete high-resolution scroll information. + * + * This event carries high-resolution wheel scroll information, + * with each multiple of 120 representing one logical scroll step + * (a wheel detent). For example, an axis_value120 of 30 is one + * quarter of a logical scroll step in the positive direction, a + * value120 of -240 are two logical scroll steps in the negative + * direction within the same hardware event. Clients that rely on + * discrete scrolling should accumulate the value120 to multiples + * of 120 before processing the event. + * + * The value120 must not be zero. + * + * This event replaces the wl_pointer.axis_discrete event in + * clients supporting wl_pointer version 8 or later. + * + * Where a wl_pointer.axis_source event occurs in the same + * wl_pointer.frame, the axis source applies to this event. + * + * The order of wl_pointer.axis_value120 and wl_pointer.axis_source + * is not guaranteed. + * @param axis axis type + * @param value120 scroll distance as fraction of 120 + * @since 8 + */ + void (*axis_value120)(void *data, + struct wl_pointer *wl_pointer, + uint32_t axis, + int32_t value120); +}; + +/** + * @ingroup iface_wl_pointer + */ +static inline int +wl_pointer_add_listener(struct wl_pointer *wl_pointer, + const struct wl_pointer_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_pointer, + (void (**)(void)) listener, data); +} + +#define WL_POINTER_SET_CURSOR 0 +#define WL_POINTER_RELEASE 1 + +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_ENTER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_LEAVE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_MOTION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_BUTTON_SINCE_VERSION 1 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_AXIS_SINCE_VERSION 1 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_FRAME_SINCE_VERSION 5 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_AXIS_SOURCE_SINCE_VERSION 5 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_AXIS_STOP_SINCE_VERSION 5 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_AXIS_DISCRETE_SINCE_VERSION 5 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_AXIS_VALUE120_SINCE_VERSION 8 + +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_SET_CURSOR_SINCE_VERSION 1 +/** + * @ingroup iface_wl_pointer + */ +#define WL_POINTER_RELEASE_SINCE_VERSION 3 + +/** @ingroup iface_wl_pointer */ +static inline void +wl_pointer_set_user_data(struct wl_pointer *wl_pointer, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_pointer, user_data); +} + +/** @ingroup iface_wl_pointer */ +static inline void * +wl_pointer_get_user_data(struct wl_pointer *wl_pointer) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_pointer); +} + +static inline uint32_t +wl_pointer_get_version(struct wl_pointer *wl_pointer) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_pointer); +} + +/** @ingroup iface_wl_pointer */ +static inline void +wl_pointer_destroy(struct wl_pointer *wl_pointer) +{ + wl_proxy_destroy((struct wl_proxy *) wl_pointer); +} + +/** + * @ingroup iface_wl_pointer + * + * Set the pointer surface, i.e., the surface that contains the + * pointer image (cursor). This request gives the surface the role + * of a cursor. If the surface already has another role, it raises + * a protocol error. + * + * The cursor actually changes only if the pointer + * focus for this device is 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 pointer 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. + * + * The serial parameter must match the latest wl_pointer.enter + * serial number sent to the client. Otherwise the request will be + * ignored. + */ +static inline void +wl_pointer_set_cursor(struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, int32_t hotspot_x, int32_t hotspot_y) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_pointer, + WL_POINTER_SET_CURSOR, NULL, wl_proxy_get_version((struct wl_proxy *) wl_pointer), 0, serial, surface, hotspot_x, hotspot_y); +} + +/** + * @ingroup iface_wl_pointer + * + * Using this request a client can tell the server that it is not going to + * use the pointer object anymore. + * + * This request destroys the pointer proxy object, so clients must not call + * wl_pointer_destroy() after using this request. + */ +static inline void +wl_pointer_release(struct wl_pointer *wl_pointer) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_pointer, + WL_POINTER_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_pointer), WL_MARSHAL_FLAG_DESTROY); +} + +#ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM +#define WL_KEYBOARD_KEYMAP_FORMAT_ENUM +/** + * @ingroup iface_wl_keyboard + * keyboard mapping format + * + * This specifies the format of the keymap provided to the + * client with the wl_keyboard.keymap event. + */ +enum wl_keyboard_keymap_format { + /** + * no keymap; client must understand how to interpret the raw keycode + */ + WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0, + /** + * libxkbcommon compatible, null-terminated string; to determine the xkb keycode, clients must add 8 to the key event keycode + */ + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1, +}; +#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */ + +#ifndef WL_KEYBOARD_KEY_STATE_ENUM +#define WL_KEYBOARD_KEY_STATE_ENUM +/** + * @ingroup iface_wl_keyboard + * physical key state + * + * Describes the physical state of a key that produced the key event. + */ +enum wl_keyboard_key_state { + /** + * key is not pressed + */ + WL_KEYBOARD_KEY_STATE_RELEASED = 0, + /** + * key is pressed + */ + WL_KEYBOARD_KEY_STATE_PRESSED = 1, +}; +#endif /* WL_KEYBOARD_KEY_STATE_ENUM */ + +/** + * @ingroup iface_wl_keyboard + * @struct wl_keyboard_listener + */ +struct wl_keyboard_listener { + /** + * keyboard mapping + * + * This event provides a file descriptor to the client which can + * be memory-mapped in read-only mode to provide a keyboard mapping + * description. + * + * From version 7 onwards, the fd must be mapped with MAP_PRIVATE + * by the recipient, as MAP_SHARED may fail. + * @param format keymap format + * @param fd keymap file descriptor + * @param size keymap size, in bytes + */ + void (*keymap)(void *data, + struct wl_keyboard *wl_keyboard, + uint32_t format, + int32_t fd, + uint32_t size); + /** + * enter event + * + * Notification that this seat's keyboard focus is on a certain + * surface. + * + * The compositor must send the wl_keyboard.modifiers event after + * this event. + * @param serial serial number of the enter event + * @param surface surface gaining keyboard focus + * @param keys the currently pressed keys + */ + void (*enter)(void *data, + struct wl_keyboard *wl_keyboard, + uint32_t serial, + struct wl_surface *surface, + struct wl_array *keys); + /** + * leave event + * + * Notification that this seat's keyboard focus is no longer on a + * certain surface. + * + * The leave notification is sent before the enter notification for + * the new focus. + * + * After this event client must assume that all keys, including + * modifiers, are lifted and also it must stop key repeating if + * there's some going on. + * @param serial serial number of the leave event + * @param surface surface that lost keyboard focus + */ + void (*leave)(void *data, + struct wl_keyboard *wl_keyboard, + uint32_t serial, + struct wl_surface *surface); + /** + * key event + * + * A key was pressed or released. The time argument is a + * timestamp with millisecond granularity, with an undefined base. + * + * The key is a platform-specific key code that can be interpreted + * by feeding it to the keyboard mapping (see the keymap event). + * + * If this event produces a change in modifiers, then the resulting + * wl_keyboard.modifiers event must be sent after this event. + * @param serial serial number of the key event + * @param time timestamp with millisecond granularity + * @param key key that produced the event + * @param state physical state of the key + */ + void (*key)(void *data, + struct wl_keyboard *wl_keyboard, + uint32_t serial, + uint32_t time, + uint32_t key, + uint32_t state); + /** + * modifier and group state + * + * Notifies clients that the modifier and/or group state has + * changed, and it should update its local state. + * @param serial serial number of the modifiers event + * @param mods_depressed depressed modifiers + * @param mods_latched latched modifiers + * @param mods_locked locked modifiers + * @param group keyboard layout + */ + void (*modifiers)(void *data, + struct wl_keyboard *wl_keyboard, + uint32_t serial, + uint32_t mods_depressed, + uint32_t mods_latched, + uint32_t mods_locked, + uint32_t group); + /** + * repeat rate and delay + * + * Informs the client about the keyboard's repeat rate and delay. + * + * This event is sent as soon as the wl_keyboard object has been + * created, and is guaranteed to be received by the client before + * any key press event. + * + * Negative values for either rate or delay are illegal. A rate of + * zero will disable any repeating (regardless of the value of + * delay). + * + * This event can be sent later on as well with a new value if + * necessary, so clients should continue listening for the event + * past the creation of wl_keyboard. + * @param rate the rate of repeating keys in characters per second + * @param delay delay in milliseconds since key down until repeating starts + * @since 4 + */ + void (*repeat_info)(void *data, + struct wl_keyboard *wl_keyboard, + int32_t rate, + int32_t delay); +}; + +/** + * @ingroup iface_wl_keyboard + */ +static inline int +wl_keyboard_add_listener(struct wl_keyboard *wl_keyboard, + const struct wl_keyboard_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_keyboard, + (void (**)(void)) listener, data); +} + +#define WL_KEYBOARD_RELEASE 0 + +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_KEYMAP_SINCE_VERSION 1 +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_ENTER_SINCE_VERSION 1 +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_LEAVE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_KEY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_MODIFIERS_SINCE_VERSION 1 +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION 4 + +/** + * @ingroup iface_wl_keyboard + */ +#define WL_KEYBOARD_RELEASE_SINCE_VERSION 3 + +/** @ingroup iface_wl_keyboard */ +static inline void +wl_keyboard_set_user_data(struct wl_keyboard *wl_keyboard, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_keyboard, user_data); +} + +/** @ingroup iface_wl_keyboard */ +static inline void * +wl_keyboard_get_user_data(struct wl_keyboard *wl_keyboard) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_keyboard); +} + +static inline uint32_t +wl_keyboard_get_version(struct wl_keyboard *wl_keyboard) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_keyboard); +} + +/** @ingroup iface_wl_keyboard */ +static inline void +wl_keyboard_destroy(struct wl_keyboard *wl_keyboard) +{ + wl_proxy_destroy((struct wl_proxy *) wl_keyboard); +} + +/** + * @ingroup iface_wl_keyboard + */ +static inline void +wl_keyboard_release(struct wl_keyboard *wl_keyboard) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_keyboard, + WL_KEYBOARD_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_keyboard), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wl_touch + * @struct wl_touch_listener + */ +struct wl_touch_listener { + /** + * touch down event and beginning of a touch sequence + * + * A new touch point has appeared on the surface. This touch + * point is assigned a unique ID. Future events from this touch + * point reference this ID. The ID ceases to be valid after a touch + * up event and may be reused in the future. + * @param serial serial number of the touch down event + * @param time timestamp with millisecond granularity + * @param surface surface touched + * @param id the unique ID of this touch point + * @param x surface-local x coordinate + * @param y surface-local y coordinate + */ + void (*down)(void *data, + struct wl_touch *wl_touch, + uint32_t serial, + uint32_t time, + struct wl_surface *surface, + int32_t id, + wl_fixed_t x, + wl_fixed_t y); + /** + * end of a touch event sequence + * + * The touch point has disappeared. No further events will be + * sent for this touch point and the touch point's ID is released + * and may be reused in a future touch down event. + * @param serial serial number of the touch up event + * @param time timestamp with millisecond granularity + * @param id the unique ID of this touch point + */ + void (*up)(void *data, + struct wl_touch *wl_touch, + uint32_t serial, + uint32_t time, + int32_t id); + /** + * update of touch point coordinates + * + * A touch point has changed coordinates. + * @param time timestamp with millisecond granularity + * @param id the unique ID of this touch point + * @param x surface-local x coordinate + * @param y surface-local y coordinate + */ + void (*motion)(void *data, + struct wl_touch *wl_touch, + uint32_t time, + int32_t id, + wl_fixed_t x, + wl_fixed_t y); + /** + * end of touch frame event + * + * Indicates the end of a set of events that logically belong + * together. A client is expected to accumulate the data in all + * events within the frame before proceeding. + * + * A wl_touch.frame terminates at least one event but otherwise no + * guarantee is provided about the set of events within a frame. A + * client must assume that any state not updated in a frame is + * unchanged from the previously known state. + */ + void (*frame)(void *data, + struct wl_touch *wl_touch); + /** + * touch session cancelled + * + * Sent if the compositor decides the touch stream is a global + * gesture. No further events are sent to the clients from that + * particular gesture. Touch cancellation applies to all touch + * points currently active on this client's surface. The client is + * responsible for finalizing the touch points, future touch points + * on this surface may reuse the touch point ID. + */ + void (*cancel)(void *data, + struct wl_touch *wl_touch); + /** + * update shape of touch point + * + * Sent when a touchpoint has changed its shape. + * + * This event does not occur on its own. It is sent before a + * wl_touch.frame event and carries the new shape information for + * any previously reported, or new touch points of that frame. + * + * Other events describing the touch point such as wl_touch.down, + * wl_touch.motion or wl_touch.orientation may be sent within the + * same wl_touch.frame. A client should treat these events as a + * single logical touch point update. The order of wl_touch.shape, + * wl_touch.orientation and wl_touch.motion is not guaranteed. A + * wl_touch.down event is guaranteed to occur before the first + * wl_touch.shape event for this touch ID but both events may occur + * within the same wl_touch.frame. + * + * A touchpoint shape is approximated by an ellipse through the + * major and minor axis length. The major axis length describes the + * longer diameter of the ellipse, while the minor axis length + * describes the shorter diameter. Major and minor are orthogonal + * and both are specified in surface-local coordinates. The center + * of the ellipse is always at the touchpoint location as reported + * by wl_touch.down or wl_touch.move. + * + * This event is only sent by the compositor if the touch device + * supports shape reports. The client has to make reasonable + * assumptions about the shape if it did not receive this event. + * @param id the unique ID of this touch point + * @param major length of the major axis in surface-local coordinates + * @param minor length of the minor axis in surface-local coordinates + * @since 6 + */ + void (*shape)(void *data, + struct wl_touch *wl_touch, + int32_t id, + wl_fixed_t major, + wl_fixed_t minor); + /** + * update orientation of touch point + * + * Sent when a touchpoint has changed its orientation. + * + * This event does not occur on its own. It is sent before a + * wl_touch.frame event and carries the new shape information for + * any previously reported, or new touch points of that frame. + * + * Other events describing the touch point such as wl_touch.down, + * wl_touch.motion or wl_touch.shape may be sent within the same + * wl_touch.frame. A client should treat these events as a single + * logical touch point update. The order of wl_touch.shape, + * wl_touch.orientation and wl_touch.motion is not guaranteed. A + * wl_touch.down event is guaranteed to occur before the first + * wl_touch.orientation event for this touch ID but both events may + * occur within the same wl_touch.frame. + * + * The orientation describes the clockwise angle of a touchpoint's + * major axis to the positive surface y-axis and is normalized to + * the -180 to +180 degree range. The granularity of orientation + * depends on the touch device, some devices only support binary + * rotation values between 0 and 90 degrees. + * + * This event is only sent by the compositor if the touch device + * supports orientation reports. + * @param id the unique ID of this touch point + * @param orientation angle between major axis and positive surface y-axis in degrees + * @since 6 + */ + void (*orientation)(void *data, + struct wl_touch *wl_touch, + int32_t id, + wl_fixed_t orientation); +}; + +/** + * @ingroup iface_wl_touch + */ +static inline int +wl_touch_add_listener(struct wl_touch *wl_touch, + const struct wl_touch_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_touch, + (void (**)(void)) listener, data); +} + +#define WL_TOUCH_RELEASE 0 + +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_DOWN_SINCE_VERSION 1 +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_UP_SINCE_VERSION 1 +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_MOTION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_FRAME_SINCE_VERSION 1 +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_CANCEL_SINCE_VERSION 1 +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_SHAPE_SINCE_VERSION 6 +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_ORIENTATION_SINCE_VERSION 6 + +/** + * @ingroup iface_wl_touch + */ +#define WL_TOUCH_RELEASE_SINCE_VERSION 3 + +/** @ingroup iface_wl_touch */ +static inline void +wl_touch_set_user_data(struct wl_touch *wl_touch, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_touch, user_data); +} + +/** @ingroup iface_wl_touch */ +static inline void * +wl_touch_get_user_data(struct wl_touch *wl_touch) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_touch); +} + +static inline uint32_t +wl_touch_get_version(struct wl_touch *wl_touch) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_touch); +} + +/** @ingroup iface_wl_touch */ +static inline void +wl_touch_destroy(struct wl_touch *wl_touch) +{ + wl_proxy_destroy((struct wl_proxy *) wl_touch); +} + +/** + * @ingroup iface_wl_touch + */ +static inline void +wl_touch_release(struct wl_touch *wl_touch) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_touch, + WL_TOUCH_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_touch), WL_MARSHAL_FLAG_DESTROY); +} + +#ifndef WL_OUTPUT_SUBPIXEL_ENUM +#define WL_OUTPUT_SUBPIXEL_ENUM +/** + * @ingroup iface_wl_output + * subpixel geometry information + * + * This enumeration describes how the physical + * pixels on an output are laid out. + */ +enum wl_output_subpixel { + /** + * unknown geometry + */ + WL_OUTPUT_SUBPIXEL_UNKNOWN = 0, + /** + * no geometry + */ + WL_OUTPUT_SUBPIXEL_NONE = 1, + /** + * horizontal RGB + */ + WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2, + /** + * horizontal BGR + */ + WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3, + /** + * vertical RGB + */ + WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4, + /** + * vertical BGR + */ + WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5, +}; +#endif /* WL_OUTPUT_SUBPIXEL_ENUM */ + +#ifndef WL_OUTPUT_TRANSFORM_ENUM +#define WL_OUTPUT_TRANSFORM_ENUM +/** + * @ingroup iface_wl_output + * transform from framebuffer to output + * + * This describes the transform that a compositor will apply to a + * surface to compensate for the rotation or mirroring of an + * output device. + * + * The flipped values correspond to an initial flip around a + * vertical axis followed by rotation. + * + * The purpose is mainly to allow clients to render accordingly and + * tell the compositor, so that for fullscreen surfaces, the + * compositor will still be able to scan out directly from client + * surfaces. + */ +enum wl_output_transform { + /** + * no transform + */ + WL_OUTPUT_TRANSFORM_NORMAL = 0, + /** + * 90 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_90 = 1, + /** + * 180 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_180 = 2, + /** + * 270 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_270 = 3, + /** + * 180 degree flip around a vertical axis + */ + WL_OUTPUT_TRANSFORM_FLIPPED = 4, + /** + * flip and rotate 90 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5, + /** + * flip and rotate 180 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6, + /** + * flip and rotate 270 degrees counter-clockwise + */ + WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7, +}; +#endif /* WL_OUTPUT_TRANSFORM_ENUM */ + +#ifndef WL_OUTPUT_MODE_ENUM +#define WL_OUTPUT_MODE_ENUM +/** + * @ingroup iface_wl_output + * mode information + * + * These flags describe properties of an output mode. + * They are used in the flags bitfield of the mode event. + */ +enum wl_output_mode { + /** + * indicates this is the current mode + */ + WL_OUTPUT_MODE_CURRENT = 0x1, + /** + * indicates this is the preferred mode + */ + WL_OUTPUT_MODE_PREFERRED = 0x2, +}; +#endif /* WL_OUTPUT_MODE_ENUM */ + +/** + * @ingroup iface_wl_output + * @struct wl_output_listener + */ +struct wl_output_listener { + /** + * properties of the output + * + * The geometry event describes geometric properties of the + * output. The event is sent when binding to the output object and + * whenever any of the properties change. + * + * The physical size can be set to zero if it doesn't make sense + * for this output (e.g. for projectors or virtual outputs). + * + * The geometry event will be followed by a done event (starting + * from version 2). + * + * Note: wl_output only advertises partial information about the + * output position and identification. Some compositors, for + * instance those not implementing a desktop-style output layout or + * those exposing virtual outputs, might fake this information. + * Instead of using x and y, clients should use + * xdg_output.logical_position. Instead of using make and model, + * clients should use name and description. + * @param x x position within the global compositor space + * @param y y position within the global compositor space + * @param physical_width width in millimeters of the output + * @param physical_height height in millimeters of the output + * @param subpixel subpixel orientation of the output + * @param make textual description of the manufacturer + * @param model textual description of the model + * @param transform transform that maps framebuffer to output + */ + void (*geometry)(void *data, + struct wl_output *wl_output, + int32_t x, + int32_t y, + int32_t physical_width, + int32_t physical_height, + int32_t subpixel, + const char *make, + const char *model, + int32_t transform); + /** + * advertise available modes for the output + * + * The mode event describes an available mode for the output. + * + * The event is sent when binding to the output object and there + * will always be one mode, the current mode. The event is sent + * again if an output changes mode, for the mode that is now + * current. In other words, the current mode is always the last + * mode that was received with the current flag set. + * + * Non-current modes are deprecated. A compositor can decide to + * only advertise the current mode and never send other modes. + * Clients should not rely on non-current modes. + * + * The size of a mode is given in physical hardware units of the + * output device. This is not necessarily the same as the output + * size in the global compositor space. For instance, the output + * may be scaled, as described in wl_output.scale, or transformed, + * as described in wl_output.transform. Clients willing to retrieve + * the output size in the global compositor space should use + * xdg_output.logical_size instead. + * + * The vertical refresh rate can be set to zero if it doesn't make + * sense for this output (e.g. for virtual outputs). + * + * The mode event will be followed by a done event (starting from + * version 2). + * + * Clients should not use the refresh rate to schedule frames. + * Instead, they should use the wl_surface.frame event or the + * presentation-time protocol. + * + * Note: this information is not always meaningful for all outputs. + * Some compositors, such as those exposing virtual outputs, might + * fake the refresh rate or the size. + * @param flags bitfield of mode flags + * @param width width of the mode in hardware units + * @param height height of the mode in hardware units + * @param refresh vertical refresh rate in mHz + */ + void (*mode)(void *data, + struct wl_output *wl_output, + uint32_t flags, + int32_t width, + int32_t height, + int32_t refresh); + /** + * sent all information about output + * + * This event is sent after all other properties have been sent + * after binding to the output object and after any other property + * changes done after that. This allows changes to the output + * properties to be seen as atomic, even if they happen via + * multiple events. + * @since 2 + */ + void (*done)(void *data, + struct wl_output *wl_output); + /** + * output scaling properties + * + * This event contains scaling geometry information that is not + * in the geometry event. It may be sent after binding the output + * object or if the output scale changes later. If it is not sent, + * the client should assume a scale of 1. + * + * A scale larger than 1 means that the compositor will + * automatically scale surface buffers by this amount when + * rendering. This is used for very high resolution displays where + * applications rendering at the native resolution would be too + * small to be legible. + * + * It is intended that scaling aware clients track the current + * output of a surface, and if it is on a scaled output it should + * use wl_surface.set_buffer_scale with the scale of the output. + * That way the compositor can avoid scaling the surface, and the + * client can supply a higher detail image. + * + * The scale event will be followed by a done event. + * @param factor scaling factor of output + * @since 2 + */ + void (*scale)(void *data, + struct wl_output *wl_output, + int32_t factor); + /** + * name of this output + * + * Many compositors will assign user-friendly names to their + * outputs, show them to the user, allow the user to refer to an + * output, etc. The client may wish to know this name as well to + * offer the user similar behaviors. + * + * The name is a UTF-8 string with no convention defined for its + * contents. Each name is unique among all wl_output globals. The + * name is only guaranteed to be unique for the compositor + * instance. + * + * The same output name is used for all clients for a given + * wl_output global. Thus, the name can be shared across processes + * to refer to a specific wl_output global. + * + * The name is not guaranteed to be persistent across sessions, + * thus cannot be used to reliably identify an output in e.g. + * configuration files. + * + * Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. + * However, do not assume that the name is a reflection of an + * underlying DRM connector, X11 connection, etc. + * + * The name event is sent after binding the output object. This + * event is only sent once per output object, and the name does not + * change over the lifetime of the wl_output global. + * + * Compositors may re-use the same output name if the wl_output + * global is destroyed and re-created later. Compositors should + * avoid re-using the same name if possible. + * + * The name event will be followed by a done event. + * @param name output name + * @since 4 + */ + void (*name)(void *data, + struct wl_output *wl_output, + const char *name); + /** + * human-readable description of this output + * + * Many compositors can produce human-readable descriptions of + * their outputs. The client may wish to know this description as + * well, e.g. for output selection purposes. + * + * The description is a UTF-8 string with no convention defined for + * its contents. The description is not guaranteed to be unique + * among all wl_output globals. Examples might include 'Foocorp 11" + * Display' or 'Virtual X11 output via :1'. + * + * The description event is sent after binding the output object + * and whenever the description changes. The description is + * optional, and may not be sent at all. + * + * The description event will be followed by a done event. + * @param description output description + * @since 4 + */ + void (*description)(void *data, + struct wl_output *wl_output, + const char *description); +}; + +/** + * @ingroup iface_wl_output + */ +static inline int +wl_output_add_listener(struct wl_output *wl_output, + const struct wl_output_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_output, + (void (**)(void)) listener, data); +} + +#define WL_OUTPUT_RELEASE 0 + +/** + * @ingroup iface_wl_output + */ +#define WL_OUTPUT_GEOMETRY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_output + */ +#define WL_OUTPUT_MODE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_output + */ +#define WL_OUTPUT_DONE_SINCE_VERSION 2 +/** + * @ingroup iface_wl_output + */ +#define WL_OUTPUT_SCALE_SINCE_VERSION 2 +/** + * @ingroup iface_wl_output + */ +#define WL_OUTPUT_NAME_SINCE_VERSION 4 +/** + * @ingroup iface_wl_output + */ +#define WL_OUTPUT_DESCRIPTION_SINCE_VERSION 4 + +/** + * @ingroup iface_wl_output + */ +#define WL_OUTPUT_RELEASE_SINCE_VERSION 3 + +/** @ingroup iface_wl_output */ +static inline void +wl_output_set_user_data(struct wl_output *wl_output, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_output, user_data); +} + +/** @ingroup iface_wl_output */ +static inline void * +wl_output_get_user_data(struct wl_output *wl_output) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_output); +} + +static inline uint32_t +wl_output_get_version(struct wl_output *wl_output) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_output); +} + +/** @ingroup iface_wl_output */ +static inline void +wl_output_destroy(struct wl_output *wl_output) +{ + wl_proxy_destroy((struct wl_proxy *) wl_output); +} + +/** + * @ingroup iface_wl_output + * + * Using this request a client can tell the server that it is not going to + * use the output object anymore. + */ +static inline void +wl_output_release(struct wl_output *wl_output) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_output, + WL_OUTPUT_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_output), WL_MARSHAL_FLAG_DESTROY); +} + +#define WL_REGION_DESTROY 0 +#define WL_REGION_ADD 1 +#define WL_REGION_SUBTRACT 2 + + +/** + * @ingroup iface_wl_region + */ +#define WL_REGION_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_region + */ +#define WL_REGION_ADD_SINCE_VERSION 1 +/** + * @ingroup iface_wl_region + */ +#define WL_REGION_SUBTRACT_SINCE_VERSION 1 + +/** @ingroup iface_wl_region */ +static inline void +wl_region_set_user_data(struct wl_region *wl_region, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_region, user_data); +} + +/** @ingroup iface_wl_region */ +static inline void * +wl_region_get_user_data(struct wl_region *wl_region) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_region); +} + +static inline uint32_t +wl_region_get_version(struct wl_region *wl_region) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_region); +} + +/** + * @ingroup iface_wl_region + * + * Destroy the region. This will invalidate the object ID. + */ +static inline void +wl_region_destroy(struct wl_region *wl_region) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_region, + WL_REGION_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wl_region + * + * Add the specified rectangle to the region. + */ +static inline void +wl_region_add(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_region, + WL_REGION_ADD, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), 0, x, y, width, height); +} + +/** + * @ingroup iface_wl_region + * + * Subtract the specified rectangle from the region. + */ +static inline void +wl_region_subtract(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_region, + WL_REGION_SUBTRACT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), 0, x, y, width, height); +} + +#ifndef WL_SUBCOMPOSITOR_ERROR_ENUM +#define WL_SUBCOMPOSITOR_ERROR_ENUM +enum wl_subcompositor_error { + /** + * the to-be sub-surface is invalid + */ + WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0, +}; +#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */ + +#define WL_SUBCOMPOSITOR_DESTROY 0 +#define WL_SUBCOMPOSITOR_GET_SUBSURFACE 1 + + +/** + * @ingroup iface_wl_subcompositor + */ +#define WL_SUBCOMPOSITOR_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_subcompositor + */ +#define WL_SUBCOMPOSITOR_GET_SUBSURFACE_SINCE_VERSION 1 + +/** @ingroup iface_wl_subcompositor */ +static inline void +wl_subcompositor_set_user_data(struct wl_subcompositor *wl_subcompositor, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_subcompositor, user_data); +} + +/** @ingroup iface_wl_subcompositor */ +static inline void * +wl_subcompositor_get_user_data(struct wl_subcompositor *wl_subcompositor) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_subcompositor); +} + +static inline uint32_t +wl_subcompositor_get_version(struct wl_subcompositor *wl_subcompositor) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_subcompositor); +} + +/** + * @ingroup iface_wl_subcompositor + * + * Informs the server that the client will not be using this + * protocol object anymore. This does not affect any other + * objects, wl_subsurface objects included. + */ +static inline void +wl_subcompositor_destroy(struct wl_subcompositor *wl_subcompositor) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_subcompositor, + WL_SUBCOMPOSITOR_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subcompositor), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wl_subcompositor + * + * Create a sub-surface interface for the given surface, and + * associate it with the given parent surface. This turns a + * plain wl_surface into a sub-surface. + * + * The to-be sub-surface must not already have another role, and it + * must not have an existing wl_subsurface object. Otherwise a protocol + * error is raised. + * + * Adding sub-surfaces to a parent is a double-buffered operation on the + * parent (see wl_surface.commit). The effect of adding a sub-surface + * becomes visible on the next time the state of the parent surface is + * applied. + * + * This request modifies the behaviour of wl_surface.commit request on + * the sub-surface, see the documentation on wl_subsurface interface. + */ +static inline struct wl_subsurface * +wl_subcompositor_get_subsurface(struct wl_subcompositor *wl_subcompositor, struct wl_surface *surface, struct wl_surface *parent) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wl_subcompositor, + WL_SUBCOMPOSITOR_GET_SUBSURFACE, &wl_subsurface_interface, wl_proxy_get_version((struct wl_proxy *) wl_subcompositor), 0, NULL, surface, parent); + + return (struct wl_subsurface *) id; +} + +#ifndef WL_SUBSURFACE_ERROR_ENUM +#define WL_SUBSURFACE_ERROR_ENUM +enum wl_subsurface_error { + /** + * wl_surface is not a sibling or the parent + */ + WL_SUBSURFACE_ERROR_BAD_SURFACE = 0, +}; +#endif /* WL_SUBSURFACE_ERROR_ENUM */ + +#define WL_SUBSURFACE_DESTROY 0 +#define WL_SUBSURFACE_SET_POSITION 1 +#define WL_SUBSURFACE_PLACE_ABOVE 2 +#define WL_SUBSURFACE_PLACE_BELOW 3 +#define WL_SUBSURFACE_SET_SYNC 4 +#define WL_SUBSURFACE_SET_DESYNC 5 + + +/** + * @ingroup iface_wl_subsurface + */ +#define WL_SUBSURFACE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wl_subsurface + */ +#define WL_SUBSURFACE_SET_POSITION_SINCE_VERSION 1 +/** + * @ingroup iface_wl_subsurface + */ +#define WL_SUBSURFACE_PLACE_ABOVE_SINCE_VERSION 1 +/** + * @ingroup iface_wl_subsurface + */ +#define WL_SUBSURFACE_PLACE_BELOW_SINCE_VERSION 1 +/** + * @ingroup iface_wl_subsurface + */ +#define WL_SUBSURFACE_SET_SYNC_SINCE_VERSION 1 +/** + * @ingroup iface_wl_subsurface + */ +#define WL_SUBSURFACE_SET_DESYNC_SINCE_VERSION 1 + +/** @ingroup iface_wl_subsurface */ +static inline void +wl_subsurface_set_user_data(struct wl_subsurface *wl_subsurface, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_subsurface, user_data); +} + +/** @ingroup iface_wl_subsurface */ +static inline void * +wl_subsurface_get_user_data(struct wl_subsurface *wl_subsurface) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_subsurface); +} + +static inline uint32_t +wl_subsurface_get_version(struct wl_subsurface *wl_subsurface) +{ + return wl_proxy_get_version((struct wl_proxy *) wl_subsurface); +} + +/** + * @ingroup iface_wl_subsurface + * + * The sub-surface interface is removed from the wl_surface object + * that was turned into a sub-surface with a + * wl_subcompositor.get_subsurface request. The wl_surface's association + * to the parent is deleted, and the wl_surface loses its role as + * a sub-surface. The wl_surface is unmapped immediately. + */ +static inline void +wl_subsurface_destroy(struct wl_subsurface *wl_subsurface) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, + WL_SUBSURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wl_subsurface + * + * This schedules a sub-surface position change. + * The sub-surface will be moved so that its origin (top left + * corner pixel) will be at the location x, y of the parent surface + * coordinate system. The coordinates are not restricted to the parent + * surface area. Negative values are allowed. + * + * The scheduled coordinates will take effect whenever the state of the + * parent surface is applied. When this happens depends on whether the + * parent surface is in synchronized mode or not. See + * wl_subsurface.set_sync and wl_subsurface.set_desync for details. + * + * If more than one set_position request is invoked by the client before + * the commit of the parent surface, the position of a new request always + * replaces the scheduled position from any previous request. + * + * The initial position is 0, 0. + */ +static inline void +wl_subsurface_set_position(struct wl_subsurface *wl_subsurface, int32_t x, int32_t y) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, + WL_SUBSURFACE_SET_POSITION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, x, y); +} + +/** + * @ingroup iface_wl_subsurface + * + * This sub-surface is taken from the stack, and put back just + * above the reference surface, changing the z-order of the sub-surfaces. + * The reference surface must be one of the sibling surfaces, or the + * parent surface. Using any other surface, including this sub-surface, + * will cause a protocol error. + * + * The z-order is double-buffered. Requests are handled in order and + * applied immediately to a pending state. The final pending state is + * copied to the active state the next time the state of the parent + * surface is applied. When this happens depends on whether the parent + * surface is in synchronized mode or not. See wl_subsurface.set_sync and + * wl_subsurface.set_desync for details. + * + * A new sub-surface is initially added as the top-most in the stack + * of its siblings and parent. + */ +static inline void +wl_subsurface_place_above(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, + WL_SUBSURFACE_PLACE_ABOVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, sibling); +} + +/** + * @ingroup iface_wl_subsurface + * + * The sub-surface is placed just below the reference surface. + * See wl_subsurface.place_above. + */ +static inline void +wl_subsurface_place_below(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, + WL_SUBSURFACE_PLACE_BELOW, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, sibling); +} + +/** + * @ingroup iface_wl_subsurface + * + * Change the commit behaviour of the sub-surface to synchronized + * mode, also described as the parent dependent mode. + * + * In synchronized mode, wl_surface.commit on a sub-surface will + * accumulate the committed state in a cache, but the state will + * not be applied and hence will not change the compositor output. + * The cached state is applied to the sub-surface immediately after + * the parent surface's state is applied. This ensures atomic + * updates of the parent and all its synchronized sub-surfaces. + * Applying the cached state will invalidate the cache, so further + * parent surface commits do not (re-)apply old state. + * + * See wl_subsurface for the recursive effect of this mode. + */ +static inline void +wl_subsurface_set_sync(struct wl_subsurface *wl_subsurface) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, + WL_SUBSURFACE_SET_SYNC, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0); +} + +/** + * @ingroup iface_wl_subsurface + * + * Change the commit behaviour of the sub-surface to desynchronized + * mode, also described as independent or freely running mode. + * + * In desynchronized mode, wl_surface.commit on a sub-surface will + * apply the pending state directly, without caching, as happens + * normally with a wl_surface. Calling wl_surface.commit on the + * parent surface has no effect on the sub-surface's wl_surface + * state. This mode allows a sub-surface to be updated on its own. + * + * If cached state exists when wl_surface.commit is called in + * desynchronized mode, the pending state is added to the cached + * state, and applied as a whole. This invalidates the cache. + * + * Note: even if a sub-surface is set to desynchronized, a parent + * sub-surface may override it to behave as synchronized. For details, + * see wl_subsurface. + * + * If a surface's parent surface behaves as desynchronized, then + * the cached state is applied on set_desync. + */ +static inline void +wl_subsurface_set_desync(struct wl_subsurface *wl_subsurface) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, + WL_SUBSURFACE_SET_DESYNC, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/linuxbsd_headers/wayland/wayland-client.h b/thirdparty/linuxbsd_headers/wayland/wayland-client.h new file mode 100644 index 00000000000..9f70fa3fbb1 --- /dev/null +++ b/thirdparty/linuxbsd_headers/wayland/wayland-client.h @@ -0,0 +1,42 @@ +/* + * Copyright © 2008 Kristian Høgsberg + * + * 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. + */ + +/** \file + * + * \brief Include the client API and protocol C API. + * + * \warning Use of this header file is discouraged. Prefer including + * wayland-client-core.h instead, which does not include the + * client protocol header and as such only defines the library + * API. + */ + +#ifndef WAYLAND_CLIENT_H +#define WAYLAND_CLIENT_H + +#include "wayland-client-core.h" +#include "wayland-client-protocol.h" + +#endif diff --git a/thirdparty/linuxbsd_headers/wayland/wayland-cursor.h b/thirdparty/linuxbsd_headers/wayland/wayland-cursor.h new file mode 100644 index 00000000000..915a1100c10 --- /dev/null +++ b/thirdparty/linuxbsd_headers/wayland/wayland-cursor.h @@ -0,0 +1,96 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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. + */ + +#ifndef WAYLAND_CURSOR_H +#define WAYLAND_CURSOR_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct wl_cursor_theme; +struct wl_buffer; +struct wl_shm; + +/** A still image part of a cursor + * + * Use `wl_cursor_image_get_buffer()` to get the corresponding `struct + * wl_buffer` to attach to your `struct wl_surface`. */ +struct wl_cursor_image { + /** Actual width */ + uint32_t width; + + /** Actual height */ + uint32_t height; + + /** Hot spot x (must be inside image) */ + uint32_t hotspot_x; + + /** Hot spot y (must be inside image) */ + uint32_t hotspot_y; + + /** Animation delay to next frame (ms) */ + uint32_t delay; +}; + +/** A cursor, as returned by `wl_cursor_theme_get_cursor()` */ +struct wl_cursor { + /** How many images there are in this cursor’s animation */ + unsigned int image_count; + + /** The array of still images composing this animation */ + struct wl_cursor_image **images; + + /** The name of this cursor */ + char *name; +}; + +struct wl_cursor_theme * +wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm); + +void +wl_cursor_theme_destroy(struct wl_cursor_theme *theme); + +struct wl_cursor * +wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme, + const char *name); + +struct wl_buffer * +wl_cursor_image_get_buffer(struct wl_cursor_image *image); + +int +wl_cursor_frame(struct wl_cursor *cursor, uint32_t time); + +int +wl_cursor_frame_and_duration(struct wl_cursor *cursor, uint32_t time, + uint32_t *duration); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/linuxbsd_headers/wayland/wayland-egl-core.h b/thirdparty/linuxbsd_headers/wayland/wayland-egl-core.h new file mode 100644 index 00000000000..b3ab5124de5 --- /dev/null +++ b/thirdparty/linuxbsd_headers/wayland/wayland-egl-core.h @@ -0,0 +1,59 @@ +/* + * Copyright © 2011 Kristian Høgsberg + * Copyright © 2011 Benjamin Franzke + * + * 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. + */ + +#ifndef WAYLAND_EGL_CORE_H +#define WAYLAND_EGL_CORE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define WL_EGL_PLATFORM 1 + +struct wl_egl_window; +struct wl_surface; + +struct wl_egl_window * +wl_egl_window_create(struct wl_surface *surface, + int width, int height); + +void +wl_egl_window_destroy(struct wl_egl_window *egl_window); + +void +wl_egl_window_resize(struct wl_egl_window *egl_window, + int width, int height, + int dx, int dy); + +void +wl_egl_window_get_attached_size(struct wl_egl_window *egl_window, + int *width, int *height); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/linuxbsd_headers/wayland/wayland-util.h b/thirdparty/linuxbsd_headers/wayland/wayland-util.h new file mode 100644 index 00000000000..18c512e129d --- /dev/null +++ b/thirdparty/linuxbsd_headers/wayland/wayland-util.h @@ -0,0 +1,765 @@ +/* + * Copyright © 2008 Kristian Høgsberg + * + * 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. + */ + +/** \file wayland-util.h + * + * \brief Utility classes, functions, and macros. + */ + +#ifndef WAYLAND_UTIL_H +#define WAYLAND_UTIL_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Visibility attribute */ +#if defined(__GNUC__) && __GNUC__ >= 4 +#define WL_EXPORT __attribute__ ((visibility("default"))) +#else +#define WL_EXPORT +#endif + +/** Deprecated attribute */ +#if defined(__GNUC__) && __GNUC__ >= 4 +#define WL_DEPRECATED __attribute__ ((deprecated)) +#else +#define WL_DEPRECATED +#endif + +/** + * Printf-style argument attribute + * + * \param x Ordinality of the format string argument + * \param y Ordinality of the argument to check against the format string + * + * \sa https://gcc.gnu.org/onlinedocs/gcc-3.2.1/gcc/Function-Attributes.html + */ +#if defined(__GNUC__) && __GNUC__ >= 4 +#define WL_PRINTF(x, y) __attribute__((__format__(__printf__, x, y))) +#else +#define WL_PRINTF(x, y) +#endif + +/** \class wl_object + * + * \brief A protocol object. + * + * A `wl_object` is an opaque struct identifying the protocol object + * underlying a `wl_proxy` or `wl_resource`. + * + * \note Functions accessing a `wl_object` are not normally used by client code. + * Clients should normally use the higher level interface generated by the + * scanner to interact with compositor objects. + * + */ +struct wl_object; + +/** + * Protocol message signature + * + * A wl_message describes the signature of an actual protocol message, such as a + * request or event, that adheres to the Wayland protocol wire format. The + * protocol implementation uses a wl_message within its demarshal machinery for + * decoding messages between a compositor and its clients. In a sense, a + * wl_message is to a protocol message like a class is to an object. + * + * The `name` of a wl_message is the name of the corresponding protocol message. + * + * The `signature` is an ordered list of symbols representing the data types + * of message arguments and, optionally, a protocol version and indicators for + * nullability. A leading integer in the `signature` indicates the _since_ + * version of the protocol message. A `?` preceding a data type symbol indicates + * that the following argument type is nullable. While it is a protocol violation + * to send messages with non-nullable arguments set to `NULL`, event handlers in + * clients might still get called with non-nullable object arguments set to + * `NULL`. This can happen when the client destroyed the object being used as + * argument on its side and an event referencing that object was sent before the + * server knew about its destruction. As this race cannot be prevented, clients + * should - as a general rule - program their event handlers such that they can + * handle object arguments declared non-nullable being `NULL` gracefully. + * + * When no arguments accompany a message, `signature` is an empty string. + * + * Symbols: + * + * * `i`: int + * * `u`: uint + * * `f`: fixed + * * `s`: string + * * `o`: object + * * `n`: new_id + * * `a`: array + * * `h`: fd + * * `?`: following argument is nullable + * + * While demarshaling primitive arguments is straightforward, when demarshaling + * messages containing `object` or `new_id` arguments, the protocol + * implementation often must determine the type of the object. The `types` of a + * wl_message is an array of wl_interface references that correspond to `o` and + * `n` arguments in `signature`, with `NULL` placeholders for arguments with + * non-object types. + * + * Consider the protocol event wl_display `delete_id` that has a single `uint` + * argument. The wl_message is: + * + * \code + * { "delete_id", "u", [NULL] } + * \endcode + * + * Here, the message `name` is `"delete_id"`, the `signature` is `"u"`, and the + * argument `types` is `[NULL]`, indicating that the `uint` argument has no + * corresponding wl_interface since it is a primitive argument. + * + * In contrast, consider a `wl_foo` interface supporting protocol request `bar` + * that has existed since version 2, and has two arguments: a `uint` and an + * object of type `wl_baz_interface` that may be `NULL`. Such a `wl_message` + * might be: + * + * \code + * { "bar", "2u?o", [NULL, &wl_baz_interface] } + * \endcode + * + * Here, the message `name` is `"bar"`, and the `signature` is `"2u?o"`. Notice + * how the `2` indicates the protocol version, the `u` indicates the first + * argument type is `uint`, and the `?o` indicates that the second argument + * is an object that may be `NULL`. Lastly, the argument `types` array indicates + * that no wl_interface corresponds to the first argument, while the type + * `wl_baz_interface` corresponds to the second argument. + * + * \sa wl_argument + * \sa wl_interface + * \sa Wire Format + */ +struct wl_message { + /** Message name */ + const char *name; + /** Message signature */ + const char *signature; + /** Object argument interfaces */ + const struct wl_interface **types; +}; + +/** + * Protocol object interface + * + * A wl_interface describes the API of a protocol object defined in the Wayland + * protocol specification. The protocol implementation uses a wl_interface + * within its marshalling machinery for encoding client requests. + * + * The `name` of a wl_interface is the name of the corresponding protocol + * interface, and `version` represents the version of the interface. The members + * `method_count` and `event_count` represent the number of `methods` (requests) + * and `events` in the respective wl_message members. + * + * For example, consider a protocol interface `foo`, marked as version `1`, with + * two requests and one event. + * + * \code{.xml} + * + * + * + * + * + * \endcode + * + * Given two wl_message arrays `foo_requests` and `foo_events`, a wl_interface + * for `foo` might be: + * + * \code + * struct wl_interface foo_interface = { + * "foo", 1, + * 2, foo_requests, + * 1, foo_events + * }; + * \endcode + * + * \note The server side of the protocol may define interface implementation + * types that incorporate the term `interface` in their name. Take + * care to not confuse these server-side `struct`s with a wl_interface + * variable whose name also ends in `interface`. For example, while the + * server may define a type `struct wl_foo_interface`, the client may + * define a `struct wl_interface wl_foo_interface`. + * + * \sa wl_message + * \sa wl_proxy + * \sa Interfaces + * \sa Versioning + */ +struct wl_interface { + /** Interface name */ + const char *name; + /** Interface version */ + int version; + /** Number of methods (requests) */ + int method_count; + /** Method (request) signatures */ + const struct wl_message *methods; + /** Number of events */ + int event_count; + /** Event signatures */ + const struct wl_message *events; +}; + +/** \class wl_list + * + * \brief Doubly-linked list + * + * On its own, an instance of `struct wl_list` represents the sentinel head of + * a doubly-linked list, and must be initialized using wl_list_init(). + * When empty, the list head's `next` and `prev` members point to the list head + * itself, otherwise `next` references the first element in the list, and `prev` + * refers to the last element in the list. + * + * Use the `struct wl_list` type to represent both the list head and the links + * between elements within the list. Use wl_list_empty() to determine if the + * list is empty in O(1). + * + * All elements in the list must be of the same type. The element type must have + * a `struct wl_list` member, often named `link` by convention. Prior to + * insertion, there is no need to initialize an element's `link` - invoking + * wl_list_init() on an individual list element's `struct wl_list` member is + * unnecessary if the very next operation is wl_list_insert(). However, a + * common idiom is to initialize an element's `link` prior to removal - ensure + * safety by invoking wl_list_init() before wl_list_remove(). + * + * Consider a list reference `struct wl_list foo_list`, an element type as + * `struct element`, and an element's link member as `struct wl_list link`. + * + * The following code initializes a list and adds three elements to it. + * + * \code + * struct wl_list foo_list; + * + * struct element { + * int foo; + * struct wl_list link; + * }; + * struct element e1, e2, e3; + * + * wl_list_init(&foo_list); + * wl_list_insert(&foo_list, &e1.link); // e1 is the first element + * wl_list_insert(&foo_list, &e2.link); // e2 is now the first element + * wl_list_insert(&e2.link, &e3.link); // insert e3 after e2 + * \endcode + * + * The list now looks like [e2, e3, e1]. + * + * The `wl_list` API provides some iterator macros. For example, to iterate + * a list in ascending order: + * + * \code + * struct element *e; + * wl_list_for_each(e, foo_list, link) { + * do_something_with_element(e); + * } + * \endcode + * + * See the documentation of each iterator for details. + * \sa http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/linux/list.h + */ +struct wl_list { + /** Previous list element */ + struct wl_list *prev; + /** Next list element */ + struct wl_list *next; +}; + +/** + * Initializes the list. + * + * \param list List to initialize + * + * \memberof wl_list + */ +void +wl_list_init(struct wl_list *list); + +/** + * Inserts an element into the list, after the element represented by \p list. + * When \p list is a reference to the list itself (the head), set the containing + * struct of \p elm as the first element in the list. + * + * \note If \p elm is already part of a list, inserting it again will lead to + * list corruption. + * + * \param list List element after which the new element is inserted + * \param elm Link of the containing struct to insert into the list + * + * \memberof wl_list + */ +void +wl_list_insert(struct wl_list *list, struct wl_list *elm); + +/** + * Removes an element from the list. + * + * \note This operation leaves \p elm in an invalid state. + * + * \param elm Link of the containing struct to remove from the list + * + * \memberof wl_list + */ +void +wl_list_remove(struct wl_list *elm); + +/** + * Determines the length of the list. + * + * \note This is an O(n) operation. + * + * \param list List whose length is to be determined + * + * \return Number of elements in the list + * + * \memberof wl_list + */ +int +wl_list_length(const struct wl_list *list); + +/** + * Determines if the list is empty. + * + * \param list List whose emptiness is to be determined + * + * \return 1 if empty, or 0 if not empty + * + * \memberof wl_list + */ +int +wl_list_empty(const struct wl_list *list); + +/** + * Inserts all of the elements of one list into another, after the element + * represented by \p list. + * + * \note This leaves \p other in an invalid state. + * + * \param list List element after which the other list elements will be inserted + * \param other List of elements to insert + * + * \memberof wl_list + */ +void +wl_list_insert_list(struct wl_list *list, struct wl_list *other); + +/** + * Retrieves a pointer to a containing struct, given a member name. + * + * This macro allows "conversion" from a pointer to a member to its containing + * struct. This is useful if you have a contained item like a wl_list, + * wl_listener, or wl_signal, provided via a callback or other means, and would + * like to retrieve the struct that contains it. + * + * To demonstrate, the following example retrieves a pointer to + * `example_container` given only its `destroy_listener` member: + * + * \code + * struct example_container { + * struct wl_listener destroy_listener; + * // other members... + * }; + * + * void example_container_destroy(struct wl_listener *listener, void *data) + * { + * struct example_container *ctr; + * + * ctr = wl_container_of(listener, ctr, destroy_listener); + * // destroy ctr... + * } + * \endcode + * + * \note `sample` need not be a valid pointer. A null or uninitialised pointer + * is sufficient. + * + * \param ptr Valid pointer to the contained member + * \param sample Pointer to a struct whose type contains \p ptr + * \param member Named location of \p ptr within the \p sample type + * + * \return The container for the specified pointer + */ +#define wl_container_of(ptr, sample, member) \ + (__typeof__(sample))((char *)(ptr) - \ + offsetof(__typeof__(*sample), member)) + +/** + * Iterates over a list. + * + * This macro expresses a for-each iterator for wl_list. Given a list and + * wl_list link member name (often named `link` by convention), this macro + * assigns each element in the list to \p pos, which can then be referenced in + * a trailing code block. For example, given a wl_list of `struct message` + * elements: + * + * \code + * struct message { + * char *contents; + * wl_list link; + * }; + * + * struct wl_list *message_list; + * // Assume message_list now "contains" many messages + * + * struct message *m; + * wl_list_for_each(m, message_list, link) { + * do_something_with_message(m); + * } + * \endcode + * + * \param pos Cursor that each list element will be assigned to + * \param head Head of the list to iterate over + * \param member Name of the link member within the element struct + * + * \relates wl_list + */ +#define wl_list_for_each(pos, head, member) \ + for (pos = wl_container_of((head)->next, pos, member); \ + &pos->member != (head); \ + pos = wl_container_of(pos->member.next, pos, member)) + +/** + * Iterates over a list, safe against removal of the list element. + * + * \note Only removal of the current element, \p pos, is safe. Removing + * any other element during traversal may lead to a loop malfunction. + * + * \sa wl_list_for_each() + * + * \param pos Cursor that each list element will be assigned to + * \param tmp Temporary pointer of the same type as \p pos + * \param head Head of the list to iterate over + * \param member Name of the link member within the element struct + * + * \relates wl_list + */ +#define wl_list_for_each_safe(pos, tmp, head, member) \ + for (pos = wl_container_of((head)->next, pos, member), \ + tmp = wl_container_of((pos)->member.next, tmp, member); \ + &pos->member != (head); \ + pos = tmp, \ + tmp = wl_container_of(pos->member.next, tmp, member)) + +/** + * Iterates backwards over a list. + * + * \sa wl_list_for_each() + * + * \param pos Cursor that each list element will be assigned to + * \param head Head of the list to iterate over + * \param member Name of the link member within the element struct + * + * \relates wl_list + */ +#define wl_list_for_each_reverse(pos, head, member) \ + for (pos = wl_container_of((head)->prev, pos, member); \ + &pos->member != (head); \ + pos = wl_container_of(pos->member.prev, pos, member)) + +/** + * Iterates backwards over a list, safe against removal of the list element. + * + * \note Only removal of the current element, \p pos, is safe. Removing + * any other element during traversal may lead to a loop malfunction. + * + * \sa wl_list_for_each() + * + * \param pos Cursor that each list element will be assigned to + * \param tmp Temporary pointer of the same type as \p pos + * \param head Head of the list to iterate over + * \param member Name of the link member within the element struct + * + * \relates wl_list + */ +#define wl_list_for_each_reverse_safe(pos, tmp, head, member) \ + for (pos = wl_container_of((head)->prev, pos, member), \ + tmp = wl_container_of((pos)->member.prev, tmp, member); \ + &pos->member != (head); \ + pos = tmp, \ + tmp = wl_container_of(pos->member.prev, tmp, member)) + +/** + * \class wl_array + * + * Dynamic array + * + * A wl_array is a dynamic array that can only grow until released. It is + * intended for relatively small allocations whose size is variable or not known + * in advance. While construction of a wl_array does not require all elements to + * be of the same size, wl_array_for_each() does require all elements to have + * the same type and size. + * + */ +struct wl_array { + /** Array size */ + size_t size; + /** Allocated space */ + size_t alloc; + /** Array data */ + void *data; +}; + +/** + * Initializes the array. + * + * \param array Array to initialize + * + * \memberof wl_array + */ +void +wl_array_init(struct wl_array *array); + +/** + * Releases the array data. + * + * \note Leaves the array in an invalid state. + * + * \param array Array whose data is to be released + * + * \memberof wl_array + */ +void +wl_array_release(struct wl_array *array); + +/** + * Increases the size of the array by \p size bytes. + * + * \param array Array whose size is to be increased + * \param size Number of bytes to increase the size of the array by + * + * \return A pointer to the beginning of the newly appended space, or NULL when + * resizing fails. + * + * \memberof wl_array + */ +void * +wl_array_add(struct wl_array *array, size_t size); + +/** + * Copies the contents of \p source to \p array. + * + * \param array Destination array to copy to + * \param source Source array to copy from + * + * \return 0 on success, or -1 on failure + * + * \memberof wl_array + */ +int +wl_array_copy(struct wl_array *array, struct wl_array *source); + +/** + * Iterates over an array. + * + * This macro expresses a for-each iterator for wl_array. It assigns each + * element in the array to \p pos, which can then be referenced in a trailing + * code block. \p pos must be a pointer to the array element type, and all + * array elements must be of the same type and size. + * + * \param pos Cursor that each array element will be assigned to + * \param array Array to iterate over + * + * \relates wl_array + * \sa wl_list_for_each() + */ +#define wl_array_for_each(pos, array) \ + for (pos = (array)->data; \ + (const char *) pos < ((const char *) (array)->data + (array)->size); \ + (pos)++) + +/** + * Fixed-point number + * + * A `wl_fixed_t` is a 24.8 signed fixed-point number with a sign bit, 23 bits + * of integer precision and 8 bits of decimal precision. Consider `wl_fixed_t` + * as an opaque struct with methods that facilitate conversion to and from + * `double` and `int` types. + */ +typedef int32_t wl_fixed_t; + +/** + * Converts a fixed-point number to a floating-point number. + * + * \param f Fixed-point number to convert + * + * \return Floating-point representation of the fixed-point argument + */ +static inline double +wl_fixed_to_double(wl_fixed_t f) +{ + union { + double d; + int64_t i; + } u; + + u.i = ((1023LL + 44LL) << 52) + (1LL << 51) + f; + + return u.d - (3LL << 43); +} + +/** + * Converts a floating-point number to a fixed-point number. + * + * \param d Floating-point number to convert + * + * \return Fixed-point representation of the floating-point argument + */ +static inline wl_fixed_t +wl_fixed_from_double(double d) +{ + union { + double d; + int64_t i; + } u; + + u.d = d + (3LL << (51 - 8)); + + return (wl_fixed_t)u.i; +} + +/** + * Converts a fixed-point number to an integer. + * + * \param f Fixed-point number to convert + * + * \return Integer component of the fixed-point argument + */ +static inline int +wl_fixed_to_int(wl_fixed_t f) +{ + return f / 256; +} + +/** + * Converts an integer to a fixed-point number. + * + * \param i Integer to convert + * + * \return Fixed-point representation of the integer argument + */ +static inline wl_fixed_t +wl_fixed_from_int(int i) +{ + return i * 256; +} + +/** + * Protocol message argument data types + * + * This union represents all of the argument types in the Wayland protocol wire + * format. The protocol implementation uses wl_argument within its marshalling + * machinery for dispatching messages between a client and a compositor. + * + * \sa wl_message + * \sa wl_interface + * \sa Wire Format + */ +union wl_argument { + int32_t i; /**< `int` */ + uint32_t u; /**< `uint` */ + wl_fixed_t f; /**< `fixed` */ + const char *s; /**< `string` */ + struct wl_object *o; /**< `object` */ + uint32_t n; /**< `new_id` */ + struct wl_array *a; /**< `array` */ + int32_t h; /**< `fd` */ +}; + +/** + * Dispatcher function type alias + * + * A dispatcher is a function that handles the emitting of callbacks in client + * code. For programs directly using the C library, this is done by using + * libffi to call function pointers. When binding to languages other than C, + * dispatchers provide a way to abstract the function calling process to be + * friendlier to other function calling systems. + * + * A dispatcher takes five arguments: The first is the dispatcher-specific + * implementation associated with the target object. The second is the object + * upon which the callback is being invoked (either wl_proxy or wl_resource). + * The third and fourth arguments are the opcode and the wl_message + * corresponding to the callback. The final argument is an array of arguments + * received from the other process via the wire protocol. + * + * \param "const void *" Dispatcher-specific implementation data + * \param "void *" Callback invocation target (wl_proxy or `wl_resource`) + * \param uint32_t Callback opcode + * \param "const struct wl_message *" Callback message signature + * \param "union wl_argument *" Array of received arguments + * + * \return 0 on success, or -1 on failure + */ +typedef int (*wl_dispatcher_func_t)(const void *, void *, uint32_t, + const struct wl_message *, + union wl_argument *); + +/** + * Log function type alias + * + * The C implementation of the Wayland protocol abstracts the details of + * logging. Users may customize the logging behavior, with a function conforming + * to the `wl_log_func_t` type, via `wl_log_set_handler_client` and + * `wl_log_set_handler_server`. + * + * A `wl_log_func_t` must conform to the expectations of `vprintf`, and + * expects two arguments: a string to write and a corresponding variable + * argument list. While the string to write may contain format specifiers and + * use values in the variable argument list, the behavior of any `wl_log_func_t` + * depends on the implementation. + * + * \note Take care to not confuse this with `wl_protocol_logger_func_t`, which + * is a specific server-side logger for requests and events. + * + * \param "const char *" String to write to the log, containing optional format + * specifiers + * \param "va_list" Variable argument list + * + * \sa wl_log_set_handler_client + * \sa wl_log_set_handler_server + */ +typedef void (*wl_log_func_t)(const char *, va_list) WL_PRINTF(1, 0); + +/** + * Return value of an iterator function + * + * \sa wl_client_for_each_resource_iterator_func_t + * \sa wl_client_for_each_resource + */ +enum wl_iterator_result { + /** Stop the iteration */ + WL_ITERATOR_STOP, + /** Continue the iteration */ + WL_ITERATOR_CONTINUE +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/linuxbsd_headers/wayland/wayland-version.h b/thirdparty/linuxbsd_headers/wayland/wayland-version.h new file mode 100644 index 00000000000..38f53e57348 --- /dev/null +++ b/thirdparty/linuxbsd_headers/wayland/wayland-version.h @@ -0,0 +1,34 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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. + */ + +#ifndef WAYLAND_VERSION_H +#define WAYLAND_VERSION_H + +#define WAYLAND_VERSION_MAJOR 1 +#define WAYLAND_VERSION_MINOR 21 +#define WAYLAND_VERSION_MICRO 0 +#define WAYLAND_VERSION "1.21.0" + +#endif diff --git a/thirdparty/wayland-protocols/COPYING b/thirdparty/wayland-protocols/COPYING new file mode 100644 index 00000000000..8ab3291e385 --- /dev/null +++ b/thirdparty/wayland-protocols/COPYING @@ -0,0 +1,33 @@ +Copyright © 2008-2013 Kristian Høgsberg +Copyright © 2010-2013 Intel Corporation +Copyright © 2013 Rafael Antognolli +Copyright © 2013 Jasper St. Pierre +Copyright © 2014 Jonas Ådahl +Copyright © 2014 Jason Ekstrand +Copyright © 2014-2015 Collabora, Ltd. +Copyright © 2015 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. + +--- + +The above is the version of the MIT "Expat" License used by X.org: + + http://cgit.freedesktop.org/xorg/xserver/tree/COPYING diff --git a/thirdparty/wayland-protocols/stable/viewporter/README b/thirdparty/wayland-protocols/stable/viewporter/README new file mode 100644 index 00000000000..e09057b16cb --- /dev/null +++ b/thirdparty/wayland-protocols/stable/viewporter/README @@ -0,0 +1,7 @@ +Viewporter: cropping and scaling extension for surface contents + +Previously known as wl_scaler. + +Maintainers: +Pekka Paalanen + diff --git a/thirdparty/wayland-protocols/stable/viewporter/viewporter.xml b/thirdparty/wayland-protocols/stable/viewporter/viewporter.xml new file mode 100644 index 00000000000..d1048d1f332 --- /dev/null +++ b/thirdparty/wayland-protocols/stable/viewporter/viewporter.xml @@ -0,0 +1,180 @@ + + + + + Copyright © 2013-2016 Collabora, Ltd. + + 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. + + + + + The global interface exposing surface cropping and scaling + capabilities is used to instantiate an interface extension for a + wl_surface object. This extended interface will then allow + cropping and scaling the surface contents, effectively + disconnecting the direct relationship between the buffer and the + surface size. + + + + + Informs the server that the client will not be using this + protocol object anymore. This does not affect any other objects, + wp_viewport objects included. + + + + + + + + + + Instantiate an interface extension for the given wl_surface to + crop and scale its content. If the given wl_surface already has + a wp_viewport object associated, the viewport_exists + protocol error is raised. + + + + + + + + + An additional interface to a wl_surface object, which allows the + client to specify the cropping and scaling of the surface + contents. + + This interface works with two concepts: the source rectangle (src_x, + src_y, src_width, src_height), and the destination size (dst_width, + dst_height). The contents of the source rectangle are scaled to the + destination size, and content outside the source rectangle is ignored. + This state is double-buffered, and is applied on the next + wl_surface.commit. + + The two parts of crop and scale state are independent: the source + rectangle, and the destination size. Initially both are unset, that + is, no scaling is applied. The whole of the current wl_buffer is + used as the source, and the surface size is as defined in + wl_surface.attach. + + If the destination size is set, it causes the surface size to become + dst_width, dst_height. The source (rectangle) is scaled to exactly + this size. This overrides whatever the attached wl_buffer size is, + unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface + has no content and therefore no size. Otherwise, the size is always + at least 1x1 in surface local coordinates. + + If the source rectangle is set, it defines what area of the wl_buffer is + taken as the source. If the source rectangle is set and the destination + size is not set, then src_width and src_height must be integers, and the + surface size becomes the source rectangle size. This results in cropping + without scaling. If src_width or src_height are not integers and + destination size is not set, the bad_size protocol error is raised when + the surface state is applied. + + The coordinate transformations from buffer pixel coordinates up to + the surface-local coordinates happen in the following order: + 1. buffer_transform (wl_surface.set_buffer_transform) + 2. buffer_scale (wl_surface.set_buffer_scale) + 3. crop and scale (wp_viewport.set*) + This means, that the source rectangle coordinates of crop and scale + are given in the coordinates after the buffer transform and scale, + i.e. in the coordinates that would be the surface-local coordinates + if the crop and scale was not applied. + + If src_x or src_y are negative, the bad_value protocol error is raised. + Otherwise, if the source rectangle is partially or completely outside of + the non-NULL wl_buffer, then the out_of_buffer protocol error is raised + when the surface state is applied. A NULL wl_buffer does not raise the + out_of_buffer error. + + If the wl_surface associated with the wp_viewport is destroyed, + all wp_viewport requests except 'destroy' raise the protocol error + no_surface. + + If the wp_viewport object is destroyed, the crop and scale + state is removed from the wl_surface. The change will be applied + on the next wl_surface.commit. + + + + + The associated wl_surface's crop and scale state is removed. + The change is applied on the next wl_surface.commit. + + + + + + + + + + + + + Set the source rectangle of the associated wl_surface. See + wp_viewport for the description, and relation to the wl_buffer + size. + + If all of x, y, width and height are -1.0, the source rectangle is + unset instead. Any other set of values where width or height are zero + or negative, or x or y are negative, raise the bad_value protocol + error. + + The crop and scale state is double-buffered state, and will be + applied on the next wl_surface.commit. + + + + + + + + + + Set the destination size of the associated wl_surface. See + wp_viewport for the description, and relation to the wl_buffer + size. + + If width is -1 and height is -1, the destination size is unset + instead. Any other pair of values for width and height that + contains zero or negative values raises the bad_value protocol + error. + + The crop and scale state is double-buffered state, and will be + applied on the next wl_surface.commit. + + + + + + + diff --git a/thirdparty/wayland-protocols/stable/xdg-shell/README b/thirdparty/wayland-protocols/stable/xdg-shell/README new file mode 100644 index 00000000000..c45f70c8300 --- /dev/null +++ b/thirdparty/wayland-protocols/stable/xdg-shell/README @@ -0,0 +1,5 @@ +xdg shell protocol + +Maintainers: +Jonas Ådahl +Mike Blumenkrantz diff --git a/thirdparty/wayland-protocols/stable/xdg-shell/xdg-shell.xml b/thirdparty/wayland-protocols/stable/xdg-shell/xdg-shell.xml new file mode 100644 index 00000000000..777eaa7499a --- /dev/null +++ b/thirdparty/wayland-protocols/stable/xdg-shell/xdg-shell.xml @@ -0,0 +1,1370 @@ + + + + + Copyright © 2008-2013 Kristian Høgsberg + Copyright © 2013 Rafael Antognolli + Copyright © 2013 Jasper St. Pierre + Copyright © 2010-2013 Intel Corporation + Copyright © 2015-2017 Samsung Electronics Co., Ltd + Copyright © 2015-2017 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. + + + + + The xdg_wm_base interface is exposed as a global object enabling clients + to turn their wl_surfaces into windows in a desktop environment. It + defines the basic functionality needed for clients and the compositor to + create windows that can be dragged, resized, maximized, etc, as well as + creating transient windows such as popup menus. + + + + + + + + + + + + + + + Destroy this xdg_wm_base object. + + Destroying a bound xdg_wm_base object while there are surfaces + still alive created by this xdg_wm_base object instance is illegal + and will result in a defunct_surfaces error. + + + + + + Create a positioner object. A positioner object is used to position + surfaces relative to some parent surface. See the interface description + and xdg_surface.get_popup for details. + + + + + + + This creates an xdg_surface for the given surface. While xdg_surface + itself is not a role, the corresponding surface may only be assigned + a role extending xdg_surface, such as xdg_toplevel or xdg_popup. It is + illegal to create an xdg_surface for a wl_surface which already has an + assigned role and this will result in a role error. + + This creates an xdg_surface for the given surface. An xdg_surface is + used as basis to define a role to a given surface, such as xdg_toplevel + or xdg_popup. It also manages functionality shared between xdg_surface + based surface roles. + + See the documentation of xdg_surface for more details about what an + xdg_surface is and how it is used. + + + + + + + + A client must respond to a ping event with a pong request or + the client may be deemed unresponsive. See xdg_wm_base.ping + and xdg_wm_base.error.unresponsive. + + + + + + + The ping event asks the client if it's still alive. Pass the + serial specified in the event back to the compositor by sending + a "pong" request back with the specified serial. See xdg_wm_base.pong. + + Compositors can use this to determine if the client is still + alive. It's unspecified what will happen if the client doesn't + respond to the ping request, or in what timeframe. Clients should + try to respond in a reasonable amount of time. The “unresponsive” + error is provided for compositors that wish to disconnect unresponsive + clients. + + A compositor is free to ping in any way it wants, but a client must + always respond to any xdg_wm_base object it created. + + + + + + + + The xdg_positioner provides a collection of rules for the placement of a + child surface relative to a parent surface. Rules can be defined to ensure + the child surface remains within the visible area's borders, and to + specify how the child surface changes its position, such as sliding along + an axis, or flipping around a rectangle. These positioner-created rules are + constrained by the requirement that a child surface must intersect with or + be at least partially adjacent to its parent surface. + + See the various requests for details about possible rules. + + At the time of the request, the compositor makes a copy of the rules + specified by the xdg_positioner. Thus, after the request is complete the + xdg_positioner object can be destroyed or reused; further changes to the + object will have no effect on previous usages. + + For an xdg_positioner object to be considered complete, it must have a + non-zero size set by set_size, and a non-zero anchor rectangle set by + set_anchor_rect. Passing an incomplete xdg_positioner object when + positioning a surface raises an invalid_positioner error. + + + + + + + + + Notify the compositor that the xdg_positioner will no longer be used. + + + + + + Set the size of the surface that is to be positioned with the positioner + object. The size is in surface-local coordinates and corresponds to the + window geometry. See xdg_surface.set_window_geometry. + + If a zero or negative size is set the invalid_input error is raised. + + + + + + + + Specify the anchor rectangle within the parent surface that the child + surface will be placed relative to. The rectangle is relative to the + window geometry as defined by xdg_surface.set_window_geometry of the + parent surface. + + When the xdg_positioner object is used to position a child surface, the + anchor rectangle may not extend outside the window geometry of the + positioned child's parent surface. + + If a negative size is set the invalid_input error is raised. + + + + + + + + + + + + + + + + + + + + + + Defines the anchor point for the anchor rectangle. The specified anchor + is used derive an anchor point that the child surface will be + positioned relative to. If a corner anchor is set (e.g. 'top_left' or + 'bottom_right'), the anchor point will be at the specified corner; + otherwise, the derived anchor point will be centered on the specified + edge, or in the center of the anchor rectangle if no edge is specified. + + + + + + + + + + + + + + + + + + + Defines in what direction a surface should be positioned, relative to + the anchor point of the parent surface. If a corner gravity is + specified (e.g. 'bottom_right' or 'top_left'), then the child surface + will be placed towards the specified gravity; otherwise, the child + surface will be centered over the anchor point on any axis that had no + gravity specified. If the gravity is not in the ‘gravity’ enum, an + invalid_input error is raised. + + + + + + + The constraint adjustment value define ways the compositor will adjust + the position of the surface, if the unadjusted position would result + in the surface being partly constrained. + + Whether a surface is considered 'constrained' is left to the compositor + to determine. For example, the surface may be partly outside the + compositor's defined 'work area', thus necessitating the child surface's + position be adjusted until it is entirely inside the work area. + + The adjustments can be combined, according to a defined precedence: 1) + Flip, 2) Slide, 3) Resize. + + + + Don't alter the surface position even if it is constrained on some + axis, for example partially outside the edge of an output. + + + + + Slide the surface along the x axis until it is no longer constrained. + + First try to slide towards the direction of the gravity on the x axis + until either the edge in the opposite direction of the gravity is + unconstrained or the edge in the direction of the gravity is + constrained. + + Then try to slide towards the opposite direction of the gravity on the + x axis until either the edge in the direction of the gravity is + unconstrained or the edge in the opposite direction of the gravity is + constrained. + + + + + Slide the surface along the y axis until it is no longer constrained. + + First try to slide towards the direction of the gravity on the y axis + until either the edge in the opposite direction of the gravity is + unconstrained or the edge in the direction of the gravity is + constrained. + + Then try to slide towards the opposite direction of the gravity on the + y axis until either the edge in the direction of the gravity is + unconstrained or the edge in the opposite direction of the gravity is + constrained. + + + + + Invert the anchor and gravity on the x axis if the surface is + constrained on the x axis. For example, if the left edge of the + surface is constrained, the gravity is 'left' and the anchor is + 'left', change the gravity to 'right' and the anchor to 'right'. + + If the adjusted position also ends up being constrained, the resulting + position of the flip_x adjustment will be the one before the + adjustment. + + + + + Invert the anchor and gravity on the y axis if the surface is + constrained on the y axis. For example, if the bottom edge of the + surface is constrained, the gravity is 'bottom' and the anchor is + 'bottom', change the gravity to 'top' and the anchor to 'top'. + + The adjusted position is calculated given the original anchor + rectangle and offset, but with the new flipped anchor and gravity + values. + + If the adjusted position also ends up being constrained, the resulting + position of the flip_y adjustment will be the one before the + adjustment. + + + + + Resize the surface horizontally so that it is completely + unconstrained. + + + + + Resize the surface vertically so that it is completely unconstrained. + + + + + + + Specify how the window should be positioned if the originally intended + position caused the surface to be constrained, meaning at least + partially outside positioning boundaries set by the compositor. The + adjustment is set by constructing a bitmask describing the adjustment to + be made when the surface is constrained on that axis. + + If no bit for one axis is set, the compositor will assume that the child + surface should not change its position on that axis when constrained. + + If more than one bit for one axis is set, the order of how adjustments + are applied is specified in the corresponding adjustment descriptions. + + The default adjustment is none. + + + + + + + Specify the surface position offset relative to the position of the + anchor on the anchor rectangle and the anchor on the surface. For + example if the anchor of the anchor rectangle is at (x, y), the surface + has the gravity bottom|right, and the offset is (ox, oy), the calculated + surface position will be (x + ox, y + oy). The offset position of the + surface is the one used for constraint testing. See + set_constraint_adjustment. + + An example use case is placing a popup menu on top of a user interface + element, while aligning the user interface element of the parent surface + with some user interface element placed somewhere in the popup surface. + + + + + + + + + + When set reactive, the surface is reconstrained if the conditions used + for constraining changed, e.g. the parent window moved. + + If the conditions changed and the popup was reconstrained, an + xdg_popup.configure event is sent with updated geometry, followed by an + xdg_surface.configure event. + + + + + + Set the parent window geometry the compositor should use when + positioning the popup. The compositor may use this information to + determine the future state the popup should be constrained using. If + this doesn't match the dimension of the parent the popup is eventually + positioned against, the behavior is undefined. + + The arguments are given in the surface-local coordinate space. + + + + + + + + Set the serial of an xdg_surface.configure event this positioner will be + used in response to. The compositor may use this information together + with set_parent_size to determine what future state the popup should be + constrained using. + + + + + + + + An interface that may be implemented by a wl_surface, for + implementations that provide a desktop-style user interface. + + It provides a base set of functionality required to construct user + interface elements requiring management by the compositor, such as + toplevel windows, menus, etc. The types of functionality are split into + xdg_surface roles. + + Creating an xdg_surface does not set the role for a wl_surface. In order + to map an xdg_surface, the client must create a role-specific object + using, e.g., get_toplevel, get_popup. The wl_surface for any given + xdg_surface can have at most one role, and may not be assigned any role + not based on xdg_surface. + + A role must be assigned before any other requests are made to the + xdg_surface object. + + The client must call wl_surface.commit on the corresponding wl_surface + for the xdg_surface state to take effect. + + Creating an xdg_surface from a wl_surface which has a buffer attached or + committed is a client error, and any attempts by a client to attach or + manipulate a buffer prior to the first xdg_surface.configure call must + also be treated as errors. + + After creating a role-specific object and setting it up, the client must + perform an initial commit without any buffer attached. The compositor + will reply with initial wl_surface state such as + wl_surface.preferred_buffer_scale followed by an xdg_surface.configure + event. The client must acknowledge it and is then allowed to attach a + buffer to map the surface. + + Mapping an xdg_surface-based role surface is defined as making it + possible for the surface to be shown by the compositor. Note that + a mapped surface is not guaranteed to be visible once it is mapped. + + For an xdg_surface to be mapped by the compositor, the following + conditions must be met: + (1) the client has assigned an xdg_surface-based role to the surface + (2) the client has set and committed the xdg_surface state and the + role-dependent state to the surface + (3) the client has committed a buffer to the surface + + A newly-unmapped surface is considered to have met condition (1) out + of the 3 required conditions for mapping a surface if its role surface + has not been destroyed, i.e. the client must perform the initial commit + again before attaching a buffer. + + + + + + + + + + + + + + Destroy the xdg_surface object. An xdg_surface must only be destroyed + after its role object has been destroyed, otherwise + a defunct_role_object error is raised. + + + + + + This creates an xdg_toplevel object for the given xdg_surface and gives + the associated wl_surface the xdg_toplevel role. + + See the documentation of xdg_toplevel for more details about what an + xdg_toplevel is and how it is used. + + + + + + + This creates an xdg_popup object for the given xdg_surface and gives + the associated wl_surface the xdg_popup role. + + If null is passed as a parent, a parent surface must be specified using + some other protocol, before committing the initial state. + + See the documentation of xdg_popup for more details about what an + xdg_popup is and how it is used. + + + + + + + + + The window geometry of a surface is its "visible bounds" from the + user's perspective. Client-side decorations often have invisible + portions like drop-shadows which should be ignored for the + purposes of aligning, placing and constraining windows. + + The window geometry is double buffered, and will be applied at the + time wl_surface.commit of the corresponding wl_surface is called. + + When maintaining a position, the compositor should treat the (x, y) + coordinate of the window geometry as the top left corner of the window. + A client changing the (x, y) window geometry coordinate should in + general not alter the position of the window. + + Once the window geometry of the surface is set, it is not possible to + unset it, and it will remain the same until set_window_geometry is + called again, even if a new subsurface or buffer is attached. + + If never set, the value is the full bounds of the surface, + including any subsurfaces. This updates dynamically on every + commit. This unset is meant for extremely simple clients. + + The arguments are given in the surface-local coordinate space of + the wl_surface associated with this xdg_surface, and may extend outside + of the wl_surface itself to mark parts of the subsurface tree as part of + the window geometry. + + When applied, the effective window geometry will be the set window + geometry clamped to the bounding rectangle of the combined + geometry of the surface of the xdg_surface and the associated + subsurfaces. + + The effective geometry will not be recalculated unless a new call to + set_window_geometry is done and the new pending surface state is + subsequently applied. + + The width and height of the effective window geometry must be + greater than zero. Setting an invalid size will raise an + invalid_size error. + + + + + + + + + + When a configure event is received, if a client commits the + surface in response to the configure event, then the client + must make an ack_configure request sometime before the commit + request, passing along the serial of the configure event. + + For instance, for toplevel surfaces the compositor might use this + information to move a surface to the top left only when the client has + drawn itself for the maximized or fullscreen state. + + If the client receives multiple configure events before it + can respond to one, it only has to ack the last configure event. + Acking a configure event that was never sent raises an invalid_serial + error. + + A client is not required to commit immediately after sending + an ack_configure request - it may even ack_configure several times + before its next surface commit. + + A client may send multiple ack_configure requests before committing, but + only the last request sent before a commit indicates which configure + event the client really is responding to. + + Sending an ack_configure request consumes the serial number sent with + the request, as well as serial numbers sent by all configure events + sent on this xdg_surface prior to the configure event referenced by + the committed serial. + + It is an error to issue multiple ack_configure requests referencing a + serial from the same configure event, or to issue an ack_configure + request referencing a serial from a configure event issued before the + event identified by the last ack_configure request for the same + xdg_surface. Doing so will raise an invalid_serial error. + + + + + + + The configure event marks the end of a configure sequence. A configure + sequence is a set of one or more events configuring the state of the + xdg_surface, including the final xdg_surface.configure event. + + Where applicable, xdg_surface surface roles will during a configure + sequence extend this event as a latched state sent as events before the + xdg_surface.configure event. Such events should be considered to make up + a set of atomically applied configuration states, where the + xdg_surface.configure commits the accumulated state. + + Clients should arrange their surface for the new states, and then send + an ack_configure request with the serial sent in this configure event at + some point before committing the new surface. + + If the client receives multiple configure events before it can respond + to one, it is free to discard all but the last event it received. + + + + + + + + + This interface defines an xdg_surface role which allows a surface to, + among other things, set window-like properties such as maximize, + fullscreen, and minimize, set application-specific metadata like title and + id, and well as trigger user interactive operations such as interactive + resize and move. + + Unmapping an xdg_toplevel means that the surface cannot be shown + by the compositor until it is explicitly mapped again. + All active operations (e.g., move, resize) are canceled and all + attributes (e.g. title, state, stacking, ...) are discarded for + an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to + the state it had right after xdg_surface.get_toplevel. The client + can re-map the toplevel by perfoming a commit without any buffer + attached, waiting for a configure event and handling it as usual (see + xdg_surface description). + + Attaching a null buffer to a toplevel unmaps the surface. + + + + + This request destroys the role surface and unmaps the surface; + see "Unmapping" behavior in interface section for details. + + + + + + + + + + + + Set the "parent" of this surface. This surface should be stacked + above the parent surface and all other ancestor surfaces. + + Parent surfaces should be set on dialogs, toolboxes, or other + "auxiliary" surfaces, so that the parent is raised when the dialog + is raised. + + Setting a null parent for a child surface unsets its parent. Setting + a null parent for a surface which currently has no parent is a no-op. + + Only mapped surfaces can have child surfaces. Setting a parent which + is not mapped is equivalent to setting a null parent. If a surface + becomes unmapped, its children's parent is set to the parent of + the now-unmapped surface. If the now-unmapped surface has no parent, + its children's parent is unset. If the now-unmapped surface becomes + mapped again, its parent-child relationship is not restored. + + The parent toplevel must not be one of the child toplevel's + descendants, and the parent must be different from the child toplevel, + otherwise the invalid_parent protocol error is raised. + + + + + + + Set a short title for the surface. + + This string may be used to identify the surface in a task bar, + window list, or other user interface elements provided by the + compositor. + + The string must be encoded in UTF-8. + + + + + + + Set an application identifier for the surface. + + The app ID identifies the general class of applications to which + the surface belongs. The compositor can use this to group multiple + surfaces together, or to determine how to launch a new application. + + For D-Bus activatable applications, the app ID is used as the D-Bus + service name. + + The compositor shell will try to group application surfaces together + by their app ID. As a best practice, it is suggested to select app + ID's that match the basename of the application's .desktop file. + For example, "org.freedesktop.FooViewer" where the .desktop file is + "org.freedesktop.FooViewer.desktop". + + Like other properties, a set_app_id request can be sent after the + xdg_toplevel has been mapped to update the property. + + See the desktop-entry specification [0] for more details on + application identifiers and how they relate to well-known D-Bus + names and .desktop files. + + [0] https://standards.freedesktop.org/desktop-entry-spec/ + + + + + + + Clients implementing client-side decorations might want to show + a context menu when right-clicking on the decorations, giving the + user a menu that they can use to maximize or minimize the window. + + This request asks the compositor to pop up such a window menu at + the given position, relative to the local surface coordinates of + the parent surface. There are no guarantees as to what menu items + the window menu contains, or even if a window menu will be drawn + at all. + + This request must be used in response to some sort of user action + like a button press, key press, or touch down event. + + + + + + + + + + Start an interactive, user-driven move of the surface. + + This request must be used in response to some sort of user action + like a button press, key press, or touch down event. The passed + serial is used to determine the type of interactive move (touch, + pointer, etc). + + The server may ignore move requests depending on the state of + the surface (e.g. fullscreen or maximized), or if the passed serial + is no longer valid. + + If triggered, the surface will lose the focus of the device + (wl_pointer, wl_touch, etc) used for the move. It is up to the + compositor to visually indicate that the move is taking place, such as + updating a pointer cursor, during the move. There is no guarantee + that the device focus will return when the move is completed. + + + + + + + + These values are used to indicate which edge of a surface + is being dragged in a resize operation. + + + + + + + + + + + + + + + Start a user-driven, interactive resize of the surface. + + This request must be used in response to some sort of user action + like a button press, key press, or touch down event. The passed + serial is used to determine the type of interactive resize (touch, + pointer, etc). + + The server may ignore resize requests depending on the state of + the surface (e.g. fullscreen or maximized). + + If triggered, the client will receive configure events with the + "resize" state enum value and the expected sizes. See the "resize" + enum value for more details about what is required. The client + must also acknowledge configure events using "ack_configure". After + the resize is completed, the client will receive another "configure" + event without the resize state. + + If triggered, the surface also will lose the focus of the device + (wl_pointer, wl_touch, etc) used for the resize. It is up to the + compositor to visually indicate that the resize is taking place, + such as updating a pointer cursor, during the resize. There is no + guarantee that the device focus will return when the resize is + completed. + + The edges parameter specifies how the surface should be resized, and + is one of the values of the resize_edge enum. Values not matching + a variant of the enum will cause the invalid_resize_edge protocol error. + The compositor may use this information to update the surface position + for example when dragging the top left corner. The compositor may also + use this information to adapt its behavior, e.g. choose an appropriate + cursor image. + + + + + + + + + The different state values used on the surface. This is designed for + state values like maximized, fullscreen. It is paired with the + configure event to ensure that both the client and the compositor + setting the state can be synchronized. + + States set in this way are double-buffered. They will get applied on + the next commit. + + + + The surface is maximized. The window geometry specified in the configure + event must be obeyed by the client, or the xdg_wm_base.invalid_surface_state + error is raised. + + The client should draw without shadow or other + decoration outside of the window geometry. + + + + + The surface is fullscreen. The window geometry specified in the + configure event is a maximum; the client cannot resize beyond it. For + a surface to cover the whole fullscreened area, the geometry + dimensions must be obeyed by the client. For more details, see + xdg_toplevel.set_fullscreen. + + + + + The surface is being resized. The window geometry specified in the + configure event is a maximum; the client cannot resize beyond it. + Clients that have aspect ratio or cell sizing configuration can use + a smaller size, however. + + + + + Client window decorations should be painted as if the window is + active. Do not assume this means that the window actually has + keyboard or pointer focus. + + + + + The window is currently in a tiled layout and the left edge is + considered to be adjacent to another part of the tiling grid. + + + + + The window is currently in a tiled layout and the right edge is + considered to be adjacent to another part of the tiling grid. + + + + + The window is currently in a tiled layout and the top edge is + considered to be adjacent to another part of the tiling grid. + + + + + The window is currently in a tiled layout and the bottom edge is + considered to be adjacent to another part of the tiling grid. + + + + + The surface is currently not ordinarily being repainted; for + example because its content is occluded by another window, or its + outputs are switched off due to screen locking. + + + + + + + Set a maximum size for the window. + + The client can specify a maximum size so that the compositor does + not try to configure the window beyond this size. + + The width and height arguments are in window geometry coordinates. + See xdg_surface.set_window_geometry. + + Values set in this way are double-buffered. They will get applied + on the next commit. + + The compositor can use this information to allow or disallow + different states like maximize or fullscreen and draw accurate + animations. + + Similarly, a tiling window manager may use this information to + place and resize client windows in a more effective way. + + The client should not rely on the compositor to obey the maximum + size. The compositor may decide to ignore the values set by the + client and request a larger size. + + If never set, or a value of zero in the request, means that the + client has no expected maximum size in the given dimension. + As a result, a client wishing to reset the maximum size + to an unspecified state can use zero for width and height in the + request. + + Requesting a maximum size to be smaller than the minimum size of + a surface is illegal and will result in an invalid_size error. + + The width and height must be greater than or equal to zero. Using + strictly negative values for width or height will result in a + invalid_size error. + + + + + + + + Set a minimum size for the window. + + The client can specify a minimum size so that the compositor does + not try to configure the window below this size. + + The width and height arguments are in window geometry coordinates. + See xdg_surface.set_window_geometry. + + Values set in this way are double-buffered. They will get applied + on the next commit. + + The compositor can use this information to allow or disallow + different states like maximize or fullscreen and draw accurate + animations. + + Similarly, a tiling window manager may use this information to + place and resize client windows in a more effective way. + + The client should not rely on the compositor to obey the minimum + size. The compositor may decide to ignore the values set by the + client and request a smaller size. + + If never set, or a value of zero in the request, means that the + client has no expected minimum size in the given dimension. + As a result, a client wishing to reset the minimum size + to an unspecified state can use zero for width and height in the + request. + + Requesting a minimum size to be larger than the maximum size of + a surface is illegal and will result in an invalid_size error. + + The width and height must be greater than or equal to zero. Using + strictly negative values for width and height will result in a + invalid_size error. + + + + + + + + Maximize the surface. + + After requesting that the surface should be maximized, the compositor + will respond by emitting a configure event. Whether this configure + actually sets the window maximized is subject to compositor policies. + The client must then update its content, drawing in the configured + state. The client must also acknowledge the configure when committing + the new content (see ack_configure). + + It is up to the compositor to decide how and where to maximize the + surface, for example which output and what region of the screen should + be used. + + If the surface was already maximized, the compositor will still emit + a configure event with the "maximized" state. + + If the surface is in a fullscreen state, this request has no direct + effect. It may alter the state the surface is returned to when + unmaximized unless overridden by the compositor. + + + + + + Unmaximize the surface. + + After requesting that the surface should be unmaximized, the compositor + will respond by emitting a configure event. Whether this actually + un-maximizes the window is subject to compositor policies. + If available and applicable, the compositor will include the window + geometry dimensions the window had prior to being maximized in the + configure event. The client must then update its content, drawing it in + the configured state. The client must also acknowledge the configure + when committing the new content (see ack_configure). + + It is up to the compositor to position the surface after it was + unmaximized; usually the position the surface had before maximizing, if + applicable. + + If the surface was already not maximized, the compositor will still + emit a configure event without the "maximized" state. + + If the surface is in a fullscreen state, this request has no direct + effect. It may alter the state the surface is returned to when + unmaximized unless overridden by the compositor. + + + + + + Make the surface fullscreen. + + After requesting that the surface should be fullscreened, the + compositor will respond by emitting a configure event. Whether the + client is actually put into a fullscreen state is subject to compositor + policies. The client must also acknowledge the configure when + committing the new content (see ack_configure). + + The output passed by the request indicates the client's preference as + to which display it should be set fullscreen on. If this value is NULL, + it's up to the compositor to choose which display will be used to map + this surface. + + If the surface doesn't cover the whole output, the compositor will + position the surface in the center of the output and compensate with + with border fill covering the rest of the output. The content of the + border fill is undefined, but should be assumed to be in some way that + attempts to blend into the surrounding area (e.g. solid black). + + If the fullscreened surface is not opaque, the compositor must make + sure that other screen content not part of the same surface tree (made + up of subsurfaces, popups or similarly coupled surfaces) are not + visible below the fullscreened surface. + + + + + + + Make the surface no longer fullscreen. + + After requesting that the surface should be unfullscreened, the + compositor will respond by emitting a configure event. + Whether this actually removes the fullscreen state of the client is + subject to compositor policies. + + Making a surface unfullscreen sets states for the surface based on the following: + * the state(s) it may have had before becoming fullscreen + * any state(s) decided by the compositor + * any state(s) requested by the client while the surface was fullscreen + + The compositor may include the previous window geometry dimensions in + the configure event, if applicable. + + The client must also acknowledge the configure when committing the new + content (see ack_configure). + + + + + + Request that the compositor minimize your surface. There is no + way to know if the surface is currently minimized, nor is there + any way to unset minimization on this surface. + + If you are looking to throttle redrawing when minimized, please + instead use the wl_surface.frame event for this, as this will + also work with live previews on windows in Alt-Tab, Expose or + similar compositor features. + + + + + + This configure event asks the client to resize its toplevel surface or + to change its state. The configured state should not be applied + immediately. See xdg_surface.configure for details. + + The width and height arguments specify a hint to the window + about how its surface should be resized in window geometry + coordinates. See set_window_geometry. + + If the width or height arguments are zero, it means the client + should decide its own window dimension. This may happen when the + compositor needs to configure the state of the surface but doesn't + have any information about any previous or expected dimension. + + The states listed in the event specify how the width/height + arguments should be interpreted, and possibly how it should be + drawn. + + Clients must send an ack_configure in response to this event. See + xdg_surface.configure and xdg_surface.ack_configure for details. + + + + + + + + + The close event is sent by the compositor when the user + wants the surface to be closed. This should be equivalent to + the user clicking the close button in client-side decorations, + if your application has any. + + This is only a request that the user intends to close the + window. The client may choose to ignore this request, or show + a dialog to ask the user to save their data, etc. + + + + + + + + The configure_bounds event may be sent prior to a xdg_toplevel.configure + event to communicate the bounds a window geometry size is recommended + to constrain to. + + The passed width and height are in surface coordinate space. If width + and height are 0, it means bounds is unknown and equivalent to as if no + configure_bounds event was ever sent for this surface. + + The bounds can for example correspond to the size of a monitor excluding + any panels or other shell components, so that a surface isn't created in + a way that it cannot fit. + + The bounds may change at any point, and in such a case, a new + xdg_toplevel.configure_bounds will be sent, followed by + xdg_toplevel.configure and xdg_surface.configure. + + + + + + + + + + + + + + + + + This event advertises the capabilities supported by the compositor. If + a capability isn't supported, clients should hide or disable the UI + elements that expose this functionality. For instance, if the + compositor doesn't advertise support for minimized toplevels, a button + triggering the set_minimized request should not be displayed. + + The compositor will ignore requests it doesn't support. For instance, + a compositor which doesn't advertise support for minimized will ignore + set_minimized requests. + + Compositors must send this event once before the first + xdg_surface.configure event. When the capabilities change, compositors + must send this event again and then send an xdg_surface.configure + event. + + The configured state should not be applied immediately. See + xdg_surface.configure for details. + + The capabilities are sent as an array of 32-bit unsigned integers in + native endianness. + + + + + + + + A popup surface is a short-lived, temporary surface. It can be used to + implement for example menus, popovers, tooltips and other similar user + interface concepts. + + A popup can be made to take an explicit grab. See xdg_popup.grab for + details. + + When the popup is dismissed, a popup_done event will be sent out, and at + the same time the surface will be unmapped. See the xdg_popup.popup_done + event for details. + + Explicitly destroying the xdg_popup object will also dismiss the popup and + unmap the surface. Clients that want to dismiss the popup when another + surface of their own is clicked should dismiss the popup using the destroy + request. + + A newly created xdg_popup will be stacked on top of all previously created + xdg_popup surfaces associated with the same xdg_toplevel. + + The parent of an xdg_popup must be mapped (see the xdg_surface + description) before the xdg_popup itself. + + The client must call wl_surface.commit on the corresponding wl_surface + for the xdg_popup state to take effect. + + + + + + + + + This destroys the popup. Explicitly destroying the xdg_popup + object will also dismiss the popup, and unmap the surface. + + If this xdg_popup is not the "topmost" popup, the + xdg_wm_base.not_the_topmost_popup protocol error will be sent. + + + + + + This request makes the created popup take an explicit grab. An explicit + grab will be dismissed when the user dismisses the popup, or when the + client destroys the xdg_popup. This can be done by the user clicking + outside the surface, using the keyboard, or even locking the screen + through closing the lid or a timeout. + + If the compositor denies the grab, the popup will be immediately + dismissed. + + This request must be used in response to some sort of user action like a + button press, key press, or touch down event. The serial number of the + event should be passed as 'serial'. + + The parent of a grabbing popup must either be an xdg_toplevel surface or + another xdg_popup with an explicit grab. If the parent is another + xdg_popup it means that the popups are nested, with this popup now being + the topmost popup. + + Nested popups must be destroyed in the reverse order they were created + in, e.g. the only popup you are allowed to destroy at all times is the + topmost one. + + When compositors choose to dismiss a popup, they may dismiss every + nested grabbing popup as well. When a compositor dismisses popups, it + will follow the same dismissing order as required from the client. + + If the topmost grabbing popup is destroyed, the grab will be returned to + the parent of the popup, if that parent previously had an explicit grab. + + If the parent is a grabbing popup which has already been dismissed, this + popup will be immediately dismissed. If the parent is a popup that did + not take an explicit grab, an error will be raised. + + During a popup grab, the client owning the grab will receive pointer + and touch events for all their surfaces as normal (similar to an + "owner-events" grab in X11 parlance), while the top most grabbing popup + will always have keyboard focus. + + + + + + + + This event asks the popup surface to configure itself given the + configuration. The configured state should not be applied immediately. + See xdg_surface.configure for details. + + The x and y arguments represent the position the popup was placed at + given the xdg_positioner rule, relative to the upper left corner of the + window geometry of the parent surface. + + For version 2 or older, the configure event for an xdg_popup is only + ever sent once for the initial configuration. Starting with version 3, + it may be sent again if the popup is setup with an xdg_positioner with + set_reactive requested, or in response to xdg_popup.reposition requests. + + + + + + + + + + The popup_done event is sent out when a popup is dismissed by the + compositor. The client should destroy the xdg_popup object at this + point. + + + + + + + + Reposition an already-mapped popup. The popup will be placed given the + details in the passed xdg_positioner object, and a + xdg_popup.repositioned followed by xdg_popup.configure and + xdg_surface.configure will be emitted in response. Any parameters set + by the previous positioner will be discarded. + + The passed token will be sent in the corresponding + xdg_popup.repositioned event. The new popup position will not take + effect until the corresponding configure event is acknowledged by the + client. See xdg_popup.repositioned for details. The token itself is + opaque, and has no other special meaning. + + If multiple reposition requests are sent, the compositor may skip all + but the last one. + + If the popup is repositioned in response to a configure event for its + parent, the client should send an xdg_positioner.set_parent_configure + and possibly an xdg_positioner.set_parent_size request to allow the + compositor to properly constrain the popup. + + If the popup is repositioned together with a parent that is being + resized, but not in response to a configure event, the client should + send an xdg_positioner.set_parent_size request. + + + + + + + + The repositioned event is sent as part of a popup configuration + sequence, together with xdg_popup.configure and lastly + xdg_surface.configure to notify the completion of a reposition request. + + The repositioned event is to notify about the completion of a + xdg_popup.reposition request. The token argument is the token passed + in the xdg_popup.reposition request. + + Immediately after this event is emitted, xdg_popup.configure and + xdg_surface.configure will be sent with the updated size and position, + as well as a new configure serial. + + The client should optionally update the content of the popup, but must + acknowledge the new popup configuration for the new position to take + effect. See xdg_surface.ack_configure for details. + + + + + + diff --git a/thirdparty/wayland-protocols/staging/fractional-scale/README b/thirdparty/wayland-protocols/staging/fractional-scale/README new file mode 100644 index 00000000000..6cb0475f276 --- /dev/null +++ b/thirdparty/wayland-protocols/staging/fractional-scale/README @@ -0,0 +1,4 @@ +wp fractional scale protocol + +Maintainers: +Kenny Levinsen diff --git a/thirdparty/wayland-protocols/staging/fractional-scale/fractional-scale-v1.xml b/thirdparty/wayland-protocols/staging/fractional-scale/fractional-scale-v1.xml new file mode 100644 index 00000000000..350bfc01eaf --- /dev/null +++ b/thirdparty/wayland-protocols/staging/fractional-scale/fractional-scale-v1.xml @@ -0,0 +1,102 @@ + + + + Copyright © 2022 Kenny Levinsen + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + This protocol allows a compositor to suggest for surfaces to render at + fractional scales. + + A client can submit scaled content by utilizing wp_viewport. This is done by + creating a wp_viewport object for the surface and setting the destination + rectangle to the surface size before the scale factor is applied. + + The buffer size is calculated by multiplying the surface size by the + intended scale. + + The wl_surface buffer scale should remain set to 1. + + If a surface has a surface-local size of 100 px by 50 px and wishes to + submit buffers with a scale of 1.5, then a buffer of 150px by 75 px should + be used and the wp_viewport destination rectangle should be 100 px by 50 px. + + For toplevel surfaces, the size is rounded halfway away from zero. The + rounding algorithm for subsurface position and size is not defined. + + + + + A global interface for requesting surfaces to use fractional scales. + + + + + Informs the server that the client will not be using this protocol + object anymore. This does not affect any other objects, + wp_fractional_scale_v1 objects included. + + + + + + + + + + Create an add-on object for the the wl_surface to let the compositor + request fractional scales. If the given wl_surface already has a + wp_fractional_scale_v1 object associated, the fractional_scale_exists + protocol error is raised. + + + + + + + + + An additional interface to a wl_surface object which allows the compositor + to inform the client of the preferred scale. + + + + + Destroy the fractional scale object. When this object is destroyed, + preferred_scale events will no longer be sent. + + + + + + Notification of a new preferred scale for this surface that the + compositor suggests that the client should use. + + The sent scale is the numerator of a fraction with a denominator of 120. + + + + + diff --git a/thirdparty/wayland-protocols/staging/xdg-activation/README b/thirdparty/wayland-protocols/staging/xdg-activation/README new file mode 100644 index 00000000000..cdd4d96cc41 --- /dev/null +++ b/thirdparty/wayland-protocols/staging/xdg-activation/README @@ -0,0 +1,4 @@ +XDG Activation protocol + +Maintainers: +Aleix Pol Gonzalez diff --git a/thirdparty/wayland-protocols/staging/xdg-activation/xdg-activation-v1.xml b/thirdparty/wayland-protocols/staging/xdg-activation/xdg-activation-v1.xml new file mode 100644 index 00000000000..9adcc274ef1 --- /dev/null +++ b/thirdparty/wayland-protocols/staging/xdg-activation/xdg-activation-v1.xml @@ -0,0 +1,200 @@ + + + + + Copyright © 2020 Aleix Pol Gonzalez <aleixpol@kde.org> + Copyright © 2020 Carlos Garnacho <carlosg@gnome.org> + + 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. + + + + The way for a client to pass focus to another toplevel is as follows. + + The client that intends to activate another toplevel uses the + xdg_activation_v1.get_activation_token request to get an activation token. + This token is then forwarded to the client, which is supposed to activate + one of its surfaces, through a separate band of communication. + + One established way of doing this is through the XDG_ACTIVATION_TOKEN + environment variable of a newly launched child process. The child process + should unset the environment variable again right after reading it out in + order to avoid propagating it to other child processes. + + Another established way exists for Applications implementing the D-Bus + interface org.freedesktop.Application, which should get their token under + activation-token on their platform_data. + + In general activation tokens may be transferred across clients through + means not described in this protocol. + + The client to be activated will then pass the token + it received to the xdg_activation_v1.activate request. The compositor can + then use this token to decide how to react to the activation request. + + The token the activating client gets may be ineffective either already at + the time it receives it, for example if it was not focused, for focus + stealing prevention. The activating client will have no way to discover + the validity of the token, and may still forward it to the to be activated + client. + + The created activation token may optionally get information attached to it + that can be used by the compositor to identify the application that we + intend to activate. This can for example be used to display a visual hint + about what application is being started. + + Warning! The protocol described in this file is currently in the testing + phase. Backward compatible changes may be added together with the + corresponding interface version bump. Backward incompatible changes can + only be done by creating a new major version of the extension. + + + + + A global interface used for informing the compositor about applications + being activated or started, or for applications to request to be + activated. + + + + + Notify the compositor that the xdg_activation object will no longer be + used. + + The child objects created via this interface are unaffected and should + be destroyed separately. + + + + + + Creates an xdg_activation_token_v1 object that will provide + the initiating client with a unique token for this activation. This + token should be offered to the clients to be activated. + + + + + + + + Requests surface activation. It's up to the compositor to display + this information as desired, for example by placing the surface above + the rest. + + The compositor may know who requested this by checking the activation + token and might decide not to follow through with the activation if it's + considered unwanted. + + Compositors can ignore unknown activation tokens when an invalid + token is passed. + + + + + + + + + An object for setting up a token and receiving a token handle that can + be passed as an activation token to another client. + + The object is created using the xdg_activation_v1.get_activation_token + request. This object should then be populated with the app_id, surface + and serial information and committed. The compositor shall then issue a + done event with the token. In case the request's parameters are invalid, + the compositor will provide an invalid token. + + + + + + + + + Provides information about the seat and serial event that requested the + token. + + The serial can come from an input or focus event. For instance, if a + click triggers the launch of a third-party client, the launcher client + should send a set_serial request with the serial and seat from the + wl_pointer.button event. + + Some compositors might refuse to activate toplevels when the token + doesn't have a valid and recent enough event serial. + + Must be sent before commit. This information is optional. + + + + + + + + The requesting client can specify an app_id to associate the token + being created with it. + + Must be sent before commit. This information is optional. + + + + + + + This request sets the surface requesting the activation. Note, this is + different from the surface that will be activated. + + Some compositors might refuse to activate toplevels when the token + doesn't have a requesting surface. + + Must be sent before commit. This information is optional. + + + + + + + Requests an activation token based on the different parameters that + have been offered through set_serial, set_surface and set_app_id. + + + + + + The 'done' event contains the unique token of this activation request + and notifies that the provider is done. + + + + + + + Notify the compositor that the xdg_activation_token_v1 object will no + longer be used. The received token stays valid. + + + + diff --git a/thirdparty/wayland-protocols/unstable/idle-inhibit/README b/thirdparty/wayland-protocols/unstable/idle-inhibit/README new file mode 100644 index 00000000000..396e8716269 --- /dev/null +++ b/thirdparty/wayland-protocols/unstable/idle-inhibit/README @@ -0,0 +1,4 @@ +Screensaver inhibition protocol + +Maintainers: +Bryce Harrington diff --git a/thirdparty/wayland-protocols/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml b/thirdparty/wayland-protocols/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml new file mode 100644 index 00000000000..9c06cdcba6c --- /dev/null +++ b/thirdparty/wayland-protocols/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml @@ -0,0 +1,83 @@ + + + + + Copyright © 2015 Samsung Electronics Co., Ltd + + 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. + + + + + This interface permits inhibiting the idle behavior such as screen + blanking, locking, and screensaving. The client binds the idle manager + globally, then creates idle-inhibitor objects for each surface. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible changes + may be added together with the corresponding interface version bump. + Backward incompatible changes are done by bumping the version number in + the protocol and interface names and resetting the interface version. + Once the protocol is to be declared stable, the 'z' prefix and the + version number in the protocol and interface names are removed and the + interface version number is reset. + + + + + Destroy the inhibit manager. + + + + + + Create a new inhibitor object associated with the given surface. + + + + + + + + + + An idle inhibitor prevents the output that the associated surface is + visible on from being set to a state where it is not visually usable due + to lack of user interaction (e.g. blanked, dimmed, locked, set to power + save, etc.) Any screensaver processes are also blocked from displaying. + + If the surface is destroyed, unmapped, becomes occluded, loses + visibility, or otherwise becomes not visually relevant for the user, the + idle inhibitor will not be honored by the compositor; if the surface + subsequently regains visibility the inhibitor takes effect once again. + Likewise, the inhibitor isn't honored if the system was already idled at + the time the inhibitor was established, although if the system later + de-idles and re-idles the inhibitor will take effect. + + + + + Remove the inhibitor effect from the associated wl_surface. + + + + + diff --git a/thirdparty/wayland-protocols/unstable/pointer-constraints/README b/thirdparty/wayland-protocols/unstable/pointer-constraints/README new file mode 100644 index 00000000000..8a242f8d7e5 --- /dev/null +++ b/thirdparty/wayland-protocols/unstable/pointer-constraints/README @@ -0,0 +1,4 @@ +Pointer constraints protocol + +Maintainers: +Jonas Ådahl diff --git a/thirdparty/wayland-protocols/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml b/thirdparty/wayland-protocols/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml new file mode 100644 index 00000000000..efd64b6603c --- /dev/null +++ b/thirdparty/wayland-protocols/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml @@ -0,0 +1,339 @@ + + + + + Copyright © 2014 Jonas Ådahl + Copyright © 2015 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. + + + + This protocol specifies a set of interfaces used for adding constraints to + the motion of a pointer. Possible constraints include confining pointer + motions to a given region, or locking it to its current position. + + In order to constrain the pointer, a client must first bind the global + interface "wp_pointer_constraints" which, if a compositor supports pointer + constraints, is exposed by the registry. Using the bound global object, the + client uses the request that corresponds to the type of constraint it wants + to make. See wp_pointer_constraints for more details. + + 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. + + + + + The global interface exposing pointer constraining functionality. It + exposes two requests: lock_pointer for locking the pointer to its + position, and confine_pointer for locking the pointer to a region. + + The lock_pointer and confine_pointer requests create the objects + wp_locked_pointer and wp_confined_pointer respectively, and the client can + use these objects to interact with the lock. + + For any surface, only one lock or confinement may be active across all + wl_pointer objects of the same seat. If a lock or confinement is requested + when another lock or confinement is active or requested on the same surface + and with any of the wl_pointer objects of the same seat, an + 'already_constrained' error will be raised. + + + + + These errors can be emitted in response to wp_pointer_constraints + requests. + + + + + + + These values represent different lifetime semantics. They are passed + as arguments to the factory requests to specify how the constraint + lifetimes should be managed. + + + + A oneshot pointer constraint will never reactivate once it has been + deactivated. See the corresponding deactivation event + (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined) for + details. + + + + + A persistent pointer constraint may again reactivate once it has + been deactivated. See the corresponding deactivation event + (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined) for + details. + + + + + + + Used by the client to notify the server that it will no longer use this + pointer constraints object. + + + + + + The lock_pointer request lets the client request to disable movements of + the virtual pointer (i.e. the cursor), effectively locking the pointer + to a position. This request may not take effect immediately; in the + future, when the compositor deems implementation-specific constraints + are satisfied, the pointer lock will be activated and the compositor + sends a locked event. + + The protocol provides no guarantee that the constraints are ever + satisfied, and does not require the compositor to send an error if the + constraints cannot ever be satisfied. It is thus possible to request a + lock that will never activate. + + There may not be another pointer constraint of any kind requested or + active on the surface for any of the wl_pointer objects of the seat of + the passed pointer when requesting a lock. If there is, an error will be + raised. See general pointer lock documentation for more details. + + The intersection of the region passed with this request and the input + region of the surface is used to determine where the pointer must be + in order for the lock to activate. It is up to the compositor whether to + warp the pointer or require some kind of user interaction for the lock + to activate. If the region is null the surface input region is used. + + A surface may receive pointer focus without the lock being activated. + + The request creates a new object wp_locked_pointer which is used to + interact with the lock as well as receive updates about its state. See + the the description of wp_locked_pointer for further information. + + Note that while a pointer is locked, the wl_pointer objects of the + corresponding seat will not emit any wl_pointer.motion events, but + relative motion events will still be emitted via wp_relative_pointer + objects of the same seat. wl_pointer.axis and wl_pointer.button events + are unaffected. + + + + + + + + + + + The confine_pointer request lets the client request to confine the + pointer cursor to a given region. This request may not take effect + immediately; in the future, when the compositor deems implementation- + specific constraints are satisfied, the pointer confinement will be + activated and the compositor sends a confined event. + + The intersection of the region passed with this request and the input + region of the surface is used to determine where the pointer must be + in order for the confinement to activate. It is up to the compositor + whether to warp the pointer or require some kind of user interaction for + the confinement to activate. If the region is null the surface input + region is used. + + The request will create a new object wp_confined_pointer which is used + to interact with the confinement as well as receive updates about its + state. See the the description of wp_confined_pointer for further + information. + + + + + + + + + + + + The wp_locked_pointer interface represents a locked pointer state. + + While the lock of this object is active, the wl_pointer objects of the + associated seat will not emit any wl_pointer.motion events. + + This object will send the event 'locked' when the lock is activated. + Whenever the lock is activated, it is guaranteed that the locked surface + will already have received pointer focus and that the pointer will be + within the region passed to the request creating this object. + + To unlock the pointer, send the destroy request. This will also destroy + the wp_locked_pointer object. + + If the compositor decides to unlock the pointer the unlocked event is + sent. See wp_locked_pointer.unlock for details. + + When unlocking, the compositor may warp the cursor position to the set + cursor position hint. If it does, it will not result in any relative + motion events emitted via wp_relative_pointer. + + If the surface the lock was requested on is destroyed and the lock is not + yet activated, the wp_locked_pointer object is now defunct and must be + destroyed. + + + + + Destroy the locked pointer object. If applicable, the compositor will + unlock the pointer. + + + + + + Set the cursor position hint relative to the top left corner of the + surface. + + If the client is drawing its own cursor, it should update the position + hint to the position of its own cursor. A compositor may use this + information to warp the pointer upon unlock in order to avoid pointer + jumps. + + The cursor position hint is double buffered. The new hint will only take + effect when the associated surface gets it pending state applied. See + wl_surface.commit for details. + + + + + + + + Set a new region used to lock the pointer. + + The new lock region is double-buffered. The new lock region will + only take effect when the associated surface gets its pending state + applied. See wl_surface.commit for details. + + For details about the lock region, see wp_locked_pointer. + + + + + + + Notification that the pointer lock of the seat's pointer is activated. + + + + + + Notification that the pointer lock of the seat's pointer is no longer + active. If this is a oneshot pointer lock (see + wp_pointer_constraints.lifetime) this object is now defunct and should + be destroyed. If this is a persistent pointer lock (see + wp_pointer_constraints.lifetime) this pointer lock may again + reactivate in the future. + + + + + + + The wp_confined_pointer interface represents a confined pointer state. + + This object will send the event 'confined' when the confinement is + activated. Whenever the confinement is activated, it is guaranteed that + the surface the pointer is confined to will already have received pointer + focus and that the pointer will be within the region passed to the request + creating this object. It is up to the compositor to decide whether this + requires some user interaction and if the pointer will warp to within the + passed region if outside. + + To unconfine the pointer, send the destroy request. This will also destroy + the wp_confined_pointer object. + + If the compositor decides to unconfine the pointer the unconfined event is + sent. The wp_confined_pointer object is at this point defunct and should + be destroyed. + + + + + Destroy the confined pointer object. If applicable, the compositor will + unconfine the pointer. + + + + + + Set a new region used to confine the pointer. + + The new confine region is double-buffered. The new confine region will + only take effect when the associated surface gets its pending state + applied. See wl_surface.commit for details. + + If the confinement is active when the new confinement region is applied + and the pointer ends up outside of newly applied region, the pointer may + warped to a position within the new confinement region. If warped, a + wl_pointer.motion event will be emitted, but no + wp_relative_pointer.relative_motion event. + + The compositor may also, instead of using the new region, unconfine the + pointer. + + For details about the confine region, see wp_confined_pointer. + + + + + + + Notification that the pointer confinement of the seat's pointer is + activated. + + + + + + Notification that the pointer confinement of the seat's pointer is no + longer active. If this is a oneshot pointer confinement (see + wp_pointer_constraints.lifetime) this object is now defunct and should + be destroyed. If this is a persistent pointer confinement (see + wp_pointer_constraints.lifetime) this pointer confinement may again + reactivate in the future. + + + + + diff --git a/thirdparty/wayland-protocols/unstable/pointer-gestures/README b/thirdparty/wayland-protocols/unstable/pointer-gestures/README new file mode 100644 index 00000000000..a419632b0f5 --- /dev/null +++ b/thirdparty/wayland-protocols/unstable/pointer-gestures/README @@ -0,0 +1,4 @@ +Pointer gestures protocol + +Maintainers: +Carlos Garnacho diff --git a/thirdparty/wayland-protocols/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml b/thirdparty/wayland-protocols/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml new file mode 100644 index 00000000000..f92a1160594 --- /dev/null +++ b/thirdparty/wayland-protocols/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml @@ -0,0 +1,253 @@ + + + + + + A global interface to provide semantic touchpad gestures for a given + pointer. + + Three gestures are currently supported: swipe, pinch, and hold. + Pinch and swipe gestures follow a three-stage cycle: begin, update, + end, hold gestures follow a two-stage cycle: begin and end. All + gestures are identified by a unique id. + + 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. + + + + + Create a swipe gesture object. See the + wl_pointer_gesture_swipe interface for details. + + + + + + + + Create a pinch gesture object. See the + wl_pointer_gesture_pinch interface for details. + + + + + + + + + + Destroy the pointer gesture object. Swipe, pinch and hold objects + created via this gesture object remain valid. + + + + + + + + Create a hold gesture object. See the + wl_pointer_gesture_hold interface for details. + + + + + + + + + + A swipe gesture object notifies a client about a multi-finger swipe + gesture detected on an indirect input device such as a touchpad. + The gesture is usually initiated by multiple fingers moving in the + same direction but once initiated the direction may change. + The precise conditions of when such a gesture is detected are + implementation-dependent. + + A gesture consists of three stages: begin, update (optional) and end. + There cannot be multiple simultaneous hold, pinch or swipe gestures on a + same pointer/seat, how compositors prevent these situations is + implementation-dependent. + + A gesture may be cancelled by the compositor or the hardware. + Clients should not consider performing permanent or irreversible + actions until the end of a gesture has been received. + + + + + + + + + This event is sent when a multi-finger swipe gesture is detected + on the device. + + + + + + + + + + This event is sent when a multi-finger swipe gesture changes the + position of the logical center. + + The dx and dy coordinates are relative coordinates of the logical + center of the gesture compared to the previous event. + + + + + + + + + This event is sent when a multi-finger swipe gesture ceases to + be valid. This may happen when one or more fingers are lifted or + the gesture is cancelled. + + When a gesture is cancelled, the client should undo state changes + caused by this gesture. What causes a gesture to be cancelled is + implementation-dependent. + + + + + + + + + + A pinch gesture object notifies a client about a multi-finger pinch + gesture detected on an indirect input device such as a touchpad. + The gesture is usually initiated by multiple fingers moving towards + each other or away from each other, or by two or more fingers rotating + around a logical center of gravity. The precise conditions of when + such a gesture is detected are implementation-dependent. + + A gesture consists of three stages: begin, update (optional) and end. + There cannot be multiple simultaneous hold, pinch or swipe gestures on a + same pointer/seat, how compositors prevent these situations is + implementation-dependent. + + A gesture may be cancelled by the compositor or the hardware. + Clients should not consider performing permanent or irreversible + actions until the end of a gesture has been received. + + + + + + + + + This event is sent when a multi-finger pinch gesture is detected + on the device. + + + + + + + + + + This event is sent when a multi-finger pinch gesture changes the + position of the logical center, the rotation or the relative scale. + + The dx and dy coordinates are relative coordinates in the + surface coordinate space of the logical center of the gesture. + + The scale factor is an absolute scale compared to the + pointer_gesture_pinch.begin event, e.g. a scale of 2 means the fingers + are now twice as far apart as on pointer_gesture_pinch.begin. + + The rotation is the relative angle in degrees clockwise compared to the previous + pointer_gesture_pinch.begin or pointer_gesture_pinch.update event. + + + + + + + + + + + This event is sent when a multi-finger pinch gesture ceases to + be valid. This may happen when one or more fingers are lifted or + the gesture is cancelled. + + When a gesture is cancelled, the client should undo state changes + caused by this gesture. What causes a gesture to be cancelled is + implementation-dependent. + + + + + + + + + + + A hold gesture object notifies a client about a single- or + multi-finger hold gesture detected on an indirect input device such as + a touchpad. The gesture is usually initiated by one or more fingers + being held down without significant movement. The precise conditions + of when such a gesture is detected are implementation-dependent. + + In particular, this gesture may be used to cancel kinetic scrolling. + + A hold gesture consists of two stages: begin and end. Unlike pinch and + swipe there is no update stage. + There cannot be multiple simultaneous hold, pinch or swipe gestures on a + same pointer/seat, how compositors prevent these situations is + implementation-dependent. + + A gesture may be cancelled by the compositor or the hardware. + Clients should not consider performing permanent or irreversible + actions until the end of a gesture has been received. + + + + + + + + + This event is sent when a hold gesture is detected on the device. + + + + + + + + + + This event is sent when a hold gesture ceases to + be valid. This may happen when the holding fingers are lifted or + the gesture is cancelled, for example if the fingers move past an + implementation-defined threshold, the finger count changes or the hold + gesture changes into a different type of gesture. + + When a gesture is cancelled, the client may need to undo state changes + caused by this gesture. What causes a gesture to be cancelled is + implementation-dependent. + + + + + + + + diff --git a/thirdparty/wayland-protocols/unstable/primary-selection/README b/thirdparty/wayland-protocols/unstable/primary-selection/README new file mode 100644 index 00000000000..ae0a4020cac --- /dev/null +++ b/thirdparty/wayland-protocols/unstable/primary-selection/README @@ -0,0 +1,4 @@ +Primary selection protocol + +Maintainers: +Simon Ser diff --git a/thirdparty/wayland-protocols/unstable/primary-selection/primary-selection-unstable-v1.xml b/thirdparty/wayland-protocols/unstable/primary-selection/primary-selection-unstable-v1.xml new file mode 100644 index 00000000000..e5a39e34cec --- /dev/null +++ b/thirdparty/wayland-protocols/unstable/primary-selection/primary-selection-unstable-v1.xml @@ -0,0 +1,225 @@ + + + + Copyright © 2015, 2016 Red Hat + + 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. + + + + This protocol provides the ability to have a primary selection device to + match that of the X server. This primary selection is a shortcut to the + common clipboard selection, where text just needs to be selected in order + to allow copying it elsewhere. The de facto way to perform this action + is the middle mouse button, although it is not limited to this one. + + Clients wishing to honor primary selection should create a primary + selection source and set it as the selection through + wp_primary_selection_device.set_selection whenever the text selection + changes. In order to minimize calls in pointer-driven text selection, + it should happen only once after the operation finished. Similarly, + a NULL source should be set when text is unselected. + + wp_primary_selection_offer objects are first announced through the + wp_primary_selection_device.data_offer event. Immediately after this event, + the primary data offer will emit wp_primary_selection_offer.offer events + to let know of the mime types being offered. + + When the primary selection changes, the client with the keyboard focus + will receive wp_primary_selection_device.selection events. Only the client + with the keyboard focus will receive such events with a non-NULL + wp_primary_selection_offer. Across keyboard focus changes, previously + focused clients will receive wp_primary_selection_device.events with a + NULL wp_primary_selection_offer. + + In order to request the primary selection data, the client must pass + a recent serial pertaining to the press event that is triggering the + operation, if the compositor deems the serial valid and recent, the + wp_primary_selection_source.send event will happen in the other end + to let the transfer begin. The client owning the primary selection + should write the requested data, and close the file descriptor + immediately. + + If the primary selection owner client disappeared during the transfer, + the client reading the data will receive a + wp_primary_selection_device.selection event with a NULL + wp_primary_selection_offer, the client should take this as a hint + to finish the reads related to the no longer existing offer. + + The primary selection owner should be checking for errors during + writes, merely cancelling the ongoing transfer if any happened. + + + + + The primary selection device manager is a singleton global object that + provides access to the primary selection. It allows to create + wp_primary_selection_source objects, as well as retrieving the per-seat + wp_primary_selection_device objects. + + + + + Create a new primary selection source. + + + + + + + Create a new data device for a given seat. + + + + + + + + Destroy the primary selection device manager. + + + + + + + + Replaces the current selection. The previous owner of the primary + selection will receive a wp_primary_selection_source.cancelled event. + + To unset the selection, set the source to NULL. + + + + + + + + Introduces a new wp_primary_selection_offer object that may be used + to receive the current primary selection. Immediately following this + event, the new wp_primary_selection_offer object will send + wp_primary_selection_offer.offer events to describe the offered mime + types. + + + + + + + The wp_primary_selection_device.selection event is sent to notify the + client of a new primary selection. This event is sent after the + wp_primary_selection.data_offer event introducing this object, and after + the offer has announced its mimetypes through + wp_primary_selection_offer.offer. + + The data_offer is valid until a new offer or NULL is received + or until the client loses keyboard focus. The client must destroy the + previous selection data_offer, if any, upon receiving this event. + + + + + + + Destroy the primary selection device. + + + + + + + A wp_primary_selection_offer represents an offer to transfer the contents + of the primary selection clipboard to the client. Similar to + wl_data_offer, the offer also describes the mime types that the data can + be converted to and provides the mechanisms for transferring the data + directly to the client. + + + + + To transfer the contents of the primary selection clipboard, the client + issues this request and indicates the mime type that it wants to + receive. The transfer happens through the passed file descriptor + (typically created with the pipe system call). The source client writes + the data in the mime type representation requested and then closes the + file descriptor. + + The receiving client reads from the read end of the pipe until EOF and + closes its end, at which point the transfer is complete. + + + + + + + + Destroy the primary selection offer. + + + + + + Sent immediately after creating announcing the + wp_primary_selection_offer through + wp_primary_selection_device.data_offer. One event is sent per offered + mime type. + + + + + + + + The source side of a wp_primary_selection_offer, it provides a way to + describe the offered data and respond to requests to transfer the + requested contents of the primary selection clipboard. + + + + + This request adds a mime type to the set of mime types advertised to + targets. Can be called several times to offer multiple types. + + + + + + + Destroy the primary selection source. + + + + + + Request for the current primary selection contents from the client. + Send the specified mime type over the passed file descriptor, then + close it. + + + + + + + + This primary selection source is no longer valid. The client should + clean up and destroy this primary selection source. + + + + diff --git a/thirdparty/wayland-protocols/unstable/relative-pointer/README b/thirdparty/wayland-protocols/unstable/relative-pointer/README new file mode 100644 index 00000000000..64c42a126e7 --- /dev/null +++ b/thirdparty/wayland-protocols/unstable/relative-pointer/README @@ -0,0 +1,4 @@ +Relative pointer protocol + +Maintainers: +Jonas Ådahl diff --git a/thirdparty/wayland-protocols/unstable/relative-pointer/relative-pointer-unstable-v1.xml b/thirdparty/wayland-protocols/unstable/relative-pointer/relative-pointer-unstable-v1.xml new file mode 100644 index 00000000000..ca6f81d12ac --- /dev/null +++ b/thirdparty/wayland-protocols/unstable/relative-pointer/relative-pointer-unstable-v1.xml @@ -0,0 +1,136 @@ + + + + + Copyright © 2014 Jonas Ådahl + Copyright © 2015 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. + + + + This protocol specifies a set of interfaces used for making clients able to + receive relative pointer events not obstructed by barriers (such as the + monitor edge or other pointer barriers). + + To start receiving relative pointer events, a client must first bind the + global interface "wp_relative_pointer_manager" which, if a compositor + supports relative pointer motion events, is exposed by the registry. After + having created the relative pointer manager proxy object, the client uses + it to create the actual relative pointer object using the + "get_relative_pointer" request given a wl_pointer. The relative pointer + motion events will then, when applicable, be transmitted via the proxy of + the newly created relative pointer object. See the documentation of the + relative pointer interface for more details. + + 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. + + + + + A global interface used for getting the relative pointer object for a + given pointer. + + + + + Used by the client to notify the server that it will no longer use this + relative pointer manager object. + + + + + + Create a relative pointer interface given a wl_pointer object. See the + wp_relative_pointer interface for more details. + + + + + + + + + A wp_relative_pointer object is an extension to the wl_pointer interface + used for emitting relative pointer events. It shares the same focus as + wl_pointer objects of the same seat and will only emit events when it has + focus. + + + + + + + + + Relative x/y pointer motion from the pointer of the seat associated with + this object. + + A relative motion is in the same dimension as regular wl_pointer motion + events, except they do not represent an absolute position. For example, + moving a pointer from (x, y) to (x', y') would have the equivalent + relative motion (x' - x, y' - y). If a pointer motion caused the + absolute pointer position to be clipped by for example the edge of the + monitor, the relative motion is unaffected by the clipping and will + represent the unclipped motion. + + This event also contains non-accelerated motion deltas. The + non-accelerated delta is, when applicable, the regular pointer motion + delta as it was before having applied motion acceleration and other + transformations such as normalization. + + Note that the non-accelerated delta does not represent 'raw' events as + they were read from some device. Pointer motion acceleration is device- + and configuration-specific and non-accelerated deltas and accelerated + deltas may have the same value on some devices. + + Relative motions are not coupled to wl_pointer.motion events, and can be + sent in combination with such events, but also independently. There may + also be scenarios where wl_pointer.motion is sent, but there is no + relative motion. The order of an absolute and relative motion event + originating from the same physical motion is not guaranteed. + + If the client needs button events or focus state, it can receive them + from a wl_pointer object of the same seat that the wp_relative_pointer + object is associated with. + + + + + + + + + + + diff --git a/thirdparty/wayland-protocols/unstable/tablet/README b/thirdparty/wayland-protocols/unstable/tablet/README new file mode 100644 index 00000000000..7ba8e77a13a --- /dev/null +++ b/thirdparty/wayland-protocols/unstable/tablet/README @@ -0,0 +1,4 @@ +Tablet protocol + +Maintainers: +Peter Hutterer diff --git a/thirdparty/wayland-protocols/unstable/tablet/tablet-unstable-v2.xml b/thirdparty/wayland-protocols/unstable/tablet/tablet-unstable-v2.xml new file mode 100644 index 00000000000..ccbb5412a54 --- /dev/null +++ b/thirdparty/wayland-protocols/unstable/tablet/tablet-unstable-v2.xml @@ -0,0 +1,1178 @@ + + + + + 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. + + + + 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. + + + + + 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. + + + + + Get the wp_tablet_seat object for the given seat. This object + provides access to all graphics tablets in this seat. + + + + + + + + Destroy the wp_tablet_manager object. Objects created from this + object are unaffected and should be destroyed separately. + + + + + + + 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. + + + + + Destroy the wp_tablet_seat object. Objects created from this + object are unaffected and should be destroyed separately. + + + + + + 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. + + + + + + + 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. + + + + + + + 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. + + + + + + + + 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. + + + + + 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. + + + + + + + + + + This destroys the client's resource for this tool object. + + + + + + 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. + + + + + + + + + + + + + + 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. + + + + + + + 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. + + + + + + + + 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. + + + + + + + + Describes extra capabilities on a tablet. + + Any tool must provide x and y values, extra axes are + device-specific. + + + + + + + + + + + + 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. + + + + + + + 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. + + + + + + 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. + + + + + + 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. + + + + + + + + + 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. + + + + + + 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. + + + + + + + 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. + + + + + + Sent whenever a tablet tool moves. + + + + + + + + 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. + + + + + + + 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. + + + + + + + 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. + + + + + + + + Sent whenever the z-rotation axis on the tool changes. The + rotation value is in degrees clockwise from the tool's + logical neutral position. + + + + + + + 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. + + + + + + + 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. + + + + + + + + Describes the physical state of a button that produced the 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. + + + + + + + + + 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. + + + + + + + + + + + + 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. + + + + + This destroys the client's resource for this tablet object. + + + + + + This event is sent in the initial burst of events before the + wp_tablet.done event. + + + + + + + This event is sent in the initial burst of events before the + wp_tablet.done event. + + + + + + + + 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. + + + + + + + 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. + + + + + + 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. + + + + + + + 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. + + + + + 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. + + + + + + + + This destroys the client's resource for this ring object. + + + + + + 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. + + + + + + + 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. + + + + + + + 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. + + + + + + + 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. + + + + + + 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. + + + + + + + + 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. + + + + + 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. + + + + + + + + This destroys the client's resource for this strip object. + + + + + + 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. + + + + + + + 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. + + + + + + + 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. + + + + + + + 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. + + + + + + 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. + + + + + + + + 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. + + + + + Destroy the wp_tablet_pad_group object. Objects created from this object + are unaffected and should be destroyed separately. + + + + + + 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. + + + + + + + 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. + + + + + + + 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. + + + + + + + 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. + + + + + + + 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. + + + + + + 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. + + + + + + + + + + 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. + + + + + 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. + + + + + + + + + Destroy the wp_tablet_pad object. Objects created from this object + are unaffected and should be destroyed separately. + + + + + + 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. + + + + + + + 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. + + + + + + + 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. + + + + + + + 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. + + + + + + Describes the physical state of a button that caused the button + event. + + + + + + + + Sent whenever the physical state of a button changes. + + + + + + + + + Notification that this pad is focused on the specified surface. + + + + + + + + + Notification that this pad is no longer focused on the specified + surface. + + + + + + + + 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. + + + + diff --git a/thirdparty/wayland-protocols/unstable/xdg-decoration/README b/thirdparty/wayland-protocols/unstable/xdg-decoration/README new file mode 100644 index 00000000000..73f0c520448 --- /dev/null +++ b/thirdparty/wayland-protocols/unstable/xdg-decoration/README @@ -0,0 +1,4 @@ +xdg_decoration protocol + +Maintainers: +Simon Ser diff --git a/thirdparty/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml b/thirdparty/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml new file mode 100644 index 00000000000..e5967751d7f --- /dev/null +++ b/thirdparty/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml @@ -0,0 +1,156 @@ + + + + Copyright © 2018 Simon Ser + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + + This interface allows a compositor to announce support for server-side + decorations. + + A window decoration is a set of window controls as deemed appropriate by + the party managing them, such as user interface components used to move, + resize and change a window's state. + + A client can use this protocol to request being decorated by a supporting + compositor. + + If compositor and client do not negotiate the use of a server-side + decoration using this protocol, clients continue to self-decorate as they + see fit. + + 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. + + + + + Destroy the decoration manager. This doesn't destroy objects created + with the manager. + + + + + + Create a new decoration object associated with the given toplevel. + + Creating an xdg_toplevel_decoration from an xdg_toplevel which has a + buffer attached or committed is a client error, and any attempts by a + client to attach or manipulate a buffer prior to the first + xdg_toplevel_decoration.configure event must also be treated as + errors. + + + + + + + + + The decoration object allows the compositor to toggle server-side window + decorations for a toplevel surface. The client can request to switch to + another mode. + + The xdg_toplevel_decoration object must be destroyed before its + xdg_toplevel. + + + + + + + + + + + Switch back to a mode without any server-side decorations at the next + commit. + + + + + + These values describe window decoration modes. + + + + + + + + Set the toplevel surface decoration mode. This informs the compositor + that the client prefers the provided decoration mode. + + After requesting a decoration mode, the compositor will respond by + emitting an xdg_surface.configure event. The client should then update + its content, drawing it without decorations if the received mode is + server-side decorations. The client must also acknowledge the configure + when committing the new content (see xdg_surface.ack_configure). + + The compositor can decide not to use the client's mode and enforce a + different mode instead. + + Clients whose decoration mode depend on the xdg_toplevel state may send + a set_mode request in response to an xdg_surface.configure event and wait + for the next xdg_surface.configure event to prevent unwanted state. + Such clients are responsible for preventing configure loops and must + make sure not to send multiple successive set_mode requests with the + same decoration mode. + + + + + + + Unset the toplevel surface decoration mode. This informs the compositor + that the client doesn't prefer a particular decoration mode. + + This request has the same semantics as set_mode. + + + + + + The configure event asks the client to change its decoration mode. The + configured state should not be applied immediately. Clients must send an + ack_configure in response to this event. See xdg_surface.configure and + xdg_surface.ack_configure for details. + + A configure event can be sent at any time. The specified mode must be + obeyed by the client. + + + + + diff --git a/thirdparty/wayland/COPYING b/thirdparty/wayland/COPYING new file mode 100644 index 00000000000..eb25a4e2b3d --- /dev/null +++ b/thirdparty/wayland/COPYING @@ -0,0 +1,29 @@ +Copyright © 2008-2012 Kristian Høgsberg +Copyright © 2010-2012 Intel Corporation +Copyright © 2011 Benjamin Franzke +Copyright © 2012 Collabora, Ltd. + +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. + +--- + +The above is the version of the MIT "Expat" License used by X.org: + + http://cgit.freedesktop.org/xorg/xserver/tree/COPYING diff --git a/thirdparty/wayland/protocol/wayland.xml b/thirdparty/wayland/protocol/wayland.xml new file mode 100644 index 00000000000..10781cf1679 --- /dev/null +++ b/thirdparty/wayland/protocol/wayland.xml @@ -0,0 +1,3058 @@ + + + + + Copyright © 2008-2011 Kristian Høgsberg + Copyright © 2010-2011 Intel Corporation + Copyright © 2012-2013 Collabora, Ltd. + + 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. + + + + + The core global object. This is a special singleton object. It + is used for internal Wayland protocol features. + + + + + The sync request asks the server to emit the 'done' event + on the returned wl_callback object. Since requests are + handled in-order and events are delivered in-order, this can + be used as a barrier to ensure all previous requests and the + resulting events have been handled. + + The object returned by this request will be destroyed by the + compositor after the callback is fired and as such the client must not + attempt to use it after that point. + + The callback_data passed in the callback is the event serial. + + + + + + + This request creates a registry object that allows the client + to list and bind the global objects available from the + compositor. + + It should be noted that the server side resources consumed in + response to a get_registry request can only be released when the + client disconnects, not when the client side proxy is destroyed. + Therefore, clients should invoke get_registry as infrequently as + possible to avoid wasting memory. + + + + + + + The error event is sent out when a fatal (non-recoverable) + error has occurred. The object_id argument is the object + where the error occurred, most often in response to a request + to that object. The code identifies the error and is defined + by the object interface. As such, each interface defines its + own set of error codes. The message is a brief description + of the error, for (debugging) convenience. + + + + + + + + + These errors are global and can be emitted in response to any + server request. + + + + + + + + + + This event is used internally by the object ID management + logic. When a client deletes an object that it had created, + the server will send this event to acknowledge that it has + seen the delete request. When the client receives this event, + it will know that it can safely reuse the object ID. + + + + + + + + The singleton global registry object. The server has a number of + global objects that are available to all clients. These objects + typically represent an actual object in the server (for example, + an input device) or they are singleton objects that provide + extension functionality. + + When a client creates a registry object, the registry object + will emit a global event for each global currently in the + registry. Globals come and go as a result of device or + monitor hotplugs, reconfiguration or other events, and the + registry will send out global and global_remove events to + keep the client up to date with the changes. To mark the end + of the initial burst of events, the client can use the + wl_display.sync request immediately after calling + wl_display.get_registry. + + A client can bind to a global object by using the bind + request. This creates a client-side handle that lets the object + emit events to the client and lets the client invoke requests on + the object. + + + + + Binds a new, client-created object to the server using the + specified name as the identifier. + + + + + + + + Notify the client of global objects. + + The event notifies the client that a global object with + the given name is now available, and it implements the + given version of the given interface. + + + + + + + + + Notify the client of removed global objects. + + This event notifies the client that the global identified + by name is no longer available. If the client bound to + the global using the bind request, the client should now + destroy that object. + + The object remains valid and requests to the object will be + ignored until the client destroys it, to avoid races between + the global going away and a client sending a request to it. + + + + + + + + Clients can handle the 'done' event to get notified when + the related request is done. + + + + + Notify the client when the related request is done. + + + + + + + + A compositor. This object is a singleton global. The + compositor is in charge of combining the contents of multiple + surfaces into one displayable output. + + + + + Ask the compositor to create a new surface. + + + + + + + Ask the compositor to create a new region. + + + + + + + + The wl_shm_pool object encapsulates a piece of memory shared + between the compositor and client. Through the wl_shm_pool + object, the client can allocate shared memory wl_buffer objects. + All objects created through the same pool share the same + underlying mapped memory. Reusing the mapped memory avoids the + setup/teardown overhead and is useful when interactively resizing + a surface or for many small buffers. + + + + + Create a wl_buffer object from the pool. + + The buffer is created offset bytes into the pool and has + width and height as specified. The stride argument specifies + the number of bytes from the beginning of one row to the beginning + of the next. The format is the pixel format of the buffer and + must be one of those advertised through the wl_shm.format event. + + A buffer will keep a reference to the pool it was created from + so it is valid to destroy the pool immediately after creating + a buffer from it. + + + + + + + + + + + + Destroy the shared memory pool. + + The mmapped memory will be released when all + buffers that have been created from this pool + are gone. + + + + + + This request will cause the server to remap the backing memory + for the pool from the file descriptor passed when the pool was + created, but using the new size. This request can only be + used to make the pool bigger. + + This request only changes the amount of bytes that are mmapped + by the server and does not touch the file corresponding to the + file descriptor passed at creation time. It is the client's + responsibility to ensure that the file is at least as big as + the new pool size. + + + + + + + + A singleton global object that provides support for shared + memory. + + Clients can create wl_shm_pool objects using the create_pool + request. + + On binding the wl_shm object one or more format events + are emitted to inform clients about the valid pixel formats + that can be used for buffers. + + + + + These errors can be emitted in response to wl_shm requests. + + + + + + + + + This describes the memory layout of an individual pixel. + + All renderers should support argb8888 and xrgb8888 but any other + formats are optional and may not be supported by the particular + renderer in use. + + The drm format codes match the macros defined in drm_fourcc.h, except + argb8888 and xrgb8888. The formats actually supported by the compositor + will be reported by the format event. + + For all wl_shm formats and unless specified in another protocol + extension, pre-multiplied alpha is used for pixel values. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create a new wl_shm_pool object. + + The pool can be used to create shared memory based buffer + objects. The server will mmap size bytes of the passed file + descriptor, to use as backing memory for the pool. + + + + + + + + + Informs the client about a valid pixel format that + can be used for buffers. Known formats include + argb8888 and xrgb8888. + + + + + + + + A buffer provides the content for a wl_surface. Buffers are + created through factory interfaces such as wl_shm, wp_linux_buffer_params + (from the linux-dmabuf protocol extension) or similar. It has a width and + a height and can be attached to a wl_surface, but the mechanism by which a + client provides and updates the contents is defined by the buffer factory + interface. + + If the buffer uses a format that has an alpha channel, the alpha channel + is assumed to be premultiplied in the color channels unless otherwise + specified. + + + + + Destroy a buffer. If and how you need to release the backing + storage is defined by the buffer factory interface. + + For possible side-effects to a surface, see wl_surface.attach. + + + + + + Sent when this wl_buffer is no longer used by the compositor. + The client is now free to reuse or destroy this buffer and its + backing storage. + + If a client receives a release event before the frame callback + requested in the same wl_surface.commit that attaches this + wl_buffer to a surface, then the client is immediately free to + reuse the buffer and its backing storage, and does not need a + second buffer for the next surface content update. Typically + this is possible, when the compositor maintains a copy of the + wl_surface contents, e.g. as a GL texture. This is an important + optimization for GL(ES) compositors with wl_shm clients. + + + + + + + A wl_data_offer represents a piece of data offered for transfer + by another client (the source client). It is used by the + copy-and-paste and drag-and-drop mechanisms. The offer + describes the different mime types that the data can be + converted to and provides the mechanism for transferring the + data directly from the source client. + + + + + + + + + + + + Indicate that the client can accept the given mime type, or + NULL for not accepted. + + For objects of version 2 or older, this request is used by the + client to give feedback whether the client can receive the given + mime type, or NULL if none is accepted; the feedback does not + determine whether the drag-and-drop operation succeeds or not. + + For objects of version 3 or newer, this request determines the + final result of the drag-and-drop operation. If the end result + is that no mime types were accepted, the drag-and-drop operation + will be cancelled and the corresponding drag source will receive + wl_data_source.cancelled. Clients may still use this event in + conjunction with wl_data_source.action for feedback. + + + + + + + + To transfer the offered data, the client issues this request + and indicates the mime type it wants to receive. The transfer + happens through the passed file descriptor (typically created + with the pipe system call). The source client writes the data + in the mime type representation requested and then closes the + file descriptor. + + The receiving client reads from the read end of the pipe until + EOF and then closes its end, at which point the transfer is + complete. + + This request may happen multiple times for different mime types, + both before and after wl_data_device.drop. Drag-and-drop destination + clients may preemptively fetch data or examine it more closely to + determine acceptance. + + + + + + + + Destroy the data offer. + + + + + + Sent immediately after creating the wl_data_offer object. One + event per offered mime type. + + + + + + + + + Notifies the compositor that the drag destination successfully + finished the drag-and-drop operation. + + Upon receiving this request, the compositor will emit + wl_data_source.dnd_finished on the drag source client. + + It is a client error to perform other requests than + wl_data_offer.destroy after this one. It is also an error to perform + this request after a NULL mime type has been set in + wl_data_offer.accept or no action was received through + wl_data_offer.action. + + If wl_data_offer.finish request is received for a non drag and drop + operation, the invalid_finish protocol error is raised. + + + + + + Sets the actions that the destination side client supports for + this operation. This request may trigger the emission of + wl_data_source.action and wl_data_offer.action events if the compositor + needs to change the selected action. + + This request can be called multiple times throughout the + drag-and-drop operation, typically in response to wl_data_device.enter + or wl_data_device.motion events. + + This request determines the final result of the drag-and-drop + operation. If the end result is that no action is accepted, + the drag source will receive wl_data_source.cancelled. + + The dnd_actions argument must contain only values expressed in the + wl_data_device_manager.dnd_actions enum, and the preferred_action + argument must only contain one of those values set, otherwise it + will result in a protocol error. + + While managing an "ask" action, the destination drag-and-drop client + may perform further wl_data_offer.receive requests, and is expected + to perform one last wl_data_offer.set_actions request with a preferred + action other than "ask" (and optionally wl_data_offer.accept) before + requesting wl_data_offer.finish, in order to convey the action selected + by the user. If the preferred action is not in the + wl_data_offer.source_actions mask, an error will be raised. + + If the "ask" action is dismissed (e.g. user cancellation), the client + is expected to perform wl_data_offer.destroy right away. + + This request can only be made on drag-and-drop offers, a protocol error + will be raised otherwise. + + + + + + + + This event indicates the actions offered by the data source. It + will be sent right after wl_data_device.enter, or anytime the source + side changes its offered actions through wl_data_source.set_actions. + + + + + + + This event indicates the action selected by the compositor after + matching the source/destination side actions. Only one action (or + none) will be offered here. + + This event can be emitted multiple times during the drag-and-drop + operation in response to destination side action changes through + wl_data_offer.set_actions. + + This event will no longer be emitted after wl_data_device.drop + happened on the drag-and-drop destination, the client must + honor the last action received, or the last preferred one set + through wl_data_offer.set_actions when handling an "ask" action. + + Compositors may also change the selected action on the fly, mainly + in response to keyboard modifier changes during the drag-and-drop + operation. + + The most recent action received is always the valid one. Prior to + receiving wl_data_device.drop, the chosen action may change (e.g. + due to keyboard modifiers being pressed). At the time of receiving + wl_data_device.drop the drag-and-drop destination must honor the + last action received. + + Action changes may still happen after wl_data_device.drop, + especially on "ask" actions, where the drag-and-drop destination + may choose another action afterwards. Action changes happening + at this stage are always the result of inter-client negotiation, the + compositor shall no longer be able to induce a different action. + + Upon "ask" actions, it is expected that the drag-and-drop destination + may potentially choose a different action and/or mime type, + based on wl_data_offer.source_actions and finally chosen by the + user (e.g. popping up a menu with the available options). The + final wl_data_offer.set_actions and wl_data_offer.accept requests + must happen before the call to wl_data_offer.finish. + + + + + + + + The wl_data_source object is the source side of a wl_data_offer. + It is created by the source client in a data transfer and + provides a way to describe the offered data and a way to respond + to requests to transfer the data. + + + + + + + + + + This request adds a mime type to the set of mime types + advertised to targets. Can be called several times to offer + multiple types. + + + + + + + Destroy the data source. + + + + + + Sent when a target accepts pointer_focus or motion events. If + a target does not accept any of the offered types, type is NULL. + + Used for feedback during drag-and-drop. + + + + + + + Request for data from the client. Send the data as the + specified mime type over the passed file descriptor, then + close it. + + + + + + + + This data source is no longer valid. There are several reasons why + this could happen: + + - The data source has been replaced by another data source. + - The drag-and-drop operation was performed, but the drop destination + did not accept any of the mime types offered through + wl_data_source.target. + - The drag-and-drop operation was performed, but the drop destination + did not select any of the actions present in the mask offered through + wl_data_source.action. + - The drag-and-drop operation was performed but didn't happen over a + surface. + - The compositor cancelled the drag-and-drop operation (e.g. compositor + dependent timeouts to avoid stale drag-and-drop transfers). + + The client should clean up and destroy this data source. + + For objects of version 2 or older, wl_data_source.cancelled will + only be emitted if the data source was replaced by another data + source. + + + + + + + + Sets the actions that the source side client supports for this + operation. This request may trigger wl_data_source.action and + wl_data_offer.action events if the compositor needs to change the + selected action. + + The dnd_actions argument must contain only values expressed in the + wl_data_device_manager.dnd_actions enum, otherwise it will result + in a protocol error. + + This request must be made once only, and can only be made on sources + used in drag-and-drop, so it must be performed before + wl_data_device.start_drag. Attempting to use the source other than + for drag-and-drop will raise a protocol error. + + + + + + + The user performed the drop action. This event does not indicate + acceptance, wl_data_source.cancelled may still be emitted afterwards + if the drop destination does not accept any mime type. + + However, this event might however not be received if the compositor + cancelled the drag-and-drop operation before this event could happen. + + Note that the data_source may still be used in the future and should + not be destroyed here. + + + + + + The drop destination finished interoperating with this data + source, so the client is now free to destroy this data source and + free all associated data. + + If the action used to perform the operation was "move", the + source can now delete the transferred data. + + + + + + This event indicates the action selected by the compositor after + matching the source/destination side actions. Only one action (or + none) will be offered here. + + This event can be emitted multiple times during the drag-and-drop + operation, mainly in response to destination side changes through + wl_data_offer.set_actions, and as the data device enters/leaves + surfaces. + + It is only possible to receive this event after + wl_data_source.dnd_drop_performed if the drag-and-drop operation + ended in an "ask" action, in which case the final wl_data_source.action + event will happen immediately before wl_data_source.dnd_finished. + + Compositors may also change the selected action on the fly, mainly + in response to keyboard modifier changes during the drag-and-drop + operation. + + The most recent action received is always the valid one. The chosen + action may change alongside negotiation (e.g. an "ask" action can turn + into a "move" operation), so the effects of the final action must + always be applied in wl_data_offer.dnd_finished. + + Clients can trigger cursor surface changes from this point, so + they reflect the current action. + + + + + + + + There is one wl_data_device per seat which can be obtained + from the global wl_data_device_manager singleton. + + A wl_data_device provides access to inter-client data transfer + mechanisms such as copy-and-paste and drag-and-drop. + + + + + + + + + This request asks the compositor to start a drag-and-drop + operation on behalf of the client. + + The source argument is the data source that provides the data + for the eventual data transfer. If source is NULL, enter, leave + and motion events are sent only to the client that initiated the + drag and the client is expected to handle the data passing + internally. If source is destroyed, the drag-and-drop session will be + cancelled. + + The origin surface is the surface where the drag originates and + the client must have an active implicit grab that matches the + serial. + + The icon surface is an optional (can be NULL) surface that + provides an icon to be moved around with the cursor. Initially, + the top-left corner of the icon surface is placed at the cursor + hotspot, but subsequent wl_surface.attach request can move the + relative position. Attach requests must be confirmed with + wl_surface.commit as usual. The icon surface is given the role of + a drag-and-drop icon. If the icon surface already has another role, + it raises a protocol error. + + The current and pending input regions of the icon wl_surface are + cleared, and wl_surface.set_input_region is ignored until the + wl_surface is no longer used as the icon surface. When the use + as an icon ends, the current and pending input regions become + undefined, and the wl_surface is unmapped. + + + + + + + + + + This request asks the compositor to set the selection + to the data from the source on behalf of the client. + + To unset the selection, set the source to NULL. + + + + + + + + The data_offer event introduces a new wl_data_offer object, + which will subsequently be used in either the + data_device.enter event (for drag-and-drop) or the + data_device.selection event (for selections). Immediately + following the data_device.data_offer event, the new data_offer + object will send out data_offer.offer events to describe the + mime types it offers. + + + + + + + This event is sent when an active drag-and-drop pointer enters + a surface owned by the client. The position of the pointer at + enter time is provided by the x and y arguments, in surface-local + coordinates. + + + + + + + + + + + This event is sent when the drag-and-drop pointer leaves the + surface and the session ends. The client must destroy the + wl_data_offer introduced at enter time at this point. + + + + + + This event is sent when the drag-and-drop pointer moves within + the currently focused surface. The new position of the pointer + is provided by the x and y arguments, in surface-local + coordinates. + + + + + + + + + The event is sent when a drag-and-drop operation is ended + because the implicit grab is removed. + + The drag-and-drop destination is expected to honor the last action + received through wl_data_offer.action, if the resulting action is + "copy" or "move", the destination can still perform + wl_data_offer.receive requests, and is expected to end all + transfers with a wl_data_offer.finish request. + + If the resulting action is "ask", the action will not be considered + final. The drag-and-drop destination is expected to perform one last + wl_data_offer.set_actions request, or wl_data_offer.destroy in order + to cancel the operation. + + + + + + The selection event is sent out to notify the client of a new + wl_data_offer for the selection for this device. The + data_device.data_offer and the data_offer.offer events are + sent out immediately before this event to introduce the data + offer object. The selection event is sent to a client + immediately before receiving keyboard focus and when a new + selection is set while the client has keyboard focus. The + data_offer is valid until a new data_offer or NULL is received + or until the client loses keyboard focus. Switching surface with + keyboard focus within the same client doesn't mean a new selection + will be sent. The client must destroy the previous selection + data_offer, if any, upon receiving this event. + + + + + + + + + This request destroys the data device. + + + + + + + The wl_data_device_manager is a singleton global object that + provides access to inter-client data transfer mechanisms such as + copy-and-paste and drag-and-drop. These mechanisms are tied to + a wl_seat and this interface lets a client get a wl_data_device + corresponding to a wl_seat. + + Depending on the version bound, the objects created from the bound + wl_data_device_manager object will have different requirements for + functioning properly. See wl_data_source.set_actions, + wl_data_offer.accept and wl_data_offer.finish for details. + + + + + Create a new data source. + + + + + + + Create a new data device for a given seat. + + + + + + + + + + This is a bitmask of the available/preferred actions in a + drag-and-drop operation. + + In the compositor, the selected action is a result of matching the + actions offered by the source and destination sides. "action" events + with a "none" action will be sent to both source and destination if + there is no match. All further checks will effectively happen on + (source actions ∩ destination actions). + + In addition, compositors may also pick different actions in + reaction to key modifiers being pressed. One common design that + is used in major toolkits (and the behavior recommended for + compositors) is: + + - If no modifiers are pressed, the first match (in bit order) + will be used. + - Pressing Shift selects "move", if enabled in the mask. + - Pressing Control selects "copy", if enabled in the mask. + + Behavior beyond that is considered implementation-dependent. + Compositors may for example bind other modifiers (like Alt/Meta) + or drags initiated with other buttons than BTN_LEFT to specific + actions (e.g. "ask"). + + + + + + + + + + + This interface is implemented by servers that provide + desktop-style user interfaces. + + It allows clients to associate a wl_shell_surface with + a basic surface. + + Note! This protocol is deprecated and not intended for production use. + For desktop-style user interfaces, use xdg_shell. Compositors and clients + should not implement this interface. + + + + + + + + + Create a shell surface for an existing surface. This gives + the wl_surface the role of a shell surface. If the wl_surface + already has another role, it raises a protocol error. + + Only one shell surface can be associated with a given surface. + + + + + + + + + An interface that may be implemented by a wl_surface, for + implementations that provide a desktop-style user interface. + + It provides requests to treat surfaces like toplevel, fullscreen + or popup windows, move, resize or maximize them, associate + metadata like title and class, etc. + + On the server side the object is automatically destroyed when + the related wl_surface is destroyed. On the client side, + wl_shell_surface_destroy() must be called before destroying + the wl_surface object. + + + + + A client must respond to a ping event with a pong request or + the client may be deemed unresponsive. + + + + + + + Start a pointer-driven move of the surface. + + This request must be used in response to a button press event. + The server may ignore move requests depending on the state of + the surface (e.g. fullscreen or maximized). + + + + + + + + These values are used to indicate which edge of a surface + is being dragged in a resize operation. The server may + use this information to adapt its behavior, e.g. choose + an appropriate cursor image. + + + + + + + + + + + + + + + Start a pointer-driven resizing of the surface. + + This request must be used in response to a button press event. + The server may ignore resize requests depending on the state of + the surface (e.g. fullscreen or maximized). + + + + + + + + + Map the surface as a toplevel surface. + + A toplevel surface is not fullscreen, maximized or transient. + + + + + + These flags specify details of the expected behaviour + of transient surfaces. Used in the set_transient request. + + + + + + + Map the surface relative to an existing surface. + + The x and y arguments specify the location of the upper left + corner of the surface relative to the upper left corner of the + parent surface, in surface-local coordinates. + + The flags argument controls details of the transient behaviour. + + + + + + + + + + Hints to indicate to the compositor how to deal with a conflict + between the dimensions of the surface and the dimensions of the + output. The compositor is free to ignore this parameter. + + + + + + + + + + Map the surface as a fullscreen surface. + + If an output parameter is given then the surface will be made + fullscreen on that output. If the client does not specify the + output then the compositor will apply its policy - usually + choosing the output on which the surface has the biggest surface + area. + + The client may specify a method to resolve a size conflict + between the output size and the surface size - this is provided + through the method parameter. + + The framerate parameter is used only when the method is set + to "driver", to indicate the preferred framerate. A value of 0 + indicates that the client does not care about framerate. The + framerate is specified in mHz, that is framerate of 60000 is 60Hz. + + A method of "scale" or "driver" implies a scaling operation of + the surface, either via a direct scaling operation or a change of + the output mode. This will override any kind of output scaling, so + that mapping a surface with a buffer size equal to the mode can + fill the screen independent of buffer_scale. + + A method of "fill" means we don't scale up the buffer, however + any output scale is applied. This means that you may run into + an edge case where the application maps a buffer with the same + size of the output mode but buffer_scale 1 (thus making a + surface larger than the output). In this case it is allowed to + downscale the results to fit the screen. + + The compositor must reply to this request with a configure event + with the dimensions for the output on which the surface will + be made fullscreen. + + + + + + + + + Map the surface as a popup. + + A popup surface is a transient surface with an added pointer + grab. + + An existing implicit grab will be changed to owner-events mode, + and the popup grab will continue after the implicit grab ends + (i.e. releasing the mouse button does not cause the popup to + be unmapped). + + The popup grab continues until the window is destroyed or a + mouse button is pressed in any other client's window. A click + in any of the client's surfaces is reported as normal, however, + clicks in other clients' surfaces will be discarded and trigger + the callback. + + The x and y arguments specify the location of the upper left + corner of the surface relative to the upper left corner of the + parent surface, in surface-local coordinates. + + + + + + + + + + + + Map the surface as a maximized surface. + + If an output parameter is given then the surface will be + maximized on that output. If the client does not specify the + output then the compositor will apply its policy - usually + choosing the output on which the surface has the biggest surface + area. + + The compositor will reply with a configure event telling + the expected new surface size. The operation is completed + on the next buffer attach to this surface. + + A maximized surface typically fills the entire output it is + bound to, except for desktop elements such as panels. This is + the main difference between a maximized shell surface and a + fullscreen shell surface. + + The details depend on the compositor implementation. + + + + + + + Set a short title for the surface. + + This string may be used to identify the surface in a task bar, + window list, or other user interface elements provided by the + compositor. + + The string must be encoded in UTF-8. + + + + + + + Set a class for the surface. + + The surface class identifies the general class of applications + to which the surface belongs. A common convention is to use the + file name (or the full path if it is a non-standard location) of + the application's .desktop file as the class. + + + + + + + Ping a client to check if it is receiving events and sending + requests. A client is expected to reply with a pong request. + + + + + + + The configure event asks the client to resize its surface. + + The size is a hint, in the sense that the client is free to + ignore it if it doesn't resize, pick a smaller size (to + satisfy aspect ratio or resize in steps of NxM pixels). + + The edges parameter provides a hint about how the surface + was resized. The client may use this information to decide + how to adjust its content to the new size (e.g. a scrolling + area might adjust its content position to leave the viewable + content unmoved). + + The client is free to dismiss all but the last configure + event it received. + + The width and height arguments specify the size of the window + in surface-local coordinates. + + + + + + + + + The popup_done event is sent out when a popup grab is broken, + that is, when the user clicks a surface that doesn't belong + to the client owning the popup surface. + + + + + + + A surface is a rectangular area that may be displayed on zero + or more outputs, and shown any number of times at the compositor's + discretion. They can present wl_buffers, receive user input, and + define a local coordinate system. + + The size of a surface (and relative positions on it) is described + in surface-local coordinates, which may differ from the buffer + coordinates of the pixel content, in case a buffer_transform + or a buffer_scale is used. + + A surface without a "role" is fairly useless: a compositor does + not know where, when or how to present it. The role is the + purpose of a wl_surface. Examples of roles are a cursor for a + pointer (as set by wl_pointer.set_cursor), a drag icon + (wl_data_device.start_drag), a sub-surface + (wl_subcompositor.get_subsurface), and a window as defined by a + shell protocol (e.g. wl_shell.get_shell_surface). + + A surface can have only one role at a time. Initially a + wl_surface does not have a role. Once a wl_surface is given a + role, it is set permanently for the whole lifetime of the + wl_surface object. Giving the current role again is allowed, + unless explicitly forbidden by the relevant interface + specification. + + Surface roles are given by requests in other interfaces such as + wl_pointer.set_cursor. The request should explicitly mention + that this request gives a role to a wl_surface. Often, this + request also creates a new protocol object that represents the + role and adds additional functionality to wl_surface. When a + client wants to destroy a wl_surface, they must destroy this 'role + object' before the wl_surface. + + Destroying the role object does not remove the role from the + wl_surface, but it may stop the wl_surface from "playing the role". + For instance, if a wl_subsurface object is destroyed, the wl_surface + it was created for will be unmapped and forget its position and + z-order. It is allowed to create a wl_subsurface for the same + wl_surface again, but it is not allowed to use the wl_surface as + a cursor (cursor is a different role than sub-surface, and role + switching is not allowed). + + + + + These errors can be emitted in response to wl_surface requests. + + + + + + + + + + Deletes the surface and invalidates its object ID. + + + + + + Set a buffer as the content of this surface. + + The new size of the surface is calculated based on the buffer + size transformed by the inverse buffer_transform and the + inverse buffer_scale. This means that at commit time the supplied + buffer size must be an integer multiple of the buffer_scale. If + that's not the case, an invalid_size error is sent. + + The x and y arguments specify the location of the new pending + buffer's upper left corner, relative to the current buffer's upper + left corner, in surface-local coordinates. In other words, the + x and y, combined with the new surface size define in which + directions the surface's size changes. Setting anything other than 0 + as x and y arguments is discouraged, and should instead be replaced + with using the separate wl_surface.offset request. + + When the bound wl_surface version is 5 or higher, passing any + non-zero x or y is a protocol violation, and will result in an + 'invalid_offset' error being raised. To achieve equivalent semantics, + use wl_surface.offset. + + Surface contents are double-buffered state, see wl_surface.commit. + + The initial surface contents are void; there is no content. + wl_surface.attach assigns the given wl_buffer as the pending + wl_buffer. wl_surface.commit makes the pending wl_buffer the new + surface contents, and the size of the surface becomes the size + calculated from the wl_buffer, as described above. After commit, + there is no pending buffer until the next attach. + + Committing a pending wl_buffer allows the compositor to read the + pixels in the wl_buffer. The compositor may access the pixels at + any time after the wl_surface.commit request. When the compositor + will not access the pixels anymore, it will send the + wl_buffer.release event. Only after receiving wl_buffer.release, + the client may reuse the wl_buffer. A wl_buffer that has been + attached and then replaced by another attach instead of committed + will not receive a release event, and is not used by the + compositor. + + If a pending wl_buffer has been committed to more than one wl_surface, + the delivery of wl_buffer.release events becomes undefined. A well + behaved client should not rely on wl_buffer.release events in this + case. Alternatively, a client could create multiple wl_buffer objects + from the same backing storage or use wp_linux_buffer_release. + + Destroying the wl_buffer after wl_buffer.release does not change + the surface contents. Destroying the wl_buffer before wl_buffer.release + is allowed as long as the underlying buffer storage isn't re-used (this + can happen e.g. on client process termination). However, if the client + destroys the wl_buffer before receiving the wl_buffer.release event and + mutates the underlying buffer storage, the surface contents become + undefined immediately. + + If wl_surface.attach is sent with a NULL wl_buffer, the + following wl_surface.commit will remove the surface content. + + + + + + + + + This request is used to describe the regions where the pending + buffer is different from the current surface contents, and where + the surface therefore needs to be repainted. The compositor + ignores the parts of the damage that fall outside of the surface. + + Damage is double-buffered state, see wl_surface.commit. + + The damage rectangle is specified in surface-local coordinates, + where x and y specify the upper left corner of the damage rectangle. + + The initial value for pending damage is empty: no damage. + wl_surface.damage adds pending damage: the new pending damage + is the union of old pending damage and the given rectangle. + + wl_surface.commit assigns pending damage as the current damage, + and clears pending damage. The server will clear the current + damage as it repaints the surface. + + Note! New clients should not use this request. Instead damage can be + posted with wl_surface.damage_buffer which uses buffer coordinates + instead of surface coordinates. + + + + + + + + + + Request a notification when it is a good time to start drawing a new + frame, by creating a frame callback. This is useful for throttling + redrawing operations, and driving animations. + + When a client is animating on a wl_surface, it can use the 'frame' + request to get notified when it is a good time to draw and commit the + next frame of animation. If the client commits an update earlier than + that, it is likely that some updates will not make it to the display, + and the client is wasting resources by drawing too often. + + The frame request will take effect on the next wl_surface.commit. + The notification will only be posted for one frame unless + requested again. For a wl_surface, the notifications are posted in + the order the frame requests were committed. + + The server must send the notifications so that a client + will not send excessive updates, while still allowing + the highest possible update rate for clients that wait for the reply + before drawing again. The server should give some time for the client + to draw and commit after sending the frame callback events to let it + hit the next output refresh. + + A server should avoid signaling the frame callbacks if the + surface is not visible in any way, e.g. the surface is off-screen, + or completely obscured by other opaque surfaces. + + The object returned by this request will be destroyed by the + compositor after the callback is fired and as such the client must not + attempt to use it after that point. + + The callback_data passed in the callback is the current time, in + milliseconds, with an undefined base. + + + + + + + This request sets the region of the surface that contains + opaque content. + + The opaque region is an optimization hint for the compositor + that lets it optimize the redrawing of content behind opaque + regions. Setting an opaque region is not required for correct + behaviour, but marking transparent content as opaque will result + in repaint artifacts. + + The opaque region is specified in surface-local coordinates. + + The compositor ignores the parts of the opaque region that fall + outside of the surface. + + Opaque region is double-buffered state, see wl_surface.commit. + + wl_surface.set_opaque_region changes the pending opaque region. + wl_surface.commit copies the pending region to the current region. + Otherwise, the pending and current regions are never changed. + + The initial value for an opaque region is empty. Setting the pending + opaque region has copy semantics, and the wl_region object can be + destroyed immediately. A NULL wl_region causes the pending opaque + region to be set to empty. + + + + + + + This request sets the region of the surface that can receive + pointer and touch events. + + Input events happening outside of this region will try the next + surface in the server surface stack. The compositor ignores the + parts of the input region that fall outside of the surface. + + The input region is specified in surface-local coordinates. + + Input region is double-buffered state, see wl_surface.commit. + + wl_surface.set_input_region changes the pending input region. + wl_surface.commit copies the pending region to the current region. + Otherwise the pending and current regions are never changed, + except cursor and icon surfaces are special cases, see + wl_pointer.set_cursor and wl_data_device.start_drag. + + The initial value for an input region is infinite. That means the + whole surface will accept input. Setting the pending input region + has copy semantics, and the wl_region object can be destroyed + immediately. A NULL wl_region causes the input region to be set + to infinite. + + + + + + + Surface state (input, opaque, and damage regions, attached buffers, + etc.) is double-buffered. Protocol requests modify the pending state, + as opposed to the current state in use by the compositor. A commit + request atomically applies all pending state, replacing the current + state. After commit, the new pending state is as documented for each + related request. + + On commit, a pending wl_buffer is applied first, and all other state + second. This means that all coordinates in double-buffered state are + relative to the new wl_buffer coming into use, except for + wl_surface.attach itself. If there is no pending wl_buffer, the + coordinates are relative to the current surface contents. + + All requests that need a commit to become effective are documented + to affect double-buffered state. + + Other interfaces may add further double-buffered surface state. + + + + + + This is emitted whenever a surface's creation, movement, or resizing + results in some part of it being within the scanout region of an + output. + + Note that a surface may be overlapping with zero or more outputs. + + + + + + + This is emitted whenever a surface's creation, movement, or resizing + results in it no longer having any part of it within the scanout region + of an output. + + Clients should not use the number of outputs the surface is on for frame + throttling purposes. The surface might be hidden even if no leave event + has been sent, and the compositor might expect new surface content + updates even if no enter event has been sent. The frame event should be + used instead. + + + + + + + + + This request sets an optional transformation on how the compositor + interprets the contents of the buffer attached to the surface. The + accepted values for the transform parameter are the values for + wl_output.transform. + + Buffer transform is double-buffered state, see wl_surface.commit. + + A newly created surface has its buffer transformation set to normal. + + wl_surface.set_buffer_transform changes the pending buffer + transformation. wl_surface.commit copies the pending buffer + transformation to the current one. Otherwise, the pending and current + values are never changed. + + The purpose of this request is to allow clients to render content + according to the output transform, thus permitting the compositor to + use certain optimizations even if the display is rotated. Using + hardware overlays and scanning out a client buffer for fullscreen + surfaces are examples of such optimizations. Those optimizations are + highly dependent on the compositor implementation, so the use of this + request should be considered on a case-by-case basis. + + Note that if the transform value includes 90 or 270 degree rotation, + the width of the buffer will become the surface height and the height + of the buffer will become the surface width. + + If transform is not one of the values from the + wl_output.transform enum the invalid_transform protocol error + is raised. + + + + + + + + + This request sets an optional scaling factor on how the compositor + interprets the contents of the buffer attached to the window. + + Buffer scale is double-buffered state, see wl_surface.commit. + + A newly created surface has its buffer scale set to 1. + + wl_surface.set_buffer_scale changes the pending buffer scale. + wl_surface.commit copies the pending buffer scale to the current one. + Otherwise, the pending and current values are never changed. + + The purpose of this request is to allow clients to supply higher + resolution buffer data for use on high resolution outputs. It is + intended that you pick the same buffer scale as the scale of the + output that the surface is displayed on. This means the compositor + can avoid scaling when rendering the surface on that output. + + Note that if the scale is larger than 1, then you have to attach + a buffer that is larger (by a factor of scale in each dimension) + than the desired surface size. + + If scale is not positive the invalid_scale protocol error is + raised. + + + + + + + + This request is used to describe the regions where the pending + buffer is different from the current surface contents, and where + the surface therefore needs to be repainted. The compositor + ignores the parts of the damage that fall outside of the surface. + + Damage is double-buffered state, see wl_surface.commit. + + The damage rectangle is specified in buffer coordinates, + where x and y specify the upper left corner of the damage rectangle. + + The initial value for pending damage is empty: no damage. + wl_surface.damage_buffer adds pending damage: the new pending + damage is the union of old pending damage and the given rectangle. + + wl_surface.commit assigns pending damage as the current damage, + and clears pending damage. The server will clear the current + damage as it repaints the surface. + + This request differs from wl_surface.damage in only one way - it + takes damage in buffer coordinates instead of surface-local + coordinates. While this generally is more intuitive than surface + coordinates, it is especially desirable when using wp_viewport + or when a drawing library (like EGL) is unaware of buffer scale + and buffer transform. + + Note: Because buffer transformation changes and damage requests may + be interleaved in the protocol stream, it is impossible to determine + the actual mapping between surface and buffer damage until + wl_surface.commit time. Therefore, compositors wishing to take both + kinds of damage into account will have to accumulate damage from the + two requests separately and only transform from one to the other + after receiving the wl_surface.commit. + + + + + + + + + + + + The x and y arguments specify the location of the new pending + buffer's upper left corner, relative to the current buffer's upper + left corner, in surface-local coordinates. In other words, the + x and y, combined with the new surface size define in which + directions the surface's size changes. + + Surface location offset is double-buffered state, see + wl_surface.commit. + + This request is semantically equivalent to and the replaces the x and y + arguments in the wl_surface.attach request in wl_surface versions prior + to 5. See wl_surface.attach for details. + + + + + + + + + A seat is a group of keyboards, pointer and touch devices. This + object is published as a global during start up, or when such a + device is hot plugged. A seat typically has a pointer and + maintains a keyboard focus and a pointer focus. + + + + + This is a bitmask of capabilities this seat has; if a member is + set, then it is present on the seat. + + + + + + + + + These errors can be emitted in response to wl_seat requests. + + + + + + + This is emitted whenever a seat gains or loses the pointer, + keyboard or touch capabilities. The argument is a capability + enum containing the complete set of capabilities this seat has. + + When the pointer capability is added, a client may create a + wl_pointer object using the wl_seat.get_pointer request. This object + will receive pointer events until the capability is removed in the + future. + + When the pointer capability is removed, a client should destroy the + wl_pointer objects associated with the seat where the capability was + removed, using the wl_pointer.release request. No further pointer + events will be received on these objects. + + In some compositors, if a seat regains the pointer capability and a + client has a previously obtained wl_pointer object of version 4 or + less, that object may start sending pointer events again. This + behavior is considered a misinterpretation of the intended behavior + and must not be relied upon by the client. wl_pointer objects of + version 5 or later must not send events if created before the most + recent event notifying the client of an added pointer capability. + + The above behavior also applies to wl_keyboard and wl_touch with the + keyboard and touch capabilities, respectively. + + + + + + + The ID provided will be initialized to the wl_pointer interface + for this seat. + + This request only takes effect if the seat has the pointer + capability, or has had the pointer capability in the past. + It is a protocol violation to issue this request on a seat that has + never had the pointer capability. The missing_capability error will + be sent in this case. + + + + + + + The ID provided will be initialized to the wl_keyboard interface + for this seat. + + This request only takes effect if the seat has the keyboard + capability, or has had the keyboard capability in the past. + It is a protocol violation to issue this request on a seat that has + never had the keyboard capability. The missing_capability error will + be sent in this case. + + + + + + + The ID provided will be initialized to the wl_touch interface + for this seat. + + This request only takes effect if the seat has the touch + capability, or has had the touch capability in the past. + It is a protocol violation to issue this request on a seat that has + never had the touch capability. The missing_capability error will + be sent in this case. + + + + + + + + + In a multi-seat configuration the seat name can be used by clients to + help identify which physical devices the seat represents. + + The seat name is a UTF-8 string with no convention defined for its + contents. Each name is unique among all wl_seat globals. The name is + only guaranteed to be unique for the current compositor instance. + + The same seat names are used for all clients. Thus, the name can be + shared across processes to refer to a specific wl_seat global. + + The name event is sent after binding to the seat global. This event is + only sent once per seat object, and the name does not change over the + lifetime of the wl_seat global. + + Compositors may re-use the same seat name if the wl_seat global is + destroyed and re-created later. + + + + + + + + + Using this request a client can tell the server that it is not going to + use the seat object anymore. + + + + + + + + The wl_pointer interface represents one or more input devices, + such as mice, which control the pointer location and pointer_focus + of a seat. + + The wl_pointer interface generates motion, enter and leave + events for the surfaces that the pointer is located over, + and button and axis events for button presses, button releases + and scrolling. + + + + + + + + + Set the pointer surface, i.e., the surface that contains the + pointer image (cursor). This request gives the surface the role + of a cursor. If the surface already has another role, it raises + a protocol error. + + The cursor actually changes only if the pointer + focus for this device is 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 pointer 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. + + The serial parameter must match the latest wl_pointer.enter + serial number sent to the client. Otherwise the request will be + ignored. + + + + + + + + + + Notification that this seat's pointer is focused on a certain + surface. + + When a seat's focus enters a surface, the pointer image + is undefined and a client should respond to this event by setting + an appropriate pointer image with the set_cursor request. + + + + + + + + + + Notification that this seat's pointer is no longer focused on + a certain surface. + + The leave notification is sent before the enter notification + for the new focus. + + + + + + + + Notification of pointer location change. The arguments + surface_x and surface_y are the location relative to the + focused surface. + + + + + + + + + Describes the physical state of a button that produced the button + event. + + + + + + + + Mouse button click and release notifications. + + The location of the click is given by the last motion or + enter event. + The time argument is a timestamp with millisecond + granularity, with an undefined base. + + The button is a button code as defined in the Linux kernel's + linux/input-event-codes.h header file, e.g. BTN_LEFT. + + Any 16-bit button code value is reserved for future additions to the + kernel's event code list. All other button codes above 0xFFFF are + currently undefined but may be used in future versions of this + protocol. + + + + + + + + + + Describes the axis types of scroll events. + + + + + + + + Scroll and other axis notifications. + + For scroll events (vertical and horizontal scroll axes), the + value parameter is the length of a vector along the specified + axis in a coordinate space identical to those of motion events, + representing a relative movement along the specified axis. + + For devices that support movements non-parallel to axes multiple + axis events will be emitted. + + When applicable, for example for touch pads, the server can + choose to emit scroll events where the motion vector is + equivalent to a motion event vector. + + When applicable, a client can transform its content relative to the + scroll distance. + + + + + + + + + + + Using this request a client can tell the server that it is not going to + use the pointer object anymore. + + This request destroys the pointer proxy object, so clients must not call + wl_pointer_destroy() after using this request. + + + + + + + + Indicates the end of a set of events that logically belong together. + A client is expected to accumulate the data in all events within the + frame before proceeding. + + All wl_pointer events before a wl_pointer.frame event belong + logically together. For example, in a diagonal scroll motion the + compositor will send an optional wl_pointer.axis_source event, two + wl_pointer.axis events (horizontal and vertical) and finally a + wl_pointer.frame event. The client may use this information to + calculate a diagonal vector for scrolling. + + When multiple wl_pointer.axis events occur within the same frame, + the motion vector is the combined motion of all events. + When a wl_pointer.axis and a wl_pointer.axis_stop event occur within + the same frame, this indicates that axis movement in one axis has + stopped but continues in the other axis. + When multiple wl_pointer.axis_stop events occur within the same + frame, this indicates that these axes stopped in the same instance. + + A wl_pointer.frame event is sent for every logical event group, + even if the group only contains a single wl_pointer event. + Specifically, a client may get a sequence: motion, frame, button, + frame, axis, frame, axis_stop, frame. + + The wl_pointer.enter and wl_pointer.leave events are logical events + generated by the compositor and not the hardware. These events are + also grouped by a wl_pointer.frame. When a pointer moves from one + surface to another, a compositor should group the + wl_pointer.leave event within the same wl_pointer.frame. + However, a client must not rely on wl_pointer.leave and + wl_pointer.enter being in the same wl_pointer.frame. + Compositor-specific policies may require the wl_pointer.leave and + wl_pointer.enter event being split across multiple wl_pointer.frame + groups. + + + + + + Describes the source types for axis events. This indicates to the + client how an axis event was physically generated; a client may + adjust the user interface accordingly. For example, scroll events + from a "finger" source may be in a smooth coordinate space with + kinetic scrolling whereas a "wheel" source may be in discrete steps + of a number of lines. + + The "continuous" axis source is a device generating events in a + continuous coordinate space, but using something other than a + finger. One example for this source is button-based scrolling where + the vertical motion of a device is converted to scroll events while + a button is held down. + + The "wheel tilt" axis source indicates that the actual device is a + wheel but the scroll event is not caused by a rotation but a + (usually sideways) tilt of the wheel. + + + + + + + + + + Source information for scroll and other axes. + + This event does not occur on its own. It is sent before a + wl_pointer.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 + wl_pointer.axis_source.finger, a wl_pointer.axis_stop event will be + sent when the user lifts the finger off the device. + + If the source is wl_pointer.axis_source.wheel, + wl_pointer.axis_source.wheel_tilt or + wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event may + or may not be sent. Whether a compositor sends an axis_stop event + for these sources is hardware-specific and implementation-dependent; + clients must not rely on receiving an axis_stop event for these + scroll sources and should treat scroll sequences from these scroll + sources as unterminated by default. + + This event is optional. If the source is unknown for a particular + axis event sequence, no event is sent. + Only one wl_pointer.axis_source event is permitted per frame. + + The order of wl_pointer.axis_discrete and wl_pointer.axis_source is + not guaranteed. + + + + + + + Stop notification for scroll and other axes. + + For some wl_pointer.axis_source types, a wl_pointer.axis_stop event + is sent to notify a client that the axis sequence has terminated. + This enables the client to implement kinetic scrolling. + See the wl_pointer.axis_source documentation for information on when + this event may be generated. + + Any wl_pointer.axis events with the same axis_source after this + event should be considered as the start of a new axis motion. + + The timestamp is to be interpreted identical to the timestamp in the + wl_pointer.axis event. The timestamp value may be the same as a + preceding wl_pointer.axis event. + + + + + + + + Discrete step information for scroll and other axes. + + This event carries the axis value of the wl_pointer.axis event in + discrete steps (e.g. mouse wheel clicks). + + This event is deprecated with wl_pointer version 8 - this event is not + sent to clients supporting version 8 or later. + + This event does not occur on its own, it is coupled with a + wl_pointer.axis event that represents this axis value on a + continuous scale. The protocol guarantees that each axis_discrete + event is always followed by exactly one axis event with the same + axis number within the same wl_pointer.frame. Note that the protocol + allows for other events to occur between the axis_discrete and + its coupled axis event, including other axis_discrete or axis + events. A wl_pointer.frame must not contain more than one axis_discrete + event per axis type. + + This event is optional; continuous scrolling devices + like two-finger scrolling on touchpads do not have discrete + steps and do not generate this event. + + The discrete value carries the directional information. e.g. a value + of -2 is two steps towards the negative direction of this axis. + + The axis number is identical to the axis number in the associated + axis event. + + The order of wl_pointer.axis_discrete and wl_pointer.axis_source is + not guaranteed. + + + + + + + + Discrete high-resolution scroll information. + + This event carries high-resolution wheel scroll information, + with each multiple of 120 representing one logical scroll step + (a wheel detent). For example, an axis_value120 of 30 is one quarter of + a logical scroll step in the positive direction, a value120 of + -240 are two logical scroll steps in the negative direction within the + same hardware event. + Clients that rely on discrete scrolling should accumulate the + value120 to multiples of 120 before processing the event. + + The value120 must not be zero. + + This event replaces the wl_pointer.axis_discrete event in clients + supporting wl_pointer version 8 or later. + + Where a wl_pointer.axis_source event occurs in the same + wl_pointer.frame, the axis source applies to this event. + + The order of wl_pointer.axis_value120 and wl_pointer.axis_source is + not guaranteed. + + + + + + + + + The wl_keyboard interface represents one or more keyboards + associated with a seat. + + + + + This specifies the format of the keymap provided to the + client with the wl_keyboard.keymap event. + + + + + + + + This event provides a file descriptor to the client which can be + memory-mapped in read-only mode to provide a keyboard mapping + description. + + From version 7 onwards, the fd must be mapped with MAP_PRIVATE by + the recipient, as MAP_SHARED may fail. + + + + + + + + + Notification that this seat's keyboard focus is on a certain + surface. + + The compositor must send the wl_keyboard.modifiers event after this + event. + + + + + + + + + Notification that this seat's keyboard focus is no longer on + a certain surface. + + The leave notification is sent before the enter notification + for the new focus. + + After this event client must assume that all keys, including modifiers, + are lifted and also it must stop key repeating if there's some going on. + + + + + + + + Describes the physical state of a key that produced the key event. + + + + + + + + A key was pressed or released. + The time argument is a timestamp with millisecond + granularity, with an undefined base. + + The key is a platform-specific key code that can be interpreted + by feeding it to the keyboard mapping (see the keymap event). + + If this event produces a change in modifiers, then the resulting + wl_keyboard.modifiers event must be sent after this event. + + + + + + + + + + Notifies clients that the modifier and/or group state has + changed, and it should update its local state. + + + + + + + + + + + + + + + + + + + Informs the client about the keyboard's repeat rate and delay. + + This event is sent as soon as the wl_keyboard object has been created, + and is guaranteed to be received by the client before any key press + event. + + Negative values for either rate or delay are illegal. A rate of zero + will disable any repeating (regardless of the value of delay). + + This event can be sent later on as well with a new value if necessary, + so clients should continue listening for the event past the creation + of wl_keyboard. + + + + + + + + + The wl_touch interface represents a touchscreen + associated with a seat. + + Touch interactions can consist of one or more contacts. + For each contact, a series of events is generated, starting + with a down event, followed by zero or more motion events, + and ending with an up event. Events relating to the same + contact point can be identified by the ID of the sequence. + + + + + A new touch point has appeared on the surface. This touch point is + assigned a unique ID. Future events from this touch point reference + this ID. The ID ceases to be valid after a touch up event and may be + reused in the future. + + + + + + + + + + + + The touch point has disappeared. No further events will be sent for + this touch point and the touch point's ID is released and may be + reused in a future touch down event. + + + + + + + + + A touch point has changed coordinates. + + + + + + + + + + Indicates the end of a set of events that logically belong together. + A client is expected to accumulate the data in all events within the + frame before proceeding. + + A wl_touch.frame terminates at least one event but otherwise no + guarantee is provided about the set of events within a frame. A client + must assume that any state not updated in a frame is unchanged from the + previously known state. + + + + + + Sent if the compositor decides the touch stream is a global + gesture. No further events are sent to the clients from that + particular gesture. Touch cancellation applies to all touch points + currently active on this client's surface. The client is + responsible for finalizing the touch points, future touch points on + this surface may reuse the touch point ID. + + + + + + + + + + + + + + Sent when a touchpoint has changed its shape. + + This event does not occur on its own. It is sent before a + wl_touch.frame event and carries the new shape information for + any previously reported, or new touch points of that frame. + + Other events describing the touch point such as wl_touch.down, + wl_touch.motion or wl_touch.orientation may be sent within the + same wl_touch.frame. A client should treat these events as a single + logical touch point update. The order of wl_touch.shape, + wl_touch.orientation and wl_touch.motion is not guaranteed. + A wl_touch.down event is guaranteed to occur before the first + wl_touch.shape event for this touch ID but both events may occur within + the same wl_touch.frame. + + A touchpoint shape is approximated by an ellipse through the major and + minor axis length. The major axis length describes the longer diameter + of the ellipse, while the minor axis length describes the shorter + diameter. Major and minor are orthogonal and both are specified in + surface-local coordinates. The center of the ellipse is always at the + touchpoint location as reported by wl_touch.down or wl_touch.move. + + This event is only sent by the compositor if the touch device supports + shape reports. The client has to make reasonable assumptions about the + shape if it did not receive this event. + + + + + + + + + Sent when a touchpoint has changed its orientation. + + This event does not occur on its own. It is sent before a + wl_touch.frame event and carries the new shape information for + any previously reported, or new touch points of that frame. + + Other events describing the touch point such as wl_touch.down, + wl_touch.motion or wl_touch.shape may be sent within the + same wl_touch.frame. A client should treat these events as a single + logical touch point update. The order of wl_touch.shape, + wl_touch.orientation and wl_touch.motion is not guaranteed. + A wl_touch.down event is guaranteed to occur before the first + wl_touch.orientation event for this touch ID but both events may occur + within the same wl_touch.frame. + + The orientation describes the clockwise angle of a touchpoint's major + axis to the positive surface y-axis and is normalized to the -180 to + +180 degree range. The granularity of orientation depends on the touch + device, some devices only support binary rotation values between 0 and + 90 degrees. + + This event is only sent by the compositor if the touch device supports + orientation reports. + + + + + + + + + An output describes part of the compositor geometry. The + compositor works in the 'compositor coordinate system' and an + output corresponds to a rectangular area in that space that is + actually visible. This typically corresponds to a monitor that + displays part of the compositor space. This object is published + as global during start up, or when a monitor is hotplugged. + + + + + This enumeration describes how the physical + pixels on an output are laid out. + + + + + + + + + + + + This describes the transform that a compositor will apply to a + surface to compensate for the rotation or mirroring of an + output device. + + The flipped values correspond to an initial flip around a + vertical axis followed by rotation. + + The purpose is mainly to allow clients to render accordingly and + tell the compositor, so that for fullscreen surfaces, the + compositor will still be able to scan out directly from client + surfaces. + + + + + + + + + + + + + + The geometry event describes geometric properties of the output. + The event is sent when binding to the output object and whenever + any of the properties change. + + The physical size can be set to zero if it doesn't make sense for this + output (e.g. for projectors or virtual outputs). + + The geometry event will be followed by a done event (starting from + version 2). + + Note: wl_output only advertises partial information about the output + position and identification. Some compositors, for instance those not + implementing a desktop-style output layout or those exposing virtual + outputs, might fake this information. Instead of using x and y, clients + should use xdg_output.logical_position. Instead of using make and model, + clients should use name and description. + + + + + + + + + + + + + + These flags describe properties of an output mode. + They are used in the flags bitfield of the mode event. + + + + + + + + The mode event describes an available mode for the output. + + The event is sent when binding to the output object and there + will always be one mode, the current mode. The event is sent + again if an output changes mode, for the mode that is now + current. In other words, the current mode is always the last + mode that was received with the current flag set. + + Non-current modes are deprecated. A compositor can decide to only + advertise the current mode and never send other modes. Clients + should not rely on non-current modes. + + The size of a mode is given in physical hardware units of + the output device. This is not necessarily the same as + the output size in the global compositor space. For instance, + the output may be scaled, as described in wl_output.scale, + or transformed, as described in wl_output.transform. Clients + willing to retrieve the output size in the global compositor + space should use xdg_output.logical_size instead. + + The vertical refresh rate can be set to zero if it doesn't make + sense for this output (e.g. for virtual outputs). + + The mode event will be followed by a done event (starting from + version 2). + + Clients should not use the refresh rate to schedule frames. Instead, + they should use the wl_surface.frame event or the presentation-time + protocol. + + Note: this information is not always meaningful for all outputs. Some + compositors, such as those exposing virtual outputs, might fake the + refresh rate or the size. + + + + + + + + + + + + This event is sent after all other properties have been + sent after binding to the output object and after any + other property changes done after that. This allows + changes to the output properties to be seen as + atomic, even if they happen via multiple events. + + + + + + This event contains scaling geometry information + that is not in the geometry event. It may be sent after + binding the output object or if the output scale changes + later. If it is not sent, the client should assume a + scale of 1. + + A scale larger than 1 means that the compositor will + automatically scale surface buffers by this amount + when rendering. This is used for very high resolution + displays where applications rendering at the native + resolution would be too small to be legible. + + It is intended that scaling aware clients track the + current output of a surface, and if it is on a scaled + output it should use wl_surface.set_buffer_scale with + the scale of the output. That way the compositor can + avoid scaling the surface, and the client can supply + a higher detail image. + + The scale event will be followed by a done event. + + + + + + + + + Using this request a client can tell the server that it is not going to + use the output object anymore. + + + + + + + + Many compositors will assign user-friendly names to their outputs, show + them to the user, allow the user to refer to an output, etc. The client + may wish to know this name as well to offer the user similar behaviors. + + The name is a UTF-8 string with no convention defined for its contents. + Each name is unique among all wl_output globals. The name is only + guaranteed to be unique for the compositor instance. + + The same output name is used for all clients for a given wl_output + global. Thus, the name can be shared across processes to refer to a + specific wl_output global. + + The name is not guaranteed to be persistent across sessions, thus cannot + be used to reliably identify an output in e.g. configuration files. + + Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do + not assume that the name is a reflection of an underlying DRM connector, + X11 connection, etc. + + The name event is sent after binding the output object. This event is + only sent once per output object, and the name does not change over the + lifetime of the wl_output global. + + Compositors may re-use the same output name if the wl_output global is + destroyed and re-created later. Compositors should avoid re-using the + same name if possible. + + The name event will be followed by a done event. + + + + + + + Many compositors can produce human-readable descriptions of their + outputs. The client may wish to know this description as well, e.g. for + output selection purposes. + + The description is a UTF-8 string with no convention defined for its + contents. The description is not guaranteed to be unique among all + wl_output globals. Examples might include 'Foocorp 11" Display' or + 'Virtual X11 output via :1'. + + The description event is sent after binding the output object and + whenever the description changes. The description is optional, and may + not be sent at all. + + The description event will be followed by a done event. + + + + + + + + A region object describes an area. + + Region objects are used to describe the opaque and input + regions of a surface. + + + + + Destroy the region. This will invalidate the object ID. + + + + + + Add the specified rectangle to the region. + + + + + + + + + + Subtract the specified rectangle from the region. + + + + + + + + + + + The global interface exposing sub-surface compositing capabilities. + A wl_surface, that has sub-surfaces associated, is called the + parent surface. Sub-surfaces can be arbitrarily nested and create + a tree of sub-surfaces. + + The root surface in a tree of sub-surfaces is the main + surface. The main surface cannot be a sub-surface, because + sub-surfaces must always have a parent. + + A main surface with its sub-surfaces forms a (compound) window. + For window management purposes, this set of wl_surface objects is + to be considered as a single window, and it should also behave as + such. + + The aim of sub-surfaces is to offload some of the compositing work + within a window from clients to the compositor. A prime example is + a video player with decorations and video in separate wl_surface + objects. This should allow the compositor to pass YUV video buffer + processing to dedicated overlay hardware when possible. + + + + + Informs the server that the client will not be using this + protocol object anymore. This does not affect any other + objects, wl_subsurface objects included. + + + + + + + + + + Create a sub-surface interface for the given surface, and + associate it with the given parent surface. This turns a + plain wl_surface into a sub-surface. + + The to-be sub-surface must not already have another role, and it + must not have an existing wl_subsurface object. Otherwise a protocol + error is raised. + + Adding sub-surfaces to a parent is a double-buffered operation on the + parent (see wl_surface.commit). The effect of adding a sub-surface + becomes visible on the next time the state of the parent surface is + applied. + + This request modifies the behaviour of wl_surface.commit request on + the sub-surface, see the documentation on wl_subsurface interface. + + + + + + + + + + An additional interface to a wl_surface object, which has been + made a sub-surface. A sub-surface has one parent surface. A + sub-surface's size and position are not limited to that of the parent. + Particularly, a sub-surface is not automatically clipped to its + parent's area. + + A sub-surface becomes mapped, when a non-NULL wl_buffer is applied + and the parent surface is mapped. The order of which one happens + first is irrelevant. A sub-surface is hidden if the parent becomes + hidden, or if a NULL wl_buffer is applied. These rules apply + recursively through the tree of surfaces. + + The behaviour of a wl_surface.commit request on a sub-surface + depends on the sub-surface's mode. The possible modes are + synchronized and desynchronized, see methods + wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized + mode caches the wl_surface state to be applied when the parent's + state gets applied, and desynchronized mode applies the pending + wl_surface state directly. A sub-surface is initially in the + synchronized mode. + + Sub-surfaces also have another kind of state, which is managed by + wl_subsurface requests, as opposed to wl_surface requests. This + state includes the sub-surface position relative to the parent + surface (wl_subsurface.set_position), and the stacking order of + the parent and its sub-surfaces (wl_subsurface.place_above and + .place_below). This state is applied when the parent surface's + wl_surface state is applied, regardless of the sub-surface's mode. + As the exception, set_sync and set_desync are effective immediately. + + The main surface can be thought to be always in desynchronized mode, + since it does not have a parent in the sub-surfaces sense. + + Even if a sub-surface is in desynchronized mode, it will behave as + in synchronized mode, if its parent surface behaves as in + synchronized mode. This rule is applied recursively throughout the + tree of surfaces. This means, that one can set a sub-surface into + synchronized mode, and then assume that all its child and grand-child + sub-surfaces are synchronized, too, without explicitly setting them. + + If the wl_surface associated with the wl_subsurface is destroyed, the + wl_subsurface object becomes inert. Note, that destroying either object + takes effect immediately. If you need to synchronize the removal + of a sub-surface to the parent surface update, unmap the sub-surface + first by attaching a NULL wl_buffer, update parent, and then destroy + the sub-surface. + + If the parent wl_surface object is destroyed, the sub-surface is + unmapped. + + + + + The sub-surface interface is removed from the wl_surface object + that was turned into a sub-surface with a + wl_subcompositor.get_subsurface request. The wl_surface's association + to the parent is deleted, and the wl_surface loses its role as + a sub-surface. The wl_surface is unmapped immediately. + + + + + + + + + + This schedules a sub-surface position change. + The sub-surface will be moved so that its origin (top left + corner pixel) will be at the location x, y of the parent surface + coordinate system. The coordinates are not restricted to the parent + surface area. Negative values are allowed. + + The scheduled coordinates will take effect whenever the state of the + parent surface is applied. When this happens depends on whether the + parent surface is in synchronized mode or not. See + wl_subsurface.set_sync and wl_subsurface.set_desync for details. + + If more than one set_position request is invoked by the client before + the commit of the parent surface, the position of a new request always + replaces the scheduled position from any previous request. + + The initial position is 0, 0. + + + + + + + + This sub-surface is taken from the stack, and put back just + above the reference surface, changing the z-order of the sub-surfaces. + The reference surface must be one of the sibling surfaces, or the + parent surface. Using any other surface, including this sub-surface, + will cause a protocol error. + + The z-order is double-buffered. Requests are handled in order and + applied immediately to a pending state. The final pending state is + copied to the active state the next time the state of the parent + surface is applied. When this happens depends on whether the parent + surface is in synchronized mode or not. See wl_subsurface.set_sync and + wl_subsurface.set_desync for details. + + A new sub-surface is initially added as the top-most in the stack + of its siblings and parent. + + + + + + + The sub-surface is placed just below the reference surface. + See wl_subsurface.place_above. + + + + + + + Change the commit behaviour of the sub-surface to synchronized + mode, also described as the parent dependent mode. + + In synchronized mode, wl_surface.commit on a sub-surface will + accumulate the committed state in a cache, but the state will + not be applied and hence will not change the compositor output. + The cached state is applied to the sub-surface immediately after + the parent surface's state is applied. This ensures atomic + updates of the parent and all its synchronized sub-surfaces. + Applying the cached state will invalidate the cache, so further + parent surface commits do not (re-)apply old state. + + See wl_subsurface for the recursive effect of this mode. + + + + + + Change the commit behaviour of the sub-surface to desynchronized + mode, also described as independent or freely running mode. + + In desynchronized mode, wl_surface.commit on a sub-surface will + apply the pending state directly, without caching, as happens + normally with a wl_surface. Calling wl_surface.commit on the + parent surface has no effect on the sub-surface's wl_surface + state. This mode allows a sub-surface to be updated on its own. + + If cached state exists when wl_surface.commit is called in + desynchronized mode, the pending state is added to the cached + state, and applied as a whole. This invalidates the cache. + + Note: even if a sub-surface is set to desynchronized, a parent + sub-surface may override it to behave as synchronized. For details, + see wl_subsurface. + + If a surface's parent surface behaves as desynchronized, then + the cached state is applied on set_desync. + + + + +