LCOV - code coverage report
Current view: top level - xenolith/platform/linux - XLPlatformLinuxWayland.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 203 1190 17.1 %
Date: 2024-04-26 09:30:07 Functions: 10 108 9.3 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       3             : 
       4             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  of this software and associated documentation files (the "Software"), to deal
       6             :  in the Software without restriction, including without limitation the rights
       7             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  copies of the Software, and to permit persons to whom the Software is
       9             :  furnished to do so, subject to the following conditions:
      10             : 
      11             :  The above copyright notice and this permission notice shall be included in
      12             :  all copies or substantial portions of the Software.
      13             : 
      14             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20             :  THE SOFTWARE.
      21             :  **/
      22             : 
      23             : #include "XLPlatformLinuxWayland.h"
      24             : #include "XLPlatformLinuxDbus.h"
      25             : #include "SPPlatformUnistd.h"
      26             : 
      27             : #include <sys/mman.h>
      28             : #include <dlfcn.h>
      29             : #include <poll.h>
      30             : #include <fcntl.h>
      31             : #include <linux/input.h>
      32             : 
      33             : #ifndef XL_WAYLAND_LOG
      34             : #if XL_WAYLAND_DEBUG
      35             : #define XL_WAYLAND_LOG(...) log::debug("Wayland", __VA_ARGS__)
      36             : #else
      37             : #define XL_WAYLAND_LOG(...)
      38             : #endif
      39             : #endif
      40             : 
      41             : #if XL_LINK
      42             : extern "C" {
      43             : 
      44             : extern const struct wl_interface wl_registry_interface;
      45             : extern const struct wl_interface wl_compositor_interface;
      46             : extern const struct wl_interface wl_output_interface;
      47             : extern const struct wl_interface wl_seat_interface;
      48             : extern const struct wl_interface wl_surface_interface;
      49             : extern const struct wl_interface wl_region_interface;
      50             : extern const struct wl_interface wl_callback_interface;
      51             : extern const struct wl_interface wl_pointer_interface;
      52             : extern const struct wl_interface wl_keyboard_interface;
      53             : extern const struct wl_interface wl_touch_interface;
      54             : extern const struct wl_interface wl_shm_interface;
      55             : extern const struct wl_interface wl_subcompositor_interface;
      56             : extern const struct wl_interface wl_subsurface_interface;
      57             : extern const struct wl_interface wl_shm_pool_interface;
      58             : extern const struct wl_interface wl_buffer_interface;
      59             : 
      60             : extern const struct wl_interface wp_viewporter_interface;
      61             : extern const struct wl_interface wp_viewport_interface;
      62             : 
      63             : extern const struct wl_interface xdg_wm_base_interface;
      64             : extern const struct wl_interface xdg_positioner_interface;
      65             : extern const struct wl_interface xdg_surface_interface;
      66             : extern const struct wl_interface xdg_toplevel_interface;
      67             : extern const struct wl_interface xdg_popup_interface;
      68             : 
      69             : struct wl_display * wl_display_connect(const char *name);
      70             : int wl_display_get_fd (struct wl_display *display);
      71             : int wl_display_dispatch (struct wl_display *display);
      72             : int wl_display_dispatch_pending (struct wl_display *display);
      73             : int wl_display_prepare_read (struct wl_display *display);
      74             : int wl_display_flush (struct wl_display *display);
      75             : int wl_display_read_events (struct wl_display *display);
      76             : void wl_display_disconnect (struct wl_display *display);
      77             : 
      78             : struct wl_proxy* wl_proxy_marshal_flags (struct wl_proxy *proxy, uint32_t opcode,
      79             :                 const struct wl_interface *interface, uint32_t version, uint32_t flags, ...);
      80             : uint32_t wl_proxy_get_version (struct wl_proxy *proxy);
      81             : int wl_proxy_add_listener (struct wl_proxy *proxy, void (**implementation)(void), void *data);
      82             : void wl_proxy_set_user_data (struct wl_proxy *proxy, void *user_data);
      83             : void *wl_proxy_get_user_data (struct wl_proxy *proxy);
      84             : void wl_proxy_set_tag (struct wl_proxy *proxy, const char * const *tag);
      85             : const char * const *wl_proxy_get_tag (struct wl_proxy *proxy);
      86             : void wl_proxy_destroy (struct wl_proxy *proxy);
      87             : int wl_display_roundtrip (struct wl_display *display);
      88             : 
      89             : wl_cursor_theme * wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm);
      90             : void wl_cursor_theme_destroy(wl_cursor_theme *theme);
      91             : wl_cursor * wl_cursor_theme_get_cursor(wl_cursor_theme *theme, const char *name);
      92             : wl_buffer * wl_cursor_image_get_buffer(wl_cursor_image *image);
      93             : 
      94             : }
      95             : #endif
      96             : 
      97             : namespace STAPPLER_VERSIONIZED stappler::xenolith::platform {
      98             : 
      99             : static const char *s_XenolithWaylandTag = "org.stappler.xenolith.wayland";
     100             : 
     101             : static WaylandLibrary *s_WaylandLibrary = nullptr;
     102             : 
     103             : struct ViewporterInterface {
     104             :         const struct wl_interface *viewporter_types[6];
     105             : 
     106             :         const struct wl_message wp_viewporter_requests[2];
     107             :         const struct wl_message wp_viewport_requests[3];
     108             : 
     109             :         const struct wl_interface wp_viewporter_interface;
     110             :         const struct wl_interface wp_viewport_interface;
     111             : 
     112          10 :         ViewporterInterface(const struct wl_interface *wl_surface_interface)
     113          10 :         : viewporter_types{
     114             :                 NULL,
     115             :                 NULL,
     116             :                 NULL,
     117             :                 NULL,
     118          10 :                 &wp_viewport_interface,
     119             :                 wl_surface_interface
     120          10 :         }, wp_viewporter_requests{
     121          10 :                 { "destroy", "", viewporter_types + 0 },
     122          10 :                 { "get_viewport", "no", viewporter_types + 4 },
     123          10 :         }, wp_viewport_requests{
     124          10 :                 { "destroy", "", viewporter_types + 0 },
     125          10 :                 { "set_source", "ffff", viewporter_types + 0 },
     126          10 :                 { "set_destination", "ii", viewporter_types + 0 },
     127          10 :         }, wp_viewporter_interface{
     128             :                 "wp_viewporter", 1,
     129          10 :                 2, wp_viewporter_requests,
     130             :                 0, NULL,
     131          10 :         }, wp_viewport_interface{
     132             :                 "wp_viewport", 1,
     133          10 :                 3, wp_viewport_requests,
     134             :                 0, NULL,
     135          10 :         } { }
     136             : };
     137             : 
     138             : struct XdgInterface {
     139             :         const struct wl_interface *xdg_shell_types[26];
     140             : 
     141             :         const struct wl_message xdg_wm_base_requests[4];
     142             :         const struct wl_message xdg_wm_base_events[1];
     143             :         const struct wl_message xdg_positioner_requests[10];
     144             :         const struct wl_message xdg_surface_requests[5];
     145             :         const struct wl_message xdg_surface_events[1];
     146             :         const struct wl_message xdg_toplevel_requests[14];
     147             :         const struct wl_message xdg_toplevel_events[3];
     148             :         const struct wl_message xdg_popup_requests[3];
     149             :         const struct wl_message xdg_popup_events[3];
     150             : 
     151             :         const struct wl_interface xdg_wm_base_interface;
     152             :         const struct wl_interface xdg_positioner_interface;
     153             :         const struct wl_interface xdg_surface_interface;
     154             :         const struct wl_interface xdg_toplevel_interface;
     155             :         const struct wl_interface xdg_popup_interface;
     156             : 
     157          10 :         XdgInterface(const struct wl_interface *wl_output_interface, const struct wl_interface *wl_seat_interface,
     158             :                         const struct wl_interface *wl_surface_interface)
     159          10 :         : xdg_shell_types{
     160             :                 NULL,
     161             :                 NULL,
     162             :                 NULL,
     163             :                 NULL,
     164          10 :                 &xdg_positioner_interface,
     165          10 :                 &xdg_surface_interface,
     166             :                 wl_surface_interface,
     167          10 :                 &xdg_toplevel_interface,
     168          10 :                 &xdg_popup_interface,
     169          10 :                 &xdg_surface_interface,
     170          10 :                 &xdg_positioner_interface,
     171          10 :                 &xdg_toplevel_interface,
     172             :                 wl_seat_interface,
     173             :                 NULL,
     174             :                 NULL,
     175             :                 NULL,
     176             :                 wl_seat_interface,
     177             :                 NULL,
     178             :                 wl_seat_interface,
     179             :                 NULL,
     180             :                 NULL,
     181             :                 wl_output_interface,
     182             :                 wl_seat_interface,
     183             :                 NULL,
     184          10 :                 &xdg_positioner_interface,
     185             :                 NULL,
     186          10 :         }, xdg_wm_base_requests{
     187          10 :                 { "destroy", "", xdg_shell_types + 0 },
     188          10 :                 { "create_positioner", "n", xdg_shell_types + 4 },
     189          10 :                 { "get_xdg_surface", "no", xdg_shell_types + 5 },
     190          10 :                 { "pong", "u", xdg_shell_types + 0 },
     191          10 :         }, xdg_wm_base_events{
     192          10 :                 { "ping", "u", xdg_shell_types + 0 },
     193          10 :         }, xdg_positioner_requests{
     194          10 :                 { "destroy", "", xdg_shell_types + 0 },
     195          10 :                 { "set_size", "ii", xdg_shell_types + 0 },
     196          10 :                 { "set_anchor_rect", "iiii", xdg_shell_types + 0 },
     197          10 :                 { "set_anchor", "u", xdg_shell_types + 0 },
     198          10 :                 { "set_gravity", "u", xdg_shell_types + 0 },
     199          10 :                 { "set_constraint_adjustment", "u", xdg_shell_types + 0 },
     200          10 :                 { "set_offset", "ii", xdg_shell_types + 0 },
     201          10 :                 { "set_reactive", "3", xdg_shell_types + 0 },
     202          10 :                 { "set_parent_size", "3ii", xdg_shell_types + 0 },
     203          10 :                 { "set_parent_configure", "3u", xdg_shell_types + 0 },
     204          10 :         }, xdg_surface_requests{
     205          10 :                 { "destroy", "", xdg_shell_types + 0 },
     206          10 :                 { "get_toplevel", "n", xdg_shell_types + 7 },
     207          10 :                 { "get_popup", "n?oo", xdg_shell_types + 8 },
     208          10 :                 { "set_window_geometry", "iiii", xdg_shell_types + 0 },
     209          10 :                 { "ack_configure", "u", xdg_shell_types + 0 },
     210          10 :         }, xdg_surface_events{
     211          10 :                 { "configure", "u", xdg_shell_types + 0 },
     212          10 :         }, xdg_toplevel_requests{
     213          10 :                 { "destroy", "", xdg_shell_types + 0 },
     214          10 :                 { "set_parent", "?o", xdg_shell_types + 11 },
     215          10 :                 { "set_title", "s", xdg_shell_types + 0 },
     216          10 :                 { "set_app_id", "s", xdg_shell_types + 0 },
     217          10 :                 { "show_window_menu", "ouii", xdg_shell_types + 12 },
     218          10 :                 { "move", "ou", xdg_shell_types + 16 },
     219          10 :                 { "resize", "ouu", xdg_shell_types + 18 },
     220          10 :                 { "set_max_size", "ii", xdg_shell_types + 0 },
     221          10 :                 { "set_min_size", "ii", xdg_shell_types + 0 },
     222          10 :                 { "set_maximized", "", xdg_shell_types + 0 },
     223          10 :                 { "unset_maximized", "", xdg_shell_types + 0 },
     224          10 :                 { "set_fullscreen", "?o", xdg_shell_types + 21 },
     225          10 :                 { "unset_fullscreen", "", xdg_shell_types + 0 },
     226          10 :                 { "set_minimized", "", xdg_shell_types + 0 },
     227          10 :         }, xdg_toplevel_events{
     228          10 :                 { "configure", "iia", xdg_shell_types + 0 },
     229          10 :                 { "close", "", xdg_shell_types + 0 },
     230          10 :                 { "configure_bounds", "4ii", xdg_shell_types + 0 },
     231          10 :         }, xdg_popup_requests{
     232          10 :                 { "destroy", "", xdg_shell_types + 0 },
     233          10 :                 { "grab", "ou", xdg_shell_types + 22 },
     234          10 :                 { "reposition", "3ou", xdg_shell_types + 24 },
     235          10 :         }, xdg_popup_events{
     236          10 :                 { "configure", "iiii", xdg_shell_types + 0 },
     237          10 :                 { "popup_done", "", xdg_shell_types + 0 },
     238          10 :                 { "repositioned", "3u", xdg_shell_types + 0 },
     239          10 :         }, xdg_wm_base_interface{
     240             :                 "xdg_wm_base", 4,
     241          10 :                 4, xdg_wm_base_requests,
     242          10 :                 1, xdg_wm_base_events,
     243          10 :         }, xdg_positioner_interface{
     244             :                 "xdg_positioner", 4,
     245          10 :                 10, xdg_positioner_requests,
     246             :                 0, NULL,
     247          10 :         }, xdg_surface_interface{
     248             :                 "xdg_surface", 4,
     249          10 :                 5, xdg_surface_requests,
     250          10 :                 1, xdg_surface_events,
     251          10 :         }, xdg_toplevel_interface{
     252             :                 "xdg_toplevel", 4,
     253          10 :                 14, xdg_toplevel_requests,
     254          10 :                 3, xdg_toplevel_events,
     255          10 :         }, xdg_popup_interface{
     256             :                 "xdg_popup", 4,
     257          10 :                 3, xdg_popup_requests,
     258          10 :                 3, xdg_popup_events,
     259          10 :         } { }
     260             : };
     261             : 
     262             : static const uint8_t s_iconClose[] = {
     263             :         0x4c, 0x5a, 0x34, 0x53, 0xab, 0x7, 0xdf, 0xd9, 0xd9, 0xf7, 0xa3, 0x64, 0x64, 0x61, 0x74, 0x61,
     264             :         0x59, 0x7, 0x90, 0x0, 0x1, 0x0, 0xff, 0xbd, 0x8f, 0x67, 0x67, 0x67, 0x5c, 0x55, 0x55, 0x55,
     265             :         0x6, 0x20, 0x0, 0x5, 0x0, 0x1c, 0x0, 0x0, 0x24, 0x0, 0xf, 0x54, 0x0, 0x1d, 0x8e, 0x67,
     266             :         0x67, 0x67, 0xff, 0x67, 0x67, 0x67, 0xb0, 0x5c, 0x0, 0x5, 0x54, 0x0, 0x13, 0xb0, 0x24, 0x0,
     267             :         0xf, 0x5c, 0x0, 0x16, 0x83, 0x66, 0x66, 0x66, 0x5, 0x67, 0x67, 0x67, 0xaf, 0x38, 0x0, 0x5b,
     268             :         0xb5, 0x6d, 0x6d, 0x6d, 0x7, 0x54, 0x0, 0xe, 0x1c, 0x0, 0xf, 0x5c, 0x0, 0x20, 0x40, 0x68,
     269             :         0x68, 0x68, 0xb6, 0x40, 0x0, 0xf, 0x54, 0x0, 0x2d, 0xf, 0xf0, 0x0, 0x4, 0x18, 0xb0, 0xc,
     270             :         0x0, 0xf, 0x7c, 0x1, 0x9, 0xf, 0x14, 0x1, 0x20, 0xf, 0xa8, 0x0, 0x2a, 0xe, 0xb4, 0x0,
     271             :         0x6, 0x58, 0x0, 0x4, 0x14, 0x1, 0xf, 0x54, 0x0, 0x30, 0x1, 0xfc, 0x0, 0x4f, 0x66, 0x66,
     272             :         0x66, 0xb1, 0x8, 0x1, 0x31, 0xf, 0x14, 0x2, 0x1, 0xf, 0xcc, 0x1, 0x1, 0xf, 0x54, 0x0,
     273             :         0x2d, 0xf, 0x1c, 0x0, 0x11, 0xf, 0x18, 0x3, 0x15, 0x0, 0xfc, 0x0, 0xf, 0x18, 0x3, 0x39,
     274             :         0xf, 0xc8, 0x3, 0x45, 0xf, 0x1, 0x0, 0xff, 0x92, 0xf0, 0x0, 0x66, 0x68, 0x65, 0x69, 0x67,
     275             :         0x68, 0x74, 0x16, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 0x16,
     276             : };
     277             : 
     278             : static const uint8_t s_iconCloseActive[] = {
     279             :         0x4c, 0x5a, 0x34, 0x53, 0xab, 0x7, 0xdf, 0xd9, 0xd9, 0xf7, 0xa3, 0x64, 0x64, 0x61, 0x74, 0x61,
     280             :         0x59, 0x7, 0x90, 0x0, 0x1, 0x0, 0x4, 0xf3, 0x5, 0xb8, 0xb8, 0xb8, 0x12, 0xb4, 0xb4, 0xb4,
     281             :         0x62, 0xb4, 0xb4, 0xb4, 0xb0, 0xb3, 0xb3, 0xb3, 0xd8, 0xb3, 0xb3, 0xb3, 0xf4, 0x4, 0x0, 0x0,
     282             :         0xc, 0x0, 0xaf, 0xaf, 0xb3, 0xb3, 0xb3, 0x61, 0xb4, 0xb4, 0xb4, 0x11, 0x0, 0x1, 0x0, 0x14,
     283             :         0xff, 0x1, 0xaa, 0xaa, 0xaa, 0x9, 0xb2, 0xb2, 0xb2, 0x7b, 0xb3, 0xb3, 0xb3, 0xf1, 0xb3, 0xb3,
     284             :         0xb3, 0xff, 0x4, 0x0, 0xc, 0x50, 0xf0, 0xb4, 0xb4, 0xb4, 0x7a, 0x34, 0x0, 0xf, 0x54, 0x0,
     285             :         0x9, 0x8f, 0xb1, 0xb1, 0xb1, 0x1a, 0xb3, 0xb3, 0xb3, 0xca, 0x50, 0x0, 0x10, 0xc, 0x4, 0x0,
     286             :         0x5f, 0xcf, 0xb3, 0xb3, 0xb3, 0x1e, 0x54, 0x0, 0x1, 0x8f, 0xb6, 0xb6, 0xb6, 0x1c, 0xb3, 0xb3,
     287             :         0xb3, 0xe4, 0x54, 0x0, 0x20, 0x4, 0x4, 0x0, 0x5c, 0xe3, 0xb3, 0xb3, 0xb3, 0x1b, 0xfc, 0x0,
     288             :         0x4f, 0xb3, 0xb3, 0xb3, 0xcd, 0x54, 0x0, 0x28, 0x1, 0x4, 0x0, 0x84, 0xb2, 0xb2, 0xb2, 0xcb,
     289             :         0xbf, 0xbf, 0xbf, 0x8, 0x58, 0x0, 0x4c, 0xb4, 0xb4, 0xb4, 0x7d, 0x24, 0x0, 0x7f, 0xce, 0xce,
     290             :         0xce, 0xff, 0xb5, 0xb5, 0xb5, 0x44, 0x0, 0x6, 0x0, 0x1c, 0x0, 0x0, 0x24, 0x0, 0x1e, 0xb3,
     291             :         0x1c, 0x0, 0x14, 0x78, 0xf8, 0x1, 0xc, 0xa4, 0x1, 0x0, 0x30, 0x0, 0x0, 0x1, 0x0, 0x3e,
     292             :         0xe7, 0xe7, 0xe7, 0x5c, 0x0, 0x3, 0x54, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x1, 0x0, 0xe, 0x5c,
     293             :         0x0, 0x1, 0xcc, 0x1, 0x5c, 0x11, 0xb2, 0xb2, 0xb2, 0x63, 0x38, 0x0, 0x35, 0xb4, 0xb4, 0xb4,
     294             :         0x38, 0x0, 0x39, 0xe9, 0xe9, 0xe9, 0x5c, 0x0, 0x8, 0x54, 0x0, 0xc, 0x1c, 0x0, 0x7, 0x10,
     295             :         0x1, 0x13, 0x60, 0xa0, 0x2, 0x1f, 0xff, 0x5c, 0x0, 0x11, 0xf, 0x54, 0x0, 0x11, 0x3, 0x4,
     296             :         0x0, 0x5e, 0xae, 0xb3, 0xb3, 0xb3, 0xdb, 0x44, 0x1, 0xe, 0x9c, 0x0, 0x0, 0x8, 0x0, 0x8,
     297             :         0xc, 0x0, 0xf, 0x7c, 0x1, 0x9, 0x3, 0x3c, 0x3, 0x1f, 0xf3, 0xe4, 0x1, 0x9, 0x8, 0xb8,
     298             :         0x0, 0xf, 0xa8, 0x0, 0x10, 0x4, 0x4, 0x0, 0x1e, 0xf3, 0x58, 0x0, 0xe, 0xb4, 0x0, 0xf,
     299             :         0x58, 0x0, 0x20, 0x0, 0x8, 0x2, 0x1f, 0xd9, 0x54, 0x0, 0x11, 0x3f, 0xe8, 0xe8, 0xe8, 0x8,
     300             :         0x1, 0x19, 0x13, 0xd7, 0x44, 0x4, 0xf, 0xb8, 0x1, 0x12, 0xf, 0x28, 0x2, 0x9, 0xb, 0x10,
     301             :         0x2, 0x10, 0xad, 0x98, 0x4, 0xf, 0x68, 0x2, 0x19, 0xf, 0x5c, 0x0, 0x14, 0x13, 0x5e, 0x18,
     302             :         0x3, 0x1e, 0xf0, 0x18, 0x3, 0x2, 0xfc, 0x0, 0xf, 0x18, 0x3, 0x20, 0x53, 0xef, 0xaf, 0xaf,
     303             :         0xaf, 0x10, 0xc8, 0x3, 0x1f, 0x7a, 0xc8, 0x3, 0x38, 0x14, 0x76, 0x20, 0x4, 0x0, 0x2c, 0x4,
     304             :         0x0, 0x34, 0x4, 0xf, 0x78, 0x4, 0x2c, 0x0, 0x4, 0x0, 0x18, 0xc9, 0x78, 0x4, 0x0, 0x1,
     305             :         0x0, 0x0, 0xe4, 0x4, 0x3, 0xec, 0x4, 0xf, 0x54, 0x0, 0x25, 0x10, 0xe2, 0xc0, 0x5, 0xf,
     306             :         0xd8, 0x5, 0x8, 0x1f, 0xc9, 0x54, 0x0, 0x20, 0x1f, 0xce, 0xd8, 0x5, 0x5, 0x8, 0x14, 0x1,
     307             :         0x0, 0xec, 0x4, 0xc, 0xcc, 0x1, 0xf, 0x4, 0x0, 0x4, 0x10, 0xef, 0x50, 0x1, 0x4f, 0xb6,
     308             :         0xb6, 0xb6, 0x7, 0xe8, 0x6, 0x15, 0x3, 0xec, 0x4, 0x13, 0x60, 0xe0, 0x2, 0x17, 0xd7, 0x9c,
     309             :         0x3, 0x10, 0xd7, 0x58, 0x4, 0x44, 0xb4, 0xb4, 0xb4, 0x5f, 0xf8, 0x1, 0xf, 0x1, 0x0, 0x1,
     310             :         0xf0, 0x0, 0x66, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x16, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68,
     311             :         0x16,
     312             : };
     313             : 
     314             : static const uint8_t s_iconMaximize[] = {
     315             :         0x4c, 0x5a, 0x34, 0x53, 0xab, 0x7, 0xdf, 0xd9, 0xd9, 0xf7, 0xa3, 0x64, 0x64, 0x61, 0x74, 0x61,
     316             :         0x59, 0x7, 0x90, 0x0, 0x1, 0x0, 0xff, 0xb9, 0x8f, 0x64, 0x64, 0x64, 0x40, 0x66, 0x66, 0x66,
     317             :         0x80, 0x4, 0x0, 0x11, 0x0, 0x2c, 0x0, 0xf, 0x58, 0x0, 0x15, 0x0, 0x30, 0x0, 0x8f, 0x65,
     318             :         0x65, 0x65, 0xfc, 0x65, 0x65, 0x65, 0xe0, 0x4, 0x0, 0xc, 0x10, 0xfc, 0x2c, 0x0, 0xf, 0x58,
     319             :         0x0, 0x1c, 0x1f, 0xe0, 0x28, 0x0, 0xd, 0x0, 0x24, 0x0, 0xf, 0x58, 0x0, 0xff, 0xff, 0x8a,
     320             :         0xf, 0x18, 0x3, 0x3e, 0xf, 0xc8, 0x3, 0x45, 0xf, 0x1, 0x0, 0xff, 0x92, 0xf0, 0x0, 0x66,
     321             :         0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x16, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 0x16,
     322             : };
     323             : 
     324             : static const uint8_t s_iconMaximizeActive[] = {
     325             :         0x4c, 0x5a, 0x34, 0x53, 0xab, 0x7, 0xdf, 0xd9, 0xd9, 0xf7, 0xa3, 0x64, 0x64, 0x61, 0x74, 0x61,
     326             :         0x59, 0x7, 0x90, 0x0, 0x1, 0x0, 0x4, 0xf3, 0x5, 0xb8, 0xb8, 0xb8, 0x12, 0xb4, 0xb4, 0xb4,
     327             :         0x62, 0xb4, 0xb4, 0xb4, 0xb0, 0xb3, 0xb3, 0xb3, 0xd8, 0xb3, 0xb3, 0xb3, 0xf4, 0x4, 0x0, 0x0,
     328             :         0xc, 0x0, 0xaf, 0xaf, 0xb3, 0xb3, 0xb3, 0x61, 0xb4, 0xb4, 0xb4, 0x11, 0x0, 0x1, 0x0, 0x14,
     329             :         0xff, 0x1, 0xaa, 0xaa, 0xaa, 0x9, 0xb2, 0xb2, 0xb2, 0x7b, 0xb3, 0xb3, 0xb3, 0xf1, 0xb3, 0xb3,
     330             :         0xb3, 0xff, 0x4, 0x0, 0xc, 0x50, 0xf0, 0xb4, 0xb4, 0xb4, 0x7a, 0x34, 0x0, 0xf, 0x54, 0x0,
     331             :         0x9, 0x8f, 0xb1, 0xb1, 0xb1, 0x1a, 0xb3, 0xb3, 0xb3, 0xca, 0x50, 0x0, 0x10, 0xc, 0x4, 0x0,
     332             :         0x5f, 0xcf, 0xb3, 0xb3, 0xb3, 0x1e, 0x54, 0x0, 0x1, 0x8f, 0xb6, 0xb6, 0xb6, 0x1c, 0xb3, 0xb3,
     333             :         0xb3, 0xe4, 0x54, 0x0, 0x20, 0x4, 0x4, 0x0, 0x5c, 0xe3, 0xb3, 0xb3, 0xb3, 0x1b, 0xfc, 0x0,
     334             :         0x4f, 0xb3, 0xb3, 0xb3, 0xcd, 0x54, 0x0, 0x28, 0x1, 0x4, 0x0, 0x84, 0xb2, 0xb2, 0xb2, 0xcb,
     335             :         0xbf, 0xbf, 0xbf, 0x8, 0x58, 0x0, 0x48, 0xb4, 0xb4, 0xb4, 0x7d, 0x20, 0x0, 0x7f, 0xc6, 0xc6,
     336             :         0xc6, 0xff, 0xd9, 0xd9, 0xd9, 0x4, 0x0, 0x12, 0x0, 0x2c, 0x0, 0xb, 0x60, 0x0, 0x14, 0x78,
     337             :         0xf8, 0x1, 0xc, 0xa4, 0x1, 0x0, 0x30, 0x0, 0x7f, 0xfe, 0xfe, 0xfe, 0xff, 0xf6, 0xf6, 0xf6,
     338             :         0x4, 0x0, 0xa, 0x0, 0x24, 0x0, 0x0, 0x2c, 0x0, 0x1e, 0xb3, 0xcc, 0x1, 0x5c, 0x11, 0xb2,
     339             :         0xb2, 0xb2, 0x63, 0xd0, 0x0, 0x0, 0x2c, 0x0, 0x0, 0x38, 0x0, 0xf, 0xf8, 0x0, 0xd, 0x0,
     340             :         0x24, 0x0, 0xe, 0x58, 0x0, 0x1, 0x10, 0x1, 0x13, 0x60, 0xa0, 0x2, 0xf, 0x58, 0x0, 0x39,
     341             :         0x0, 0x4, 0x0, 0x5f, 0xae, 0xb3, 0xb3, 0xb3, 0xdb, 0x58, 0x0, 0x40, 0x0, 0x3c, 0x3, 0x1f,
     342             :         0xf3, 0x58, 0x0, 0x40, 0x1f, 0xf3, 0x58, 0x0, 0x44, 0x0, 0x8, 0x2, 0x1f, 0xd9, 0x58, 0x0,
     343             :         0x40, 0x13, 0xd7, 0x44, 0x4, 0xf, 0x10, 0x2, 0x3d, 0x10, 0xad, 0x98, 0x4, 0xf, 0xb0, 0x0,
     344             :         0x40, 0x13, 0x5e, 0x18, 0x3, 0x1f, 0xf0, 0x18, 0x3, 0x38, 0x53, 0xef, 0xaf, 0xaf, 0xaf, 0x10,
     345             :         0xc8, 0x3, 0x1f, 0x7a, 0xc8, 0x3, 0x38, 0x14, 0x76, 0x20, 0x4, 0x0, 0x2c, 0x4, 0x0, 0x34,
     346             :         0x4, 0xf, 0x78, 0x4, 0x2c, 0x0, 0x4, 0x0, 0x18, 0xc9, 0x78, 0x4, 0x0, 0x1, 0x0, 0x0,
     347             :         0xe4, 0x4, 0x3, 0xec, 0x4, 0xf, 0x54, 0x0, 0x25, 0x10, 0xe2, 0xc0, 0x5, 0xf, 0xd8, 0x5,
     348             :         0x8, 0x1f, 0xc9, 0x54, 0x0, 0x20, 0x1f, 0xce, 0xd8, 0x5, 0x5, 0x8, 0x14, 0x1, 0x0, 0xec,
     349             :         0x4, 0xc, 0xcc, 0x1, 0xf, 0x4, 0x0, 0x4, 0x10, 0xef, 0x50, 0x1, 0x4f, 0xb6, 0xb6, 0xb6,
     350             :         0x7, 0xe8, 0x6, 0x15, 0x3, 0xec, 0x4, 0x13, 0x60, 0xe0, 0x2, 0x17, 0xd7, 0x9c, 0x3, 0x10,
     351             :         0xd7, 0x58, 0x4, 0x44, 0xb4, 0xb4, 0xb4, 0x5f, 0xf8, 0x1, 0xf, 0x1, 0x0, 0x1, 0xf0, 0x0,
     352             :         0x66, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x16, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 0x16,
     353             : };
     354             : 
     355             : static const uint8_t s_iconMinimize[] = {
     356             :         0x4c, 0x5a, 0x34, 0x53, 0xab, 0x7, 0xdf, 0xd9, 0xd9, 0xf7, 0xa3, 0x64, 0x64, 0x61, 0x74, 0x61,
     357             :         0x59, 0x7, 0x90, 0x0, 0x1, 0x0, 0xff, 0xff, 0xff, 0xff, 0x7c, 0x8f, 0x68, 0x68, 0x68, 0x20,
     358             :         0x64, 0x64, 0x64, 0x40, 0x4, 0x0, 0x11, 0x0, 0x2c, 0x0, 0xf, 0x58, 0x0, 0x15, 0x8f, 0x66,
     359             :         0x66, 0x66, 0x80, 0x65, 0x65, 0x65, 0xff, 0x4, 0x0, 0x11, 0x0, 0x2c, 0x0, 0xf, 0x58, 0x0,
     360             :         0x15, 0x40, 0x60, 0x60, 0x60, 0x10, 0x88, 0x0, 0xf, 0x4, 0x0, 0x11, 0x0, 0x2c, 0x0, 0xf,
     361             :         0x4, 0x3, 0xff, 0xff, 0x13, 0xf0, 0x0, 0x66, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x16, 0x65,
     362             :         0x77, 0x69, 0x64, 0x74, 0x68, 0x16,
     363             : };
     364             : 
     365             : static const uint8_t s_iconMinimizeActive[] = {
     366             :         0x4c, 0x5a, 0x34, 0x53, 0xab, 0x7, 0xdf, 0xd9, 0xd9, 0xf7, 0xa3, 0x64, 0x64, 0x61, 0x74, 0x61,
     367             :         0x59, 0x7, 0x90, 0x0, 0x1, 0x0, 0x4, 0xf3, 0x5, 0xb8, 0xb8, 0xb8, 0x12, 0xb4, 0xb4, 0xb4,
     368             :         0x62, 0xb4, 0xb4, 0xb4, 0xb0, 0xb3, 0xb3, 0xb3, 0xd8, 0xb3, 0xb3, 0xb3, 0xf4, 0x4, 0x0, 0x0,
     369             :         0xc, 0x0, 0xaf, 0xaf, 0xb3, 0xb3, 0xb3, 0x61, 0xb4, 0xb4, 0xb4, 0x11, 0x0, 0x1, 0x0, 0x14,
     370             :         0xff, 0x1, 0xaa, 0xaa, 0xaa, 0x9, 0xb2, 0xb2, 0xb2, 0x7b, 0xb3, 0xb3, 0xb3, 0xf1, 0xb3, 0xb3,
     371             :         0xb3, 0xff, 0x4, 0x0, 0xc, 0x50, 0xf0, 0xb4, 0xb4, 0xb4, 0x7a, 0x34, 0x0, 0xf, 0x54, 0x0,
     372             :         0x9, 0x8f, 0xb1, 0xb1, 0xb1, 0x1a, 0xb3, 0xb3, 0xb3, 0xca, 0x50, 0x0, 0x10, 0xc, 0x4, 0x0,
     373             :         0x5f, 0xcf, 0xb3, 0xb3, 0xb3, 0x1e, 0x54, 0x0, 0x1, 0x8f, 0xb6, 0xb6, 0xb6, 0x1c, 0xb3, 0xb3,
     374             :         0xb3, 0xe4, 0x54, 0x0, 0x20, 0x4, 0x4, 0x0, 0x5c, 0xe3, 0xb3, 0xb3, 0xb3, 0x1b, 0xfc, 0x0,
     375             :         0x4f, 0xb3, 0xb3, 0xb3, 0xcd, 0x54, 0x0, 0x28, 0x1, 0x4, 0x0, 0x84, 0xb2, 0xb2, 0xb2, 0xcb,
     376             :         0xbf, 0xbf, 0xbf, 0x8, 0x58, 0x0, 0x4f, 0xb4, 0xb4, 0xb4, 0x7d, 0x54, 0x0, 0x2d, 0x7, 0x4,
     377             :         0x0, 0x14, 0x78, 0xf8, 0x1, 0xe, 0xa4, 0x1, 0xf, 0x4, 0x0, 0x2a, 0x10, 0xf0, 0x28, 0x2,
     378             :         0x4f, 0xb2, 0xb2, 0xb2, 0x63, 0x54, 0x0, 0x38, 0x4, 0x10, 0x1, 0x13, 0x60, 0xa0, 0x2, 0x1f,
     379             :         0xff, 0x4, 0x0, 0x3c, 0x5f, 0xae, 0xb3, 0xb3, 0xb3, 0xdb, 0x58, 0x0, 0x40, 0x0, 0x3c, 0x3,
     380             :         0x1f, 0xf3, 0x58, 0x0, 0x40, 0x1f, 0xf3, 0x58, 0x0, 0x44, 0x0, 0x8, 0x2, 0x1f, 0xd9, 0x58,
     381             :         0x0, 0x40, 0x13, 0xd7, 0x44, 0x4, 0x9, 0x18, 0x0, 0x7f, 0xbd, 0xbd, 0xbd, 0xff, 0xc6, 0xc6,
     382             :         0xc6, 0x4, 0x0, 0x12, 0x0, 0x2c, 0x0, 0x1e, 0xb3, 0x10, 0x2, 0x10, 0xad, 0x98, 0x4, 0xc,
     383             :         0x18, 0x0, 0x4f, 0xd9, 0xd9, 0xd9, 0xff, 0x1, 0x0, 0x15, 0x0, 0x2c, 0x0, 0x1e, 0xb3, 0xb0,
     384             :         0x0, 0x13, 0x5e, 0x18, 0x3, 0x18, 0xf0, 0x18, 0x0, 0x31, 0xb8, 0xb8, 0xb8, 0x88, 0x0, 0xf,
     385             :         0x4, 0x0, 0x11, 0x0, 0x2c, 0x0, 0xb, 0x54, 0x0, 0x53, 0xef, 0xaf, 0xaf, 0xaf, 0x10, 0xc8,
     386             :         0x3, 0x1f, 0x7a, 0x5c, 0x1, 0x38, 0x14, 0x76, 0x20, 0x4, 0x0, 0x2c, 0x4, 0x0, 0x34, 0x4,
     387             :         0xf, 0x54, 0x0, 0x30, 0x18, 0xc9, 0x78, 0x4, 0x0, 0x1, 0x0, 0x0, 0xe4, 0x4, 0x3, 0xec,
     388             :         0x4, 0xf, 0x54, 0x0, 0x25, 0x10, 0xe2, 0xc0, 0x5, 0xf, 0xd8, 0x5, 0x8, 0x1f, 0xc9, 0x54,
     389             :         0x0, 0x20, 0x1f, 0xce, 0xd8, 0x5, 0x5, 0x8, 0x14, 0x1, 0x0, 0xec, 0x4, 0xc, 0xcc, 0x1,
     390             :         0xf, 0x4, 0x0, 0x4, 0x10, 0xef, 0x50, 0x1, 0x4f, 0xb6, 0xb6, 0xb6, 0x7, 0xe8, 0x6, 0x15,
     391             :         0x3, 0xec, 0x4, 0x13, 0x60, 0xe0, 0x2, 0x17, 0xd7, 0x9c, 0x3, 0x10, 0xd7, 0x58, 0x4, 0x44,
     392             :         0xb4, 0xb4, 0xb4, 0x5f, 0xf8, 0x1, 0xf, 0x1, 0x0, 0x1, 0xf0, 0x0, 0x66, 0x68, 0x65, 0x69,
     393             :         0x67, 0x68, 0x74, 0x16, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 0x16,
     394             : };
     395             : 
     396             : static const uint8_t s_iconRestore[] = {
     397             :         0x4c, 0x5a, 0x34, 0x53, 0xab, 0x7, 0xdf, 0xd9, 0xd9, 0xf7, 0xa3, 0x64, 0x64, 0x61, 0x74, 0x61,
     398             :         0x59, 0x7, 0x90, 0x0, 0x1, 0x0, 0xff, 0xc5, 0x8f, 0x65, 0x65, 0x65, 0x30, 0x68, 0x68, 0x68,
     399             :         0x40, 0x4, 0x0, 0x8, 0x1f, 0x20, 0x58, 0x0, 0x21, 0x8f, 0x67, 0x67, 0x67, 0x54, 0x66, 0x66,
     400             :         0x66, 0x70, 0x4, 0x0, 0x1, 0x40, 0x65, 0x65, 0x65, 0x7e, 0x5c, 0x0, 0xf, 0xcc, 0x0, 0x3d,
     401             :         0x0, 0x5c, 0x0, 0xf, 0x58, 0x0, 0x18, 0x0, 0xfc, 0x0, 0x5f, 0x60, 0x65, 0x65, 0x65, 0xc0,
     402             :         0x4, 0x0, 0x8, 0x1f, 0x90, 0x58, 0x0, 0x20, 0x0, 0x30, 0x0, 0x9c, 0x80, 0x65, 0x65, 0x65,
     403             :         0xf4, 0x64, 0x64, 0x64, 0xa0, 0x4, 0x0, 0x40, 0x65, 0x65, 0x65, 0xdc, 0x5c, 0x0, 0xf, 0x58,
     404             :         0x0, 0x28, 0x1f, 0xe0, 0x1c, 0x0, 0x1, 0x3, 0x5c, 0x0, 0xf, 0x58, 0x0, 0xfa, 0x0, 0x84,
     405             :         0x2, 0x0, 0xe0, 0x2, 0xf, 0x58, 0x0, 0x3d, 0xf, 0x98, 0x2, 0x20, 0x0, 0x58, 0x0, 0x10,
     406             :         0xfc, 0x5c, 0x0, 0x1e, 0x65, 0x4, 0x0, 0x1f, 0xf4, 0x58, 0x0, 0x24, 0x0, 0x94, 0x0, 0x10,
     407             :         0x40, 0x5c, 0x0, 0xf, 0x4, 0x0, 0x5, 0x0, 0xe0, 0x2, 0xf, 0xb8, 0x5, 0xff, 0xc6, 0xf0,
     408             :         0x0, 0x66, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x16, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 0x16,
     409             : };
     410             : 
     411             : static const uint8_t s_iconRestoreActive[] = {
     412             :         0x4c, 0x5a, 0x34, 0x53, 0xab, 0x7, 0xdf, 0xd9, 0xd9, 0xf7, 0xa3, 0x64, 0x64, 0x61, 0x74, 0x61,
     413             :         0x59, 0x7, 0x90, 0x0, 0x1, 0x0, 0x4, 0xf3, 0x5, 0xb8, 0xb8, 0xb8, 0x12, 0xb1, 0xb1, 0xb1,
     414             :         0x62, 0xb2, 0xb2, 0xb2, 0xb0, 0xb2, 0xb2, 0xb2, 0xd8, 0xb2, 0xb2, 0xb2, 0xf4, 0x4, 0x0, 0x0,
     415             :         0xc, 0x0, 0xaf, 0xaf, 0xb3, 0xb3, 0xb3, 0x61, 0xb4, 0xb4, 0xb4, 0x11, 0x0, 0x1, 0x0, 0x14,
     416             :         0xff, 0x1, 0xaa, 0xaa, 0xaa, 0x9, 0xb2, 0xb2, 0xb2, 0x7b, 0xb2, 0xb2, 0xb2, 0xf1, 0xb2, 0xb2,
     417             :         0xb2, 0xff, 0x4, 0x0, 0x9, 0x80, 0xb3, 0xb3, 0xb3, 0xf0, 0xb2, 0xb2, 0xb2, 0x7a, 0x34, 0x0,
     418             :         0xf, 0x54, 0x0, 0x9, 0x8f, 0xb1, 0xb1, 0xb1, 0x1a, 0xb2, 0xb2, 0xb2, 0xca, 0x50, 0x0, 0xd,
     419             :         0xc, 0x4, 0x0, 0x8f, 0xb1, 0xb1, 0xb1, 0xcf, 0xb3, 0xb3, 0xb3, 0x1e, 0x54, 0x0, 0x1, 0x8f,
     420             :         0xb6, 0xb6, 0xb6, 0x1c, 0xb2, 0xb2, 0xb2, 0xe4, 0x54, 0x0, 0x1d, 0x7, 0x5c, 0x0, 0x6e, 0xe3,
     421             :         0xb3, 0xb3, 0xb3, 0x1b, 0x0, 0xfc, 0x0, 0x1f, 0xcd, 0x54, 0x0, 0x25, 0x7, 0x4, 0x0, 0x57,
     422             :         0xcb, 0xbf, 0xbf, 0xbf, 0x8, 0x0, 0x1, 0x1f, 0x7d, 0x2c, 0x0, 0x5, 0x7f, 0xc0, 0xc0, 0xc0,
     423             :         0xff, 0xc5, 0xc5, 0xc5, 0x4, 0x0, 0x6, 0x3c, 0xbc, 0xbc, 0xbc, 0x74, 0x1, 0x14, 0x78, 0xf8,
     424             :         0x1, 0xf, 0xa4, 0x1, 0x9, 0x7f, 0xcb, 0xcb, 0xcb, 0xff, 0xd4, 0xd4, 0xd4, 0x4, 0x0, 0x2,
     425             :         0x31, 0xd8, 0xd8, 0xd8, 0x5c, 0x0, 0xc, 0xcc, 0x1, 0x0, 0x28, 0x2, 0x4f, 0xb2, 0xb2, 0xb2,
     426             :         0x63, 0xf8, 0x0, 0x25, 0x0, 0x5c, 0x0, 0xc, 0x58, 0x0, 0x3, 0x4, 0x0, 0x13, 0x60, 0xa0,
     427             :         0x2, 0x9, 0x18, 0x0, 0x7f, 0xcf, 0xcf, 0xcf, 0xff, 0xec, 0xec, 0xec, 0x4, 0x0, 0x6, 0x3e,
     428             :         0xdd, 0xdd, 0xdd, 0x58, 0x0, 0xa, 0xc4, 0x1, 0x5c, 0xae, 0xb2, 0xb2, 0xb2, 0xdb, 0x18, 0x0,
     429             :         0xbd, 0xd9, 0xd9, 0xd9, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0xe2, 0xe2, 0xe2, 0x4, 0x0, 0x31, 0xf4,
     430             :         0xf4, 0xf4, 0x5c, 0x0, 0xf, 0xb0, 0x0, 0xc, 0x0, 0x3c, 0x3, 0x1f, 0xf3, 0x58, 0x0, 0x1,
     431             :         0x3f, 0xf6, 0xf6, 0xf6, 0xfc, 0x0, 0x2, 0x0, 0x5c, 0x0, 0xf, 0x58, 0x0, 0x10, 0x1f, 0xf3,
     432             :         0x58, 0x0, 0x44, 0x5f, 0xf1, 0xb1, 0xb1, 0xb1, 0xd9, 0x58, 0x0, 0x40, 0x10, 0xd7, 0x44, 0x4,
     433             :         0xf, 0x58, 0x0, 0x25, 0x0, 0x84, 0x2, 0x0, 0xe0, 0x2, 0x1e, 0xb2, 0x28, 0x0, 0x10, 0xad,
     434             :         0x98, 0x4, 0xf, 0x58, 0x0, 0x25, 0xf, 0x90, 0x4, 0x8, 0x10, 0x5e, 0x18, 0x3, 0x3, 0x98,
     435             :         0x4, 0x9, 0x58, 0x0, 0x31, 0xfe, 0xfe, 0xfe, 0x5c, 0x0, 0xc, 0x4, 0x0, 0x0, 0x28, 0x2,
     436             :         0xf, 0x58, 0x0, 0xc, 0x50, 0xef, 0xaf, 0xaf, 0xaf, 0x10, 0x74, 0x3, 0x0, 0xec, 0x4, 0x8,
     437             :         0x1c, 0x0, 0x0, 0x34, 0x1, 0x0, 0x5c, 0x0, 0xf, 0x4, 0x0, 0x5, 0x0, 0xe0, 0x2, 0xf,
     438             :         0x80, 0x4, 0x8, 0x14, 0x76, 0x20, 0x4, 0x0, 0x2c, 0x4, 0x0, 0x34, 0x4, 0xf, 0x78, 0x4,
     439             :         0x30, 0x18, 0xc9, 0x78, 0x4, 0x0, 0x1, 0x0, 0x0, 0xe4, 0x4, 0x0, 0xec, 0x4, 0xf, 0x54,
     440             :         0x0, 0x28, 0x10, 0xe2, 0xc0, 0x5, 0xf, 0xd8, 0x5, 0x8, 0x1f, 0xc9, 0x54, 0x0, 0x20, 0x1f,
     441             :         0xce, 0xd8, 0x5, 0x5, 0x8, 0x14, 0x1, 0x0, 0xec, 0x4, 0xc, 0xcc, 0x1, 0xf, 0xa4, 0x1,
     442             :         0x5, 0x0, 0x50, 0x1, 0x4f, 0xb6, 0xb6, 0xb6, 0x7, 0xe8, 0x6, 0x15, 0x3, 0xec, 0x4, 0x13,
     443             :         0x60, 0xe0, 0x2, 0x17, 0xd7, 0x9c, 0x3, 0x10, 0xd7, 0x58, 0x4, 0x44, 0xb1, 0xb1, 0xb1, 0x5f,
     444             :         0xf8, 0x1, 0xf, 0x1, 0x0, 0x1, 0xf0, 0x0, 0x66, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x16,
     445             :         0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 0x16,
     446             : };
     447             : 
     448           0 : WaylandLibrary *WaylandLibrary::getInstance() {
     449           0 :         return s_WaylandLibrary;
     450             : }
     451             : 
     452          20 : WaylandLibrary::~WaylandLibrary() {
     453          10 :         close();
     454          20 : }
     455             : 
     456          10 : WaylandLibrary::WaylandLibrary() {
     457             : 
     458          10 : }
     459             : 
     460          10 : bool WaylandLibrary::init() {
     461             : #ifndef XL_LINK
     462          10 :         _handle = Dso("libwayland-client.so");
     463          10 :         if (!_handle) {
     464           0 :                 return false;
     465             :         }
     466             : #endif
     467          10 :         if (open(_handle)) {
     468          10 :                 s_WaylandLibrary = this;
     469          10 :                 openConnection(_pending);
     470          10 :                 return _pending.display != nullptr;
     471             :         } else {
     472           0 :                 _handle = Dso();
     473             :         }
     474           0 :         return false;
     475             : }
     476             : 
     477          10 : void WaylandLibrary::close() {
     478          10 :         if (_pending.display) {
     479           0 :                 wl_display_disconnect(_pending.display);
     480           0 :                 _pending.display = nullptr;
     481             :         }
     482             : 
     483          10 :         if (viewporter) {
     484          10 :                 delete viewporter;
     485          10 :                 viewporter = nullptr;
     486             :         }
     487             : 
     488          10 :         if (xdg) {
     489          10 :                 delete xdg;
     490          10 :                 xdg = nullptr;
     491             :         }
     492             : 
     493          10 :         if (s_WaylandLibrary == this) {
     494          10 :                 s_WaylandLibrary = nullptr;
     495             :         }
     496          10 : }
     497             : 
     498           0 : WaylandLibrary::ConnectionData WaylandLibrary::acquireConnection() {
     499           0 :         if (_pending.display) {
     500           0 :                 _current = _pending;
     501           0 :                 _pending = ConnectionData({nullptr});
     502           0 :                 return _current;
     503             :         } else {
     504           0 :                 openConnection(_current);
     505           0 :                 return _current;
     506             :         }
     507             : }
     508             : 
     509           0 : WaylandLibrary::ConnectionData WaylandLibrary::getActiveConnection() const {
     510           0 :         if (_pending.display) {
     511           0 :                 return _pending;
     512             :         } else {
     513           0 :                 return _current;
     514             :         }
     515             : }
     516             : 
     517           0 : bool WaylandLibrary::ownsProxy(wl_proxy *proxy) {
     518           0 :         auto tag = getInstance()->wl_proxy_get_tag(proxy);
     519           0 :         return tag == &s_XenolithWaylandTag;
     520             : }
     521             : 
     522           0 : bool WaylandLibrary::ownsProxy(wl_output *output) {
     523           0 :         return ownsProxy((struct wl_proxy *) output);
     524             : }
     525             : 
     526           0 : bool WaylandLibrary::ownsProxy(wl_surface *surface) {
     527           0 :         return ownsProxy((struct wl_proxy *) surface);
     528             : }
     529             : 
     530          10 : bool WaylandLibrary::open(Dso &handle) {
     531             : #if XL_LINK
     532             :         this->wl_registry_interface = &::wl_registry_interface;
     533             :         this->wl_compositor_interface = &::wl_compositor_interface;
     534             :         this->wl_output_interface = &::wl_output_interface;
     535             :         this->wl_seat_interface = &::wl_seat_interface;
     536             :         this->wl_surface_interface = &::wl_surface_interface;
     537             :         this->wl_region_interface = &::wl_region_interface;
     538             :         this->wl_callback_interface = &::wl_callback_interface;
     539             :         this->wl_pointer_interface = &::wl_pointer_interface;
     540             :         this->wl_keyboard_interface = &::wl_keyboard_interface;
     541             :         this->wl_touch_interface = &::wl_touch_interface;
     542             :         this->wl_shm_interface = &::wl_shm_interface;
     543             :         this->wl_subcompositor_interface = &::wl_subcompositor_interface;
     544             :         this->wl_subsurface_interface = &::wl_subsurface_interface;
     545             :         this->wl_shm_pool_interface = &::wl_shm_pool_interface;
     546             :         this->wl_buffer_interface = &::wl_buffer_interface;
     547             : 
     548             :         this->wl_display_connect = &::wl_display_connect;
     549             :         this->wl_display_get_fd = &::wl_display_get_fd;
     550             :         this->wl_display_dispatch = &::wl_display_dispatch;
     551             :         this->wl_display_dispatch_pending = &::wl_display_dispatch_pending;
     552             :         this->wl_display_prepare_read = &::wl_display_prepare_read;
     553             :         this->wl_display_flush = &::wl_display_flush;
     554             :         this->wl_display_read_events = &::wl_display_read_events;
     555             :         this->wl_display_disconnect = &::wl_display_disconnect;
     556             :         this->wl_proxy_marshal_flags = &::wl_proxy_marshal_flags;
     557             :         this->wl_proxy_get_version = &::wl_proxy_get_version;
     558             :         this->wl_proxy_add_listener = &::wl_proxy_add_listener;
     559             :         this->wl_proxy_set_user_data = &::wl_proxy_set_user_data;
     560             :         this->wl_proxy_get_user_data = &::wl_proxy_get_user_data;
     561             :         this->wl_proxy_set_tag = &::wl_proxy_set_tag;
     562             :         this->wl_proxy_get_tag = &::wl_proxy_get_tag;
     563             :         this->wl_proxy_destroy = &::wl_proxy_destroy;
     564             :         this->wl_display_roundtrip = &::wl_display_roundtrip;
     565             : #else
     566          10 :         this->wl_registry_interface = handle.sym<decltype(this->wl_registry_interface)>("wl_registry_interface");
     567          10 :         this->wl_compositor_interface = handle.sym<decltype(this->wl_compositor_interface)>("wl_compositor_interface");
     568          10 :         this->wl_output_interface = handle.sym<decltype(this->wl_output_interface)>("wl_output_interface");
     569          10 :         this->wl_seat_interface = handle.sym<decltype(this->wl_seat_interface)>("wl_seat_interface");
     570          10 :         this->wl_surface_interface = handle.sym<decltype(this->wl_surface_interface)>("wl_surface_interface");
     571          10 :         this->wl_region_interface = handle.sym<decltype(this->wl_region_interface)>("wl_region_interface");
     572          10 :         this->wl_callback_interface = handle.sym<decltype(this->wl_callback_interface)>("wl_callback_interface");
     573          10 :         this->wl_pointer_interface = handle.sym<decltype(this->wl_callback_interface)>("wl_pointer_interface");
     574          10 :         this->wl_keyboard_interface = handle.sym<decltype(this->wl_keyboard_interface)>("wl_keyboard_interface");
     575          10 :         this->wl_touch_interface = handle.sym<decltype(this->wl_touch_interface)>("wl_touch_interface");
     576          10 :         this->wl_shm_interface = handle.sym<decltype(this->wl_shm_interface)>("wl_shm_interface");
     577          10 :         this->wl_subcompositor_interface = handle.sym<decltype(this->wl_subcompositor_interface)>("wl_subcompositor_interface");
     578          10 :         this->wl_subsurface_interface = handle.sym<decltype(this->wl_subsurface_interface)>("wl_subsurface_interface");
     579          10 :         this->wl_shm_pool_interface = handle.sym<decltype(this->wl_shm_pool_interface)>("wl_shm_pool_interface");
     580          10 :         this->wl_buffer_interface = handle.sym<decltype(this->wl_buffer_interface)>("wl_buffer_interface");
     581             : 
     582          10 :         this->wl_display_connect = handle.sym<decltype(this->wl_display_connect)>("wl_display_connect");
     583          10 :         this->wl_display_get_fd = handle.sym<decltype(this->wl_display_get_fd)>("wl_display_get_fd");
     584          10 :         this->wl_display_dispatch = handle.sym<decltype(this->wl_display_dispatch)>("wl_display_dispatch");
     585          10 :         this->wl_display_dispatch_pending = handle.sym<decltype(this->wl_display_dispatch_pending)>("wl_display_dispatch_pending");
     586          10 :         this->wl_display_prepare_read = handle.sym<decltype(this->wl_display_prepare_read)>("wl_display_prepare_read");
     587          10 :         this->wl_display_flush = handle.sym<decltype(this->wl_display_flush)>("wl_display_flush");
     588          10 :         this->wl_display_read_events = handle.sym<decltype(this->wl_display_read_events)>("wl_display_read_events");
     589          10 :         this->wl_display_disconnect = handle.sym<decltype(this->wl_display_disconnect)>("wl_display_disconnect");
     590          10 :         this->wl_proxy_marshal_flags = handle.sym<decltype(this->wl_proxy_marshal_flags)>("wl_proxy_marshal_flags");
     591          10 :         this->wl_proxy_get_version = handle.sym<decltype(this->wl_proxy_get_version)>("wl_proxy_get_version");
     592          10 :         this->wl_proxy_add_listener = handle.sym<decltype(this->wl_proxy_add_listener)>("wl_proxy_add_listener");
     593          10 :         this->wl_proxy_set_user_data = handle.sym<decltype(this->wl_proxy_set_user_data)>("wl_proxy_set_user_data");
     594          10 :         this->wl_proxy_get_user_data = handle.sym<decltype(this->wl_proxy_get_user_data)>("wl_proxy_get_user_data");
     595          10 :         this->wl_proxy_set_tag = handle.sym<decltype(this->wl_proxy_set_tag)>("wl_proxy_set_tag");
     596          10 :         this->wl_proxy_get_tag = handle.sym<decltype(this->wl_proxy_get_tag)>("wl_proxy_get_tag");
     597          10 :         this->wl_proxy_destroy = handle.sym<decltype(this->wl_proxy_destroy)>("wl_proxy_destroy");
     598          10 :         this->wl_display_roundtrip = handle.sym<decltype(this->wl_display_roundtrip)>("wl_display_roundtrip");
     599             : #endif
     600             : 
     601          10 :         if (this->wl_registry_interface
     602          10 :                         && this->wl_compositor_interface
     603          10 :                         && this->wl_output_interface
     604          10 :                         && this->wl_seat_interface
     605          10 :                         && this->wl_surface_interface
     606          10 :                         && this->wl_region_interface
     607          10 :                         && this->wl_callback_interface
     608          10 :                         && this->wl_pointer_interface
     609          10 :                         && this->wl_keyboard_interface
     610          10 :                         && this->wl_touch_interface
     611          10 :                         && this->wl_shm_interface
     612          10 :                         && this->wl_subcompositor_interface
     613          10 :                         && this->wl_subsurface_interface
     614          10 :                         && this->wl_shm_pool_interface
     615          10 :                         && this->wl_buffer_interface
     616          10 :                         && this->wl_display_connect
     617          10 :                         && this->wl_display_get_fd
     618          10 :                         && this->wl_display_dispatch
     619          10 :                         && this->wl_display_disconnect
     620          10 :                         && this->wl_proxy_marshal_flags
     621          10 :                         && this->wl_proxy_get_version
     622          10 :                         && this->wl_proxy_add_listener
     623          10 :                         && this->wl_proxy_set_user_data
     624          10 :                         && this->wl_proxy_get_user_data
     625          10 :                         && this->wl_proxy_set_tag
     626          10 :                         && this->wl_proxy_get_tag
     627          10 :                         && this->wl_proxy_destroy
     628          10 :                         && this->wl_display_roundtrip
     629          10 :                         && this->wl_registry_interface) {
     630          10 :                 viewporter = new ViewporterInterface(wl_surface_interface);
     631          10 :                 xdg = new XdgInterface(wl_output_interface, wl_seat_interface, wl_surface_interface);
     632             : 
     633          10 :                 wp_viewporter_interface = &viewporter->wp_viewporter_interface;
     634          10 :                 wp_viewport_interface = &viewporter->wp_viewport_interface;
     635             : 
     636          10 :                 xdg_wm_base_interface = &xdg->xdg_wm_base_interface;
     637          10 :                 xdg_positioner_interface = &xdg->xdg_positioner_interface;
     638          10 :                 xdg_surface_interface = &xdg->xdg_surface_interface;
     639          10 :                 xdg_toplevel_interface = &xdg->xdg_toplevel_interface;
     640          10 :                 xdg_popup_interface = &xdg->xdg_popup_interface;
     641             : 
     642             : #ifndef XL_LINK
     643          10 :                 _cursor = Dso("libwayland-cursor.so");
     644             : #endif
     645          10 :                 if (!openWaylandCursor(_cursor)) {
     646           0 :                         _cursor = Dso();
     647             :                 }
     648          10 :                 return true;
     649             :         }
     650           0 :         return false;
     651             : }
     652             : 
     653          10 : bool WaylandLibrary::openWaylandCursor(Dso &handle) {
     654             : #if XL_LINK
     655             :         this->wl_cursor_theme_load = &::wl_cursor_theme_load;
     656             :         this->wl_cursor_theme_destroy = &::wl_cursor_theme_destroy;
     657             :         this->wl_cursor_theme_get_cursor = &::wl_cursor_theme_get_cursor;
     658             :         this->wl_cursor_image_get_buffer = &::wl_cursor_image_get_buffer;
     659             : #else
     660          10 :         if (!handle) {
     661           0 :                 return false;
     662             :         }
     663             : 
     664          10 :         this->wl_cursor_theme_load = handle.sym<decltype(this->wl_cursor_theme_load)>("wl_cursor_theme_load");
     665          10 :         this->wl_cursor_theme_destroy = handle.sym<decltype(this->wl_cursor_theme_destroy)>("wl_cursor_theme_destroy");
     666          10 :         this->wl_cursor_theme_get_cursor = handle.sym<decltype(this->wl_cursor_theme_get_cursor)>("wl_cursor_theme_get_cursor");
     667          10 :         this->wl_cursor_image_get_buffer = handle.sym<decltype(this->wl_cursor_image_get_buffer)>("wl_cursor_image_get_buffer");
     668             : #endif
     669          10 :         return this->wl_cursor_theme_load
     670          10 :                 && this->wl_cursor_theme_destroy
     671          10 :                 && this->wl_cursor_theme_get_cursor
     672          20 :                 && this->wl_cursor_image_get_buffer;
     673             : }
     674             : 
     675          10 : void WaylandLibrary::openConnection(ConnectionData &data) {
     676          10 :         data.display = wl_display_connect(NULL);
     677          10 : }
     678             : 
     679             : static const xdg_wm_base_listener s_XdgWmBaseListener{
     680           0 :         [] (void *data, xdg_wm_base *xdg_wm_base, uint32_t serial) {
     681           0 :                 ((WaylandDisplay *)data)->wayland->xdg_wm_base_pong(xdg_wm_base, serial);
     682           0 :         },
     683             : };
     684             : 
     685             : static const wl_registry_listener s_WaylandRegistryListener{
     686           0 :         [] (void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) {
     687           0 :                 auto display = (WaylandDisplay *)data;
     688           0 :                 auto wayland = display->wayland.get();
     689             : 
     690             :                 XL_WAYLAND_LOG("handleGlobal: '", interface, "', version: ", version, ", name: ", name);
     691           0 :                 if (strcmp(interface, wayland->wl_compositor_interface->name) == 0) {
     692           0 :                         display->compositor = static_cast<wl_compositor *>(wayland->wl_registry_bind(registry, name,
     693           0 :                                         wayland->wl_compositor_interface, std::min(version, 4U)));
     694           0 :                 } else if (strcmp(interface, wayland->wl_subcompositor_interface->name) == 0) {
     695           0 :                         display->subcompositor = static_cast<wl_subcompositor *>(wayland->wl_registry_bind(registry, name,
     696             :                                         wayland->wl_subcompositor_interface, 1U));
     697           0 :                 } else if (strcmp(interface, wayland->wl_output_interface->name) == 0) {
     698           0 :                         auto out = Rc<WaylandOutput>::create(wayland, registry, name, version);
     699           0 :                         display->outputs.emplace_back(move(out));
     700           0 :                 } else if (strcmp(interface, wayland->wp_viewporter_interface->name) == 0) {
     701           0 :                         display->viewporter = static_cast<struct wp_viewporter *>(wayland->wl_registry_bind(registry, name,
     702             :                                         wayland->wp_viewporter_interface, 1));
     703           0 :                 } else if (strcmp(interface, wayland->xdg_wm_base_interface->name) == 0) {
     704           0 :                         display->xdgWmBase = static_cast<struct xdg_wm_base *>(wayland->wl_registry_bind(registry, name,
     705           0 :                                         wayland->xdg_wm_base_interface, std::min(version, 2U)));
     706           0 :                         wayland->xdg_wm_base_add_listener(display->xdgWmBase, &s_XdgWmBaseListener, display);
     707           0 :                 } else if (strcmp(interface, wayland->wl_shm_interface->name) == 0) {
     708           0 :                         display->shm = Rc<WaylandShm>::create(wayland, registry, name, version);
     709           0 :                 } else if (strcmp(interface, wayland->wl_seat_interface->name) == 0) {
     710           0 :                         display->seat = Rc<WaylandSeat>::create(wayland, display, registry, name, version);
     711             :                 }
     712           0 :         },
     713           0 :         [] (void *data, struct wl_registry *registry, uint32_t name) {
     714             :                 //auto display = (WaylandDisplay *)data;
     715             : 
     716           0 :         },
     717             : };
     718             : 
     719           0 : WaylandDisplay::~WaylandDisplay() {
     720           0 :         if (xdgWmBase) {
     721           0 :                 wayland->xdg_wm_base_destroy(xdgWmBase);
     722           0 :                 xdgWmBase = nullptr;
     723             :         }
     724           0 :         if (compositor) {
     725           0 :                 wayland->wl_compositor_destroy(compositor);
     726           0 :                 compositor = nullptr;
     727             :         }
     728           0 :         if (subcompositor) {
     729           0 :                 wayland->wl_subcompositor_destroy(subcompositor);
     730           0 :                 subcompositor = nullptr;
     731             :         }
     732           0 :         if (viewporter) {
     733           0 :                 wayland->wp_viewporter_destroy(viewporter);
     734           0 :                 viewporter = nullptr;
     735             :         }
     736             : 
     737           0 :         shm = nullptr;
     738           0 :         seat = nullptr;
     739           0 :         outputs.clear();
     740             : 
     741           0 :         if (display) {
     742           0 :                 wayland->wl_display_disconnect(display);
     743           0 :                 display = nullptr;
     744             :         }
     745           0 : }
     746             : 
     747           0 : bool WaylandDisplay::init(const Rc<WaylandLibrary> &lib) {
     748           0 :         wayland = lib;
     749             : 
     750           0 :         auto connection = wayland->acquireConnection();
     751             : 
     752           0 :         display = connection.display;
     753             : 
     754           0 :         struct wl_registry *registry = wayland->wl_display_get_registry(display);
     755             : 
     756           0 :         wayland->wl_registry_add_listener(registry, &s_WaylandRegistryListener, this);
     757           0 :         wayland->wl_display_roundtrip(display); // registry
     758           0 :         wayland->wl_display_roundtrip(display); // seats and outputs
     759           0 :         wayland->wl_registry_destroy(registry);
     760             : 
     761           0 :         xkb = XkbLibrary::getInstance();
     762           0 :         return true;
     763             : }
     764             : 
     765           0 : wl_surface *WaylandDisplay::createSurface(WaylandViewInterface *view) {
     766           0 :         auto surface = wayland->wl_compositor_create_surface(compositor);
     767           0 :         wayland->wl_surface_set_user_data(surface, view);
     768           0 :         wayland->wl_proxy_set_tag((struct wl_proxy *) surface, &s_XenolithWaylandTag);
     769           0 :         surfaces.emplace(surface);
     770           0 :         return surface;
     771             : }
     772             : 
     773           0 : void WaylandDisplay::destroySurface(wl_surface *surface) {
     774           0 :         surfaces.erase(surface);
     775           0 :         wayland->wl_surface_destroy(surface);
     776           0 : }
     777             : 
     778           0 : wl_surface *WaylandDisplay::createDecorationSurface(WaylandDecoration *decor) {
     779           0 :         auto surface = wayland->wl_compositor_create_surface(compositor);
     780           0 :         wayland->wl_surface_set_user_data(surface, decor);
     781           0 :         wayland->wl_proxy_set_tag((struct wl_proxy *) surface, &s_XenolithWaylandTag);
     782           0 :         decorations.emplace(surface);
     783           0 :         return surface;
     784             : }
     785             : 
     786           0 : void WaylandDisplay::destroyDecorationSurface(wl_surface *surface) {
     787           0 :         decorations.erase(surface);
     788           0 :         wayland->wl_surface_destroy(surface);
     789           0 : }
     790             : 
     791           0 : bool WaylandDisplay::ownsSurface(wl_surface *surface) const {
     792           0 :         return surfaces.find(surface) != surfaces.end();
     793             : }
     794             : 
     795           0 : bool WaylandDisplay::isDecoration(wl_surface *surface) const {
     796           0 :         return decorations.find(surface) != decorations.end();
     797             : }
     798             : 
     799           0 : bool WaylandDisplay::flush() {
     800           0 :         while (wayland->wl_display_prepare_read(display) != 0) {
     801           0 :                 wayland->wl_display_dispatch_pending(display);
     802             :         }
     803             : 
     804           0 :         while (wayland->wl_display_flush(display) == -1) {
     805           0 :                 if (errno != EAGAIN) {
     806           0 :                         return false;
     807             :                 }
     808             : 
     809           0 :                 struct pollfd fd = { getSocketFd(), POLLOUT };
     810             : 
     811           0 :                 while (::poll(&fd, 1, -1) == -1) {
     812           0 :                         if (errno != EINTR && errno != EAGAIN) {
     813           0 :                                 return false;
     814             :                         }
     815             :                 }
     816             :         }
     817             : 
     818           0 :         wayland->wl_display_read_events(display);
     819           0 :         wayland->wl_display_dispatch_pending(display);
     820             : 
     821           0 :         return true;
     822             : }
     823             : 
     824           0 : int WaylandDisplay::getSocketFd() const {
     825           0 :         return wayland->wl_display_get_fd(display);
     826             : }
     827             : 
     828           0 : WaylandCursorTheme::~WaylandCursorTheme() {
     829           0 :         if (cursorTheme) {
     830           0 :                 wayland->wl_cursor_theme_destroy(cursorTheme);
     831           0 :                 cursorTheme = nullptr;
     832             :         }
     833           0 : }
     834             : 
     835           0 : static const char *getCursorName(WaylandCursorImage image) {
     836           0 :         switch (image) {
     837           0 :         case WaylandCursorImage::LeftPtr: return "left_ptr"; break;
     838           0 :         case WaylandCursorImage::EResize: return "right_side"; break;
     839           0 :         case WaylandCursorImage::NEResize: return "top_right_corner"; break;
     840           0 :         case WaylandCursorImage::NResize: return "top_side"; break;
     841           0 :         case WaylandCursorImage::NWResize: return "top_left_corner"; break;
     842           0 :         case WaylandCursorImage::SEResize: return "bottom_right_corner"; break;
     843           0 :         case WaylandCursorImage::SResize: return "bottom_side"; break;
     844           0 :         case WaylandCursorImage::SWResize: return "bottom_left_corner"; break;
     845           0 :         case WaylandCursorImage::WResize: return "left_side"; break;
     846           0 :         case WaylandCursorImage::Max: break;
     847             :         }
     848           0 :         return nullptr;
     849             : }
     850             : 
     851           0 : bool WaylandCursorTheme::init(WaylandDisplay *display, StringView name, int size) {
     852           0 :         wayland = display->wayland;
     853           0 :         cursorSize = size;
     854           0 :         cursorName = name.str<Interface>();
     855           0 :         cursorTheme = wayland->wl_cursor_theme_load(name.data(), size, display->shm->shm);
     856             : 
     857           0 :         if (cursorTheme) {
     858           0 :                 for (int i = 0; i < toInt(WaylandCursorImage::Max); ++ i) {
     859           0 :                         auto name = getCursorName(WaylandCursorImage(i));
     860           0 :                         auto cursor = wayland->wl_cursor_theme_get_cursor(cursorTheme, name);
     861           0 :                         cursors.emplace_back(cursor);
     862             :                 }
     863           0 :                 return true;
     864             :         }
     865             : 
     866           0 :         return false;
     867             : }
     868             : 
     869           0 : void WaylandCursorTheme::setCursor(WaylandSeat *seat) {
     870           0 :         setCursor(seat->pointer, seat->cursorSurface, seat->serial, seat->cursorImage, seat->pointerScale);
     871           0 : }
     872             : 
     873           0 : void WaylandCursorTheme::setCursor(wl_pointer *pointer, wl_surface *cursorSurface, uint32_t serial, WaylandCursorImage img, int scale) {
     874           0 :         if (!cursorTheme || cursors.size() <= size_t(toInt(img))) {
     875           0 :                 return;
     876             :         }
     877             : 
     878           0 :         auto cursor = cursors[toInt(img)];
     879           0 :         if (!cursor) {
     880           0 :                 cursor = cursors[0];
     881             :         }
     882             : 
     883           0 :         auto image = cursor->images[0];
     884           0 :         auto buffer = wayland->wl_cursor_image_get_buffer(image);
     885           0 :         wayland->wl_pointer_set_cursor(pointer, serial, cursorSurface, image->hotspot_x / scale, image->hotspot_y / scale);
     886           0 :         wayland->wl_surface_attach(cursorSurface, buffer, 0, 0);
     887           0 :         wayland->wl_surface_set_buffer_scale(cursorSurface, scale);
     888           0 :         wayland->wl_surface_damage_buffer(cursorSurface, 0, 0, image->width, image->height);
     889           0 :         wayland->wl_surface_commit(cursorSurface);
     890             : }
     891             : 
     892             : static struct wl_shm_listener s_WaylandShmListener = {
     893           0 :         [] (void *data, wl_shm *shm, uint32_t format) {
     894           0 :                 ((WaylandShm *)data)->format = format;
     895           0 :         }
     896             : };
     897             : 
     898           0 : static int createAnonymousFile(off_t size) {
     899             :         static const char tpl[] = "/xl-wayland-XXXXXX";
     900             :         const char* path;
     901             :         int fd;
     902             :         int ret;
     903             : 
     904           0 :         fd = ::memfd_create("xl-wayland", MFD_CLOEXEC | MFD_ALLOW_SEALING);
     905           0 :         if (fd >= 0) {
     906           0 :                 ::fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
     907             :         } else {
     908           0 :                 path = getenv("XDG_RUNTIME_DIR");
     909           0 :                 if (!path) {
     910           0 :                         errno = ENOENT;
     911           0 :                         return -1;
     912             :                 }
     913             : 
     914           0 :                 char* tmpname = (char *)::calloc(strlen(path) + sizeof(tpl), 1);
     915           0 :                 ::strcpy(tmpname, path);
     916           0 :                 ::strcat(tmpname, tpl);
     917             : 
     918           0 :                 fd = ::mkostemp(tmpname, O_CLOEXEC);
     919           0 :                 if (fd >= 0) {
     920           0 :                         ::unlink(tmpname);
     921           0 :                         ::free(tmpname);
     922             :                 } else {
     923           0 :                         ::free(tmpname);
     924           0 :                         return -1;
     925             :                 }
     926             :         }
     927             : 
     928           0 :         ret = ::posix_fallocate(fd, 0, size);
     929           0 :         if (ret != 0) {
     930           0 :                 ::close(fd);
     931           0 :                 errno = ret;
     932           0 :                 return -1;
     933             :         }
     934           0 :         return fd;
     935             : }
     936             : 
     937           0 : WaylandBuffer::~WaylandBuffer() {
     938           0 :         if (buffer) {
     939           0 :                 wayland->wl_buffer_destroy(buffer);
     940           0 :                 buffer = nullptr;
     941             :         }
     942           0 : }
     943             : 
     944           0 : bool WaylandBuffer::init(WaylandLibrary *lib, wl_shm_pool *pool, int32_t offset,
     945             :                 int32_t w, int32_t h, int32_t stride, uint32_t format) {
     946           0 :         wayland = lib;
     947           0 :         width = w;
     948           0 :         height = h;
     949           0 :         buffer = wayland->wl_shm_pool_create_buffer(pool, offset, width, height, stride, format);
     950           0 :         return true;
     951             : }
     952             : 
     953           0 : WaylandShm::~WaylandShm() {
     954           0 :         if (shm) {
     955           0 :                 wayland->wl_shm_destroy(shm);
     956           0 :                 shm = nullptr;
     957             :         }
     958           0 : }
     959             : 
     960           0 : bool WaylandShm::init(const Rc<WaylandLibrary> &lib, wl_registry *registry, uint32_t name, uint32_t version) {
     961           0 :         wayland = lib;
     962           0 :         id = name;
     963           0 :         shm = static_cast<wl_shm*>(wayland->wl_registry_bind(registry, name,
     964           0 :                         wayland->wl_shm_interface, std::min(version, 1U)));
     965           0 :         wayland->wl_shm_set_user_data(shm, this);
     966           0 :         wayland->wl_shm_add_listener(shm, &s_WaylandShmListener, this);
     967           0 :         wayland->wl_proxy_set_tag((struct wl_proxy *) shm, &s_XenolithWaylandTag);
     968           0 :         return true;
     969             : }
     970             : 
     971           0 : static void makeGaussianVector(Color4B *retA, Color4B *retB, uint32_t size) {
     972           0 :         const float sigma = sqrtf((size * size) / (-2.0f * logf(1.0f / 255.0f)));
     973           0 :         const float sigma_v = -1.0f / (2.0f * sigma * sigma);
     974             : 
     975           0 :         for (uint32_t j = 0; j < size; j++) {
     976           0 :                 retA[j].a = (uint8_t)(24.0f * expf( (j * j) * sigma_v ));
     977           0 :                 retB[j].a = (uint8_t)(64.0f * expf( (j * j) * sigma_v ));
     978             :         }
     979           0 : }
     980             : 
     981           0 : static void makeGaussianRange(Color4B *retA, Color4B *retB, uint32_t size, uint32_t inset) {
     982           0 :         auto width = size + inset;
     983           0 :         auto targetA = retA;
     984           0 :         auto targetB = retA + width * width;
     985           0 :         auto targetC = retA + width * width * 2;
     986           0 :         auto targetD = retA + width * width * 3;
     987           0 :         auto targetE = retB;
     988           0 :         auto targetF = retB + width * width;
     989           0 :         auto targetG = retB + width * width * 2;
     990           0 :         auto targetH = retB + width * width * 3;
     991             : 
     992           0 :         const float sigma = sqrtf((size * size) / (-2.0f * logf(1.0f / 255.0f)));
     993           0 :         const float sigma_v = -1.0f / (2.0f * sigma * sigma);
     994             : 
     995           0 :         for (uint32_t i = 0; i < width; i++) {
     996           0 :                 for (uint32_t j = 0; j < width; j++) {
     997           0 :                         float dist = sqrtf( (i * i) + (j * j) );
     998           0 :                         float tmp = 0.0f;
     999           0 :                         if (dist <= inset) {
    1000           0 :                                 tmp = 1.0f;
    1001           0 :                         } else if (dist > size + inset) {
    1002           0 :                                 tmp = 0.0f;
    1003             :                         } else {
    1004           0 :                                 dist = dist - inset;
    1005           0 :                                 tmp = expf( (dist * dist) * sigma_v);
    1006             :                         }
    1007             : 
    1008           0 :                         auto valueA = (uint8_t)(24.0f * tmp);
    1009           0 :                         auto valueB = (uint8_t)(64.0f * tmp);
    1010           0 :                         targetA[i * width + j].a = valueA;
    1011           0 :                         targetB[(width - i - 1) * width + (width - j - 1)].a = valueA;
    1012           0 :                         targetC[(i) * width + (width - j - 1)].a = valueA;
    1013           0 :                         targetD[(width - i - 1) * width + (j)].a = valueA;
    1014           0 :                         targetE[i * width + j].a = valueB;
    1015           0 :                         targetF[(width - i - 1) * width + (width - j - 1)].a = valueB;
    1016           0 :                         targetG[(i) * width + (width - j - 1)].a = valueB;
    1017           0 :                         targetH[(width - i - 1) * width + (j)].a = valueB;
    1018             :                 }
    1019             :         }
    1020           0 : }
    1021             : 
    1022           0 : static void makeRoundedHeader(Color4B *retA, uint32_t size, const Color3B &colorA, const Color3B &colorB) {
    1023           0 :         auto targetA = retA;
    1024           0 :         auto targetB = retA + size * size * 1;
    1025           0 :         auto targetC = retA + size * size * 2;
    1026           0 :         auto targetD = retA + size * size * 3;
    1027             : 
    1028           0 :         Color4B tmpA = Color4B(colorA.b, colorA.g, colorA.r, 255);
    1029           0 :         Color4B tmpB = Color4B(colorB.b, colorB.g, colorB.r, 255);
    1030           0 :         for (uint32_t i = 0; i < size; i++) {
    1031           0 :                 for (uint32_t j = 0; j < size; j++) {
    1032           0 :                         auto u = size - i - 1;
    1033           0 :                         auto v = size - j - 1;
    1034           0 :                         float dist = sqrtf( (u * u) + (v * v) );
    1035           0 :                         if (dist >= size) {
    1036           0 :                                 targetA[i * size + j] = Color4B(0, 0, 0, 0);
    1037           0 :                                 targetB[i * size + j] = Color4B(0, 0, 0, 0);
    1038           0 :                                 targetC[i * size + (size - j - 1)] = Color4B(0, 0, 0, 0);
    1039           0 :                                 targetD[i * size + (size - j - 1)] = Color4B(0, 0, 0, 0);
    1040             :                         } else {
    1041           0 :                                 targetA[i * size + j] = tmpA;
    1042           0 :                                 targetB[i * size + j] = tmpB;
    1043           0 :                                 targetC[i * size + (size - j - 1)] = tmpA;
    1044           0 :                                 targetD[i * size + (size - j - 1)] = tmpB;
    1045             :                         }
    1046             :                 }
    1047             :         }
    1048           0 : }
    1049             : 
    1050           0 : bool WaylandShm::allocateDecorations(ShadowBuffers *ret, uint32_t width, uint32_t inset,
    1051             :                 const Color3B &header, const Color3B &headerActive) {
    1052             : 
    1053           0 :         auto size = width * sizeof(Color4B) * 8; // plain shadows
    1054           0 :         size += (width + inset) * (width + inset) * sizeof(Color4B) * 8; // cornerShadows
    1055           0 :         size += (inset * 2 * inset) * sizeof(Color4B) * 2;
    1056           0 :         size += 2 * sizeof(Color4B);
    1057             : 
    1058             :         struct IconData {
    1059             :                 WaylandDecorationName name;
    1060             :                 Value value;
    1061             :                 bool active;
    1062             :                 uint32_t width = 0;
    1063             :                 uint32_t height = 0;
    1064             :                 BytesView data;
    1065             :         };
    1066             : 
    1067           0 :         Vector<IconData> icons;
    1068             : 
    1069           0 :         auto loadData = [&] (WaylandDecorationName name, BytesView data, bool active) {
    1070           0 :                 auto &icon = icons.emplace_back(IconData{name, data::read<Interface>(data), active});
    1071           0 :                 icon.width = icon.value.getInteger("width");
    1072           0 :                 icon.height = icon.value.getInteger("height");
    1073           0 :                 icon.data = icon.value.getBytes("data");
    1074           0 :                 return icon.width * icon.height * sizeof(Color4B);
    1075           0 :         };
    1076             : 
    1077           0 :         size += loadData(WaylandDecorationName::IconClose, BytesView(s_iconClose, sizeof(s_iconClose)), false);
    1078           0 :         size += loadData(WaylandDecorationName::IconMaximize, BytesView(s_iconMaximize, sizeof(s_iconMaximize)), false);
    1079           0 :         size += loadData(WaylandDecorationName::IconMinimize, BytesView(s_iconMinimize, sizeof(s_iconMinimize)), false);
    1080           0 :         size += loadData(WaylandDecorationName::IconRestore, BytesView(s_iconRestore, sizeof(s_iconRestore)), false);
    1081           0 :         size += loadData(WaylandDecorationName::IconClose, BytesView(s_iconCloseActive, sizeof(s_iconCloseActive)), true);
    1082           0 :         size += loadData(WaylandDecorationName::IconMaximize, BytesView(s_iconMaximizeActive, sizeof(s_iconMaximizeActive)), true);
    1083           0 :         size += loadData(WaylandDecorationName::IconMinimize, BytesView(s_iconMinimizeActive, sizeof(s_iconMinimizeActive)), true);
    1084           0 :         size += loadData(WaylandDecorationName::IconRestore, BytesView(s_iconRestoreActive, sizeof(s_iconRestoreActive)), true);
    1085             : 
    1086           0 :         const int fd = createAnonymousFile(size);
    1087           0 :         if (fd < 0) {
    1088           0 :                 return false;
    1089             :         }
    1090             : 
    1091           0 :         auto data = ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    1092           0 :         if (data == MAP_FAILED) {
    1093           0 :                 ::close(fd);
    1094           0 :                 return false;
    1095             :         }
    1096             : 
    1097           0 :         auto pool = wayland->wl_shm_create_pool(shm, fd, size);
    1098           0 :         ::close(fd);
    1099             : 
    1100           0 :         auto targetA = (Color4B *)data;
    1101           0 :         auto targetB = (Color4B *)data + width * 4;
    1102           0 :         makeGaussianVector(targetA, targetB, width);
    1103             : 
    1104             :         // make normal
    1105           0 :         ::memcpy(targetA + width * 2, targetA, width * sizeof(Color4B));
    1106           0 :         ::memcpy(targetA + width * 3, targetA, width * sizeof(Color4B));
    1107           0 :         std::reverse(targetA, targetA + width);
    1108           0 :         ::memcpy(targetA + width * 1, targetA, width * sizeof(Color4B));
    1109             : 
    1110             :         // make active
    1111           0 :         ::memcpy(targetB + width * 2, targetB, width * sizeof(Color4B));
    1112           0 :         ::memcpy(targetB + width * 3, targetB, width * sizeof(Color4B));
    1113           0 :         std::reverse(targetB, targetB + width);
    1114           0 :         ::memcpy(targetB + width * 1, targetB, width * sizeof(Color4B));
    1115             : 
    1116           0 :         ret->top = Rc<WaylandBuffer>::create(wayland, pool, width * sizeof(Color4B) * 0,
    1117           0 :                         1, width, sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1118           0 :         ret->left = Rc<WaylandBuffer>::create(wayland, pool, width * sizeof(Color4B) * 1,
    1119           0 :                         width, 1, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1120           0 :         ret->bottom = Rc<WaylandBuffer>::create(wayland, pool, width * sizeof(Color4B) * 2,
    1121           0 :                         1, width, sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1122           0 :         ret->right = Rc<WaylandBuffer>::create(wayland, pool, width * sizeof(Color4B) * 3,
    1123           0 :                         width, 1, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1124           0 :         ret->topActive = Rc<WaylandBuffer>::create(wayland, pool, width * sizeof(Color4B) * 4,
    1125           0 :                         1, width, sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1126           0 :         ret->leftActive = Rc<WaylandBuffer>::create(wayland, pool, width * sizeof(Color4B) * 5,
    1127           0 :                         width, 1, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1128           0 :         ret->bottomActive = Rc<WaylandBuffer>::create(wayland, pool, width * sizeof(Color4B) * 6,
    1129           0 :                         1, width, sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1130           0 :         ret->rightActive = Rc<WaylandBuffer>::create(wayland, pool, width * sizeof(Color4B) * 7,
    1131           0 :                         width, 1, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1132             : 
    1133           0 :         auto offset = width * 8 * sizeof(Color4B);
    1134           0 :         targetA = (Color4B *)data + width * 8;
    1135           0 :         width += inset;
    1136           0 :         targetB = targetA + width * width * 4;
    1137           0 :         makeGaussianRange(targetA, targetB, width - inset, inset);
    1138             : 
    1139           0 :         ret->bottomRight = Rc<WaylandBuffer>::create(wayland, pool, offset,
    1140           0 :                         width, width, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1141           0 :         ret->topLeft = Rc<WaylandBuffer>::create(wayland, pool, offset + width * width * sizeof(Color4B),
    1142           0 :                         width, width, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1143           0 :         ret->bottomLeft = Rc<WaylandBuffer>::create(wayland, pool, offset + width * width * 2 * sizeof(Color4B),
    1144           0 :                         width, width, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1145           0 :         ret->topRight = Rc<WaylandBuffer>::create(wayland, pool, offset + width * width * 3 * sizeof(Color4B),
    1146           0 :                         width, width, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1147           0 :         ret->bottomRightActive =Rc<WaylandBuffer>::create(wayland, pool, offset + width * width * 4 * sizeof(Color4B),
    1148           0 :                         width, width, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1149           0 :         ret->topLeftActive = Rc<WaylandBuffer>::create(wayland, pool, offset + width * width * 5 * sizeof(Color4B),
    1150           0 :                         width, width, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1151           0 :         ret->bottomLeftActive = Rc<WaylandBuffer>::create(wayland, pool, offset + width * width * 6 * sizeof(Color4B),
    1152           0 :                         width, width, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1153           0 :         ret->topRightActive = Rc<WaylandBuffer>::create(wayland, pool, offset + width * width * 7 * sizeof(Color4B),
    1154           0 :                         width, width, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1155             : 
    1156           0 :         offset += width * width * 8 * sizeof(Color4B);
    1157           0 :         targetA = (Color4B *)((uint8_t *)data + offset);
    1158             : 
    1159           0 :         makeRoundedHeader(targetA, inset, header, headerActive);
    1160             : 
    1161           0 :         ret->headerLeft = Rc<WaylandBuffer>::create(wayland, pool, offset,
    1162           0 :                         inset, inset, inset * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1163           0 :         ret->headerLeftActive = Rc<WaylandBuffer>::create(wayland, pool, offset + inset * inset * sizeof(Color4B) * 1,
    1164           0 :                         inset, inset, inset * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1165           0 :         ret->headerRight = Rc<WaylandBuffer>::create(wayland, pool, offset + inset * inset * sizeof(Color4B) * 2,
    1166           0 :                         inset, inset, inset * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1167           0 :         ret->headerRightActive = Rc<WaylandBuffer>::create(wayland, pool, offset + inset * inset * sizeof(Color4B) * 3,
    1168           0 :                         inset, inset, inset * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1169             : 
    1170           0 :         offset += inset * inset * sizeof(Color4B) * 4;
    1171           0 :         targetA = (Color4B *)((uint8_t *)data + offset);
    1172           0 :         targetA[0] = Color4B(header.b, header.g, header.r, 255);
    1173           0 :         targetA[1] = Color4B(headerActive.b, headerActive.g, headerActive.r, 255);
    1174             : 
    1175           0 :         ret->headerCenter = Rc<WaylandBuffer>::create(wayland, pool, offset,
    1176           0 :                         1, 1, sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1177           0 :         ret->headerCenterActive = Rc<WaylandBuffer>::create(wayland, pool, offset + sizeof(Color4B),
    1178           0 :                         1, 1, sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1179             : 
    1180           0 :         offset += 2 * sizeof(Color4B);
    1181           0 :         targetA += 2;
    1182             : 
    1183           0 :         for (IconData &it : icons) {
    1184           0 :                 memcpy((uint8_t *)data + offset, it.data.data(), it.data.size());
    1185           0 :                 Rc<WaylandBuffer> buf = Rc<WaylandBuffer>::create(wayland, pool, offset,
    1186           0 :                         it.width, it.height, it.width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
    1187           0 :                 switch (it.name) {
    1188           0 :                 case WaylandDecorationName::IconClose:
    1189           0 :                         if (it.active) { ret->iconCloseActive = move(buf); } else { ret->iconClose = move(buf); }
    1190           0 :                         break;
    1191           0 :                 case WaylandDecorationName::IconMaximize:
    1192           0 :                         if (it.active) { ret->iconMaximizeActive = move(buf); } else { ret->iconMaximize = move(buf); }
    1193           0 :                         break;
    1194           0 :                 case WaylandDecorationName::IconMinimize:
    1195           0 :                         if (it.active) { ret->iconMinimizeActive = move(buf); } else { ret->iconMinimize = move(buf); }
    1196           0 :                         break;
    1197           0 :                 case WaylandDecorationName::IconRestore:
    1198           0 :                         if (it.active) { ret->iconRestoreActive = move(buf); } else { ret->iconRestore = move(buf); }
    1199           0 :                         break;
    1200           0 :                 default:
    1201           0 :                         break;
    1202             :                 }
    1203           0 :                 offset += it.data.size();
    1204           0 :         }
    1205             : 
    1206           0 :         ::munmap(data, size);
    1207           0 :         wayland->wl_shm_pool_destroy(pool);
    1208             : 
    1209           0 :         return true;
    1210           0 : }
    1211             : 
    1212             : static const wl_output_listener s_WaylandOutputListener{
    1213             :         // geometry
    1214           0 :         [] (void *data, wl_output *wl_output, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height,
    1215             :                         int32_t subpixel, char const *make, char const *model, int32_t transform) {
    1216           0 :                 auto out = ((WaylandOutput *)data);
    1217           0 :                 out->geometry = WaylandOutput::Geometry{x, y, physical_width, physical_height,
    1218           0 :                         subpixel, transform, make, model};
    1219           0 :                 if (out->name.empty()) {
    1220           0 :                         out->name = toString(make, " ", model);
    1221             :                 }
    1222           0 :         },
    1223             : 
    1224             :         // mode
    1225           0 :         [] (void *data, wl_output *output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
    1226           0 :                 ((WaylandOutput *)data)->mode = WaylandOutput::Mode{flags, width, height, refresh};
    1227           0 :         },
    1228             : 
    1229             :         // done
    1230           0 :         [] (void *data, wl_output* output) {
    1231             :                 // do nothing
    1232           0 :         },
    1233             : 
    1234             :         // scale
    1235           0 :         [] (void *data, wl_output* output, int32_t factor) {
    1236           0 :                 ((WaylandOutput *)data)->scale = factor;
    1237           0 :         },
    1238             : 
    1239             :         // name
    1240           0 :         [] (void *data, struct wl_output *wl_output, const char *name) {
    1241           0 :                 ((WaylandOutput *)data)->name = name;
    1242           0 :         },
    1243             : 
    1244             :         // description
    1245           0 :         [] (void *data, struct wl_output *wl_output, const char *name) {
    1246           0 :                 ((WaylandOutput *)data)->desc = name;
    1247           0 :         }
    1248             : };
    1249             : 
    1250           0 : WaylandOutput::~WaylandOutput() {
    1251           0 :         if (output) {
    1252           0 :                 wayland->wl_output_destroy(output);
    1253           0 :                 output = nullptr;
    1254             :         }
    1255           0 : }
    1256             : 
    1257           0 : bool WaylandOutput::init(const Rc<WaylandLibrary> &lib, wl_registry *registry, uint32_t name, uint32_t version) {
    1258           0 :         wayland = lib;
    1259           0 :         id = name;
    1260           0 :         output = static_cast<wl_output*>(wayland->wl_registry_bind(registry, name,
    1261           0 :                         wayland->wl_output_interface, std::min(version, 2U)));
    1262           0 :         wayland->wl_output_set_user_data(output, this);
    1263           0 :         wayland->wl_output_add_listener(output, &s_WaylandOutputListener, this);
    1264           0 :         wayland->wl_proxy_set_tag((struct wl_proxy *) output, &s_XenolithWaylandTag);
    1265           0 :         return true;
    1266             : }
    1267             : 
    1268           0 : String WaylandOutput::description() const {
    1269           0 :         StringStream stream;
    1270           0 :         stream << geometry.make << " " << geometry.model << ": "
    1271           0 :                         << mode.width << "x" << mode.height << "@" << mode.refresh / 1000 << "Hz (x" << scale << ");";
    1272           0 :         if (mode.flags & WL_OUTPUT_MODE_CURRENT) {
    1273           0 :                 stream << " Current;";
    1274             :         }
    1275           0 :         if (mode.flags & WL_OUTPUT_MODE_PREFERRED) {
    1276           0 :                 stream << " Preferred;";
    1277             :         }
    1278           0 :         if (!desc.empty()) {
    1279           0 :                 stream << " " << desc << ";";
    1280             :         }
    1281           0 :         return stream.str();
    1282           0 : }
    1283             : 
    1284             : static struct wl_pointer_listener s_WaylandPointerListener{
    1285             :         // enter
    1286           0 :         [] (void *data, wl_pointer *wl_pointer, uint32_t serial, wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
    1287           0 :                 auto seat = (WaylandSeat *)data;
    1288           0 :                 seat->pointerFocus = surface;
    1289           0 :                 seat->serial = serial;
    1290             : 
    1291           0 :                 if (!seat->root->ownsSurface(surface)) {
    1292           0 :                         if (seat->root->isDecoration(surface)) {
    1293           0 :                                 if (auto decor = (WaylandDecoration *)seat->wayland->wl_surface_get_user_data(surface)) {
    1294           0 :                                         if (decor->image != seat->cursorImage) {
    1295           0 :                                                 if (seat->cursorTheme) {
    1296           0 :                                                         seat->cursorImage = decor->image;
    1297           0 :                                                         seat->cursorTheme->setCursor(seat);
    1298             :                                                 }
    1299             :                                         }
    1300           0 :                                         seat->pointerDecorations.emplace(decor);
    1301           0 :                                         decor->onEnter();
    1302             :                                 }
    1303             :                         }
    1304           0 :                         return;
    1305             :                 }
    1306             : 
    1307           0 :                 if (auto view = (WaylandViewInterface *)seat->wayland->wl_surface_get_user_data(surface)) {
    1308           0 :                         seat->pointerViews.emplace(view);
    1309           0 :                         if (WaylandCursorImage::LeftPtr != seat->cursorImage) {
    1310           0 :                                 if (seat->cursorTheme) {
    1311           0 :                                         seat->cursorImage = WaylandCursorImage::LeftPtr;
    1312           0 :                                         seat->cursorTheme->setCursor(seat);
    1313             :                                 }
    1314             :                         }
    1315           0 :                         view->handlePointerEnter(surface_x, surface_y);
    1316             :                 }
    1317             :         },
    1318             : 
    1319             :         // leave
    1320           0 :         [] (void *data, wl_pointer *wl_pointer, uint32_t serial, wl_surface *surface) {
    1321           0 :                 auto seat = (WaylandSeat *)data;
    1322             : 
    1323           0 :                 if (seat->root->isDecoration(surface)) {
    1324           0 :                         if (auto decor = (WaylandDecoration *)seat->wayland->wl_surface_get_user_data(surface)) {
    1325           0 :                                 decor->waitForMove = false;
    1326           0 :                                 seat->pointerDecorations.erase(decor);
    1327           0 :                                 decor->onLeave();
    1328             :                         }
    1329             :                 }
    1330             : 
    1331           0 :                 if (seat->root->ownsSurface(surface)) {
    1332           0 :                         if (auto view = (WaylandViewInterface *)seat->wayland->wl_surface_get_user_data(surface)) {
    1333           0 :                                 view->handlePointerLeave();
    1334           0 :                                 seat->pointerViews.erase(view);
    1335             :                         }
    1336             :                 }
    1337             : 
    1338           0 :                 if (seat->pointerFocus == surface) {
    1339           0 :                         seat->pointerFocus = NULL;
    1340           0 :                         seat->cursorImage = WaylandCursorImage::Max;
    1341             :                 }
    1342           0 :         },
    1343             : 
    1344             :         // motion
    1345           0 :         [] (void *data, wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
    1346           0 :                 auto seat = (WaylandSeat *)data;
    1347           0 :                 for (auto &it : seat->pointerViews) {
    1348           0 :                         it->handlePointerMotion(time, surface_x, surface_y);
    1349             :                 }
    1350           0 :                 for (auto &it : seat->pointerDecorations) {
    1351           0 :                         it->handleMotion();
    1352             :                 }
    1353           0 :         },
    1354             : 
    1355             :         // button
    1356           0 :         [] (void *data, wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
    1357           0 :                 auto seat = (WaylandSeat *)data;
    1358           0 :                 for (auto &it : seat->pointerViews) {
    1359           0 :                         it->handlePointerButton(serial, time, button, state);
    1360             :                 }
    1361           0 :                 for (auto &it : seat->pointerDecorations) {
    1362           0 :                         it->handlePress(serial, button, state);
    1363             :                 }
    1364           0 :         },
    1365             : 
    1366             :         // axis
    1367           0 :         [] (void *data, wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value) {
    1368           0 :                 auto seat = (WaylandSeat *)data;
    1369           0 :                 for (auto &it : seat->pointerViews) {
    1370           0 :                         it->handlePointerAxis(time, axis, value);
    1371             :                 }
    1372           0 :         },
    1373             : 
    1374             :         // frame
    1375           0 :         [] (void *data, wl_pointer *wl_pointer) {
    1376           0 :                 auto seat = (WaylandSeat *)data;
    1377           0 :                 for (auto &it : seat->pointerViews) {
    1378           0 :                         it->handlePointerFrame();
    1379             :                 }
    1380           0 :         },
    1381             : 
    1382             :         // axis_source
    1383           0 :         [] (void *data, wl_pointer *wl_pointer, uint32_t axis_source) {
    1384           0 :                 auto seat = (WaylandSeat *)data;
    1385           0 :                 for (auto &it : seat->pointerViews) {
    1386           0 :                         it->handlePointerAxisSource(axis_source);
    1387             :                 }
    1388           0 :         },
    1389             : 
    1390             :         // axis_stop
    1391           0 :         [] (void *data, wl_pointer *wl_pointer, uint32_t time, uint32_t axis) {
    1392           0 :                 auto seat = (WaylandSeat *)data;
    1393           0 :                 for (auto &it : seat->pointerViews) {
    1394           0 :                         it->handlePointerAxisStop(time, axis);
    1395             :                 }
    1396           0 :         },
    1397             : 
    1398             :         // axis_discrete
    1399           0 :         [] (void *data, wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) {
    1400           0 :                 auto seat = (WaylandSeat *)data;
    1401           0 :                 for (auto &it : seat->pointerViews) {
    1402           0 :                         it->handlePointerAxisDiscrete(axis, discrete);
    1403             :                 }
    1404           0 :         }
    1405             : };
    1406             : 
    1407             : static struct wl_keyboard_listener s_WaylandKeyboardListener{
    1408             :         // keymap
    1409           0 :         [] (void *data, wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size) {
    1410           0 :                 auto seat = (WaylandSeat *)data;
    1411           0 :                 if (seat->root->xkb) {
    1412           0 :                         auto map_shm = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
    1413           0 :                         if (map_shm != MAP_FAILED) {
    1414           0 :                                 if (seat->state) {
    1415           0 :                                         seat->root->xkb->xkb_state_unref(seat->state);
    1416           0 :                                         seat->state = nullptr;
    1417             :                                 }
    1418             : 
    1419           0 :                                 if (seat->compose) {
    1420           0 :                                         seat->root->xkb->xkb_compose_state_unref(seat->compose);
    1421           0 :                                         seat->compose = nullptr;
    1422             :                                 }
    1423             : 
    1424           0 :                                 auto keymap = seat->root->xkb->xkb_keymap_new_from_string(seat->root->xkb->getContext(),
    1425             :                                                 (const char *)map_shm, xkb_keymap_format(format), XKB_KEYMAP_COMPILE_NO_FLAGS);
    1426           0 :                                 if (keymap) {
    1427           0 :                                         seat->state = seat->root->xkb->xkb_state_new(keymap);
    1428           0 :                                         seat->keyState.controlIndex = seat->root->xkb->xkb_keymap_mod_get_index(keymap, "Control");
    1429           0 :                                         seat->keyState.altIndex = seat->root->xkb->xkb_keymap_mod_get_index(keymap, "Mod1");
    1430           0 :                                         seat->keyState.shiftIndex = seat->root->xkb->xkb_keymap_mod_get_index(keymap, "Shift");
    1431           0 :                                         seat->keyState.superIndex = seat->root->xkb->xkb_keymap_mod_get_index(keymap, "Mod4");
    1432           0 :                                         seat->keyState.capsLockIndex = seat->root->xkb->xkb_keymap_mod_get_index(keymap, "Lock");
    1433           0 :                                         seat->keyState.numLockIndex = seat->root->xkb->xkb_keymap_mod_get_index(keymap, "Mod2");
    1434           0 :                                         seat->root->xkb->xkb_keymap_unref(keymap);
    1435             :                                 }
    1436             : 
    1437           0 :                                 auto locale = getenv("LC_ALL");
    1438           0 :                                 if (!locale) { locale = getenv("LC_CTYPE"); }
    1439           0 :                                 if (!locale) { locale = getenv("LANG"); }
    1440             : 
    1441           0 :                                 auto composeTable = seat->root->xkb->xkb_compose_table_new_from_locale(seat->root->xkb->getContext(),
    1442             :                                                 locale ? locale : "C", XKB_COMPOSE_COMPILE_NO_FLAGS);
    1443           0 :                                 if (composeTable) {
    1444           0 :                                         seat->compose = seat->root->xkb->xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS);
    1445           0 :                                         seat->root->xkb->xkb_compose_table_unref(composeTable);
    1446             :                                 }
    1447             : 
    1448           0 :                                 munmap(map_shm, size);
    1449             :                         }
    1450             :                 }
    1451           0 :                 close(fd);
    1452           0 :         },
    1453             : 
    1454             :         // enter
    1455           0 :         [] (void *data, wl_keyboard *wl_keyboard, uint32_t serial, wl_surface *surface, struct wl_array *keys) {
    1456           0 :                 auto seat = (WaylandSeat *)data;
    1457           0 :                 if (seat->root->ownsSurface(surface)) {
    1458           0 :                         if (auto view = (WaylandViewInterface *)seat->wayland->wl_surface_get_user_data(surface)) {
    1459           0 :                                 Vector<uint32_t> keysVec;
    1460           0 :                                 for (uint32_t *it = (uint32_t *)keys->data; (const char *)it < ((const char *) keys->data + keys->size); ++ it) {
    1461           0 :                                         keysVec.emplace_back(*it);
    1462             :                                 }
    1463             : 
    1464           0 :                                 seat->keyboardViews.emplace(view);
    1465           0 :                                 view->handleKeyboardEnter(move(keysVec), seat->keyState.modsDepressed, seat->keyState.modsLatched, seat->keyState.modsLocked);
    1466           0 :                         }
    1467             :                 }
    1468           0 :         },
    1469             : 
    1470             :         // leave
    1471           0 :         [] (void *data, wl_keyboard *wl_keyboard, uint32_t serial, wl_surface *surface) {
    1472           0 :                 auto seat = (WaylandSeat *)data;
    1473           0 :                 if (seat->root->ownsSurface(surface)) {
    1474           0 :                         if (auto view = (WaylandViewInterface *)seat->wayland->wl_surface_get_user_data(surface)) {
    1475           0 :                                 view->handleKeyboardLeave();
    1476           0 :                                 seat->keyboardViews.erase(view);
    1477             :                         }
    1478             :                 }
    1479           0 :         },
    1480             : 
    1481             :         // key
    1482           0 :         [] (void *data, wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) {
    1483           0 :                 auto seat = (WaylandSeat *)data;
    1484           0 :                 for (auto &it : seat->keyboardViews) {
    1485           0 :                         it->handleKey(time, key, state);
    1486             :                 }
    1487           0 :         },
    1488             : 
    1489             :         // modifiers
    1490           0 :         [] (void *data, wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed,
    1491             :                         uint32_t mods_latched, uint32_t mods_locked, uint32_t group) {
    1492           0 :                 auto seat = (WaylandSeat *)data;
    1493           0 :                 if (seat->state) {
    1494           0 :                         seat->root->xkb->xkb_state_update_mask(seat->state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
    1495           0 :                         seat->keyState.modsDepressed = mods_depressed;
    1496           0 :                         seat->keyState.modsLatched = mods_latched;
    1497           0 :                         seat->keyState.modsLocked = mods_locked;
    1498           0 :                         for (auto &it : seat->keyboardViews) {
    1499           0 :                                 it->handleKeyModifiers(mods_depressed, mods_latched, mods_locked);
    1500             :                         }
    1501             :                 }
    1502           0 :         },
    1503             : 
    1504             :         // repeat_info
    1505           0 :         [] (void *data, wl_keyboard *wl_keyboard, int32_t rate, int32_t delay) {
    1506           0 :                 auto seat = (WaylandSeat *)data;
    1507           0 :                 seat->keyState.keyRepeatRate = rate;
    1508           0 :                 seat->keyState.keyRepeatDelay = delay;
    1509           0 :                 seat->keyState.keyRepeatInterval = 1'000'000 / rate;
    1510           0 :         }
    1511             : };
    1512             : 
    1513             : static struct wl_touch_listener s_WaylandTouchListener{
    1514             :         // down
    1515           0 :         [](void *data, wl_touch *touch, uint32_t serial, uint32_t time, wl_surface *surface, int32_t id, wl_fixed_t x, wl_fixed_t y) {
    1516             : 
    1517           0 :         },
    1518             : 
    1519             :         // up
    1520           0 :         [](void *data, wl_touch *touch, uint32_t serial, uint32_t time, int32_t id) {
    1521             : 
    1522           0 :         },
    1523             : 
    1524             :         // motion
    1525           0 :         [](void *data, wl_touch *touch, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) {
    1526             : 
    1527           0 :         },
    1528             : 
    1529             :         // frame
    1530           0 :         [](void *data, wl_touch *touch) {
    1531             : 
    1532           0 :         },
    1533             : 
    1534             :         // cancel
    1535           0 :         [](void *data, wl_touch *touch) {
    1536             : 
    1537           0 :         },
    1538             : 
    1539             :         // shape
    1540           0 :         [](void *data, wl_touch *touch, int32_t id, wl_fixed_t major, wl_fixed_t minor) {
    1541             : 
    1542           0 :         },
    1543             : 
    1544             :         // orientation
    1545           0 :         [](void *data, wl_touch *touch, int32_t id, wl_fixed_t orientation) {
    1546             : 
    1547           0 :         }
    1548             : };
    1549             : 
    1550             : static struct wl_seat_listener s_WaylandSeatListener{
    1551           0 :         [] (void *data, struct wl_seat *wl_seat, uint32_t capabilities) {
    1552           0 :                 auto seat = (WaylandSeat *)data;
    1553           0 :                 seat->capabilities = capabilities;
    1554           0 :                 seat->root->seatDirty = true;
    1555             : 
    1556           0 :                 if ((capabilities & WL_SEAT_CAPABILITY_POINTER) != 0) {
    1557           0 :                         seat->initCursors();
    1558             :                 }
    1559             : 
    1560           0 :                 seat->update();
    1561           0 :         },
    1562           0 :         [] (void *data, struct wl_seat *wl_seat, const char *name) {
    1563           0 :                 auto seat = (WaylandSeat*) data;
    1564           0 :                 seat->name = name;
    1565           0 :         }
    1566             : };
    1567             : 
    1568           0 : WaylandSeat::~WaylandSeat() {
    1569           0 :         if (state) {
    1570           0 :                 root->xkb->xkb_state_unref(state);
    1571           0 :                 state = nullptr;
    1572             :         }
    1573           0 :         if (compose) {
    1574           0 :                 root->xkb->xkb_compose_state_unref(compose);
    1575           0 :                 compose = nullptr;
    1576             :         }
    1577           0 :         if (seat) {
    1578           0 :                 wayland->wl_seat_destroy(seat);
    1579           0 :                 seat = nullptr;
    1580             :         }
    1581           0 : }
    1582             : 
    1583           0 : bool WaylandSeat::init(const Rc<WaylandLibrary> &lib, WaylandDisplay *view, wl_registry *registry, uint32_t name, uint32_t version) {
    1584           0 :         wayland = lib;
    1585           0 :         root = view;
    1586           0 :         id = name;
    1587           0 :         if (version >= 5U) {
    1588           0 :                 hasPointerFrames = true;
    1589             :         }
    1590           0 :         seat = static_cast<wl_seat *>(wayland->wl_registry_bind(registry, name,
    1591           0 :                         wayland->wl_seat_interface, std::min(version, 5U)));
    1592           0 :         wayland->wl_seat_set_user_data(seat, this);
    1593           0 :         wayland->wl_seat_add_listener(seat, &s_WaylandSeatListener, this);
    1594           0 :         wayland->wl_proxy_set_tag((struct wl_proxy *) seat, &s_XenolithWaylandTag);
    1595             : 
    1596           0 :         keyState.keycodes[KEY_GRAVE] = core::InputKeyCode::GRAVE_ACCENT;
    1597           0 :         keyState.keycodes[KEY_1] = core::InputKeyCode::_1;
    1598           0 :         keyState.keycodes[KEY_2] = core::InputKeyCode::_2;
    1599           0 :         keyState.keycodes[KEY_3] = core::InputKeyCode::_3;
    1600           0 :         keyState.keycodes[KEY_4] = core::InputKeyCode::_4;
    1601           0 :         keyState.keycodes[KEY_5] = core::InputKeyCode::_5;
    1602           0 :         keyState.keycodes[KEY_6] = core::InputKeyCode::_6;
    1603           0 :         keyState.keycodes[KEY_7] = core::InputKeyCode::_7;
    1604           0 :         keyState.keycodes[KEY_8] = core::InputKeyCode::_8;
    1605           0 :         keyState.keycodes[KEY_9] = core::InputKeyCode::_9;
    1606           0 :         keyState.keycodes[KEY_0] = core::InputKeyCode::_0;
    1607           0 :         keyState.keycodes[KEY_SPACE] = core::InputKeyCode::SPACE;
    1608           0 :         keyState.keycodes[KEY_MINUS] = core::InputKeyCode::MINUS;
    1609           0 :         keyState.keycodes[KEY_EQUAL] = core::InputKeyCode::EQUAL;
    1610           0 :         keyState.keycodes[KEY_Q] = core::InputKeyCode::Q;
    1611           0 :         keyState.keycodes[KEY_W] = core::InputKeyCode::W;
    1612           0 :         keyState.keycodes[KEY_E] = core::InputKeyCode::E;
    1613           0 :         keyState.keycodes[KEY_R] = core::InputKeyCode::R;
    1614           0 :         keyState.keycodes[KEY_T] = core::InputKeyCode::T;
    1615           0 :         keyState.keycodes[KEY_Y] = core::InputKeyCode::Y;
    1616           0 :         keyState.keycodes[KEY_U] = core::InputKeyCode::U;
    1617           0 :         keyState.keycodes[KEY_I] = core::InputKeyCode::I;
    1618           0 :         keyState.keycodes[KEY_O] = core::InputKeyCode::O;
    1619           0 :         keyState.keycodes[KEY_P] = core::InputKeyCode::P;
    1620           0 :         keyState.keycodes[KEY_LEFTBRACE] = core::InputKeyCode::LEFT_BRACKET;
    1621           0 :         keyState.keycodes[KEY_RIGHTBRACE] = core::InputKeyCode::RIGHT_BRACKET;
    1622           0 :         keyState.keycodes[KEY_A] = core::InputKeyCode::A;
    1623           0 :         keyState.keycodes[KEY_S] = core::InputKeyCode::S;
    1624           0 :         keyState.keycodes[KEY_D] = core::InputKeyCode::D;
    1625           0 :         keyState.keycodes[KEY_F] = core::InputKeyCode::F;
    1626           0 :         keyState.keycodes[KEY_G] = core::InputKeyCode::G;
    1627           0 :         keyState.keycodes[KEY_H] = core::InputKeyCode::H;
    1628           0 :         keyState.keycodes[KEY_J] = core::InputKeyCode::J;
    1629           0 :         keyState.keycodes[KEY_K] = core::InputKeyCode::K;
    1630           0 :         keyState.keycodes[KEY_L] = core::InputKeyCode::L;
    1631           0 :         keyState.keycodes[KEY_SEMICOLON] = core::InputKeyCode::SEMICOLON;
    1632           0 :         keyState.keycodes[KEY_APOSTROPHE] = core::InputKeyCode::APOSTROPHE;
    1633           0 :         keyState.keycodes[KEY_Z] = core::InputKeyCode::Z;
    1634           0 :         keyState.keycodes[KEY_X] = core::InputKeyCode::X;
    1635           0 :         keyState.keycodes[KEY_C] = core::InputKeyCode::C;
    1636           0 :         keyState.keycodes[KEY_V] = core::InputKeyCode::V;
    1637           0 :         keyState.keycodes[KEY_B] = core::InputKeyCode::B;
    1638           0 :         keyState.keycodes[KEY_N] = core::InputKeyCode::N;
    1639           0 :         keyState.keycodes[KEY_M] = core::InputKeyCode::M;
    1640           0 :         keyState.keycodes[KEY_COMMA] = core::InputKeyCode::COMMA;
    1641           0 :         keyState.keycodes[KEY_DOT] = core::InputKeyCode::PERIOD;
    1642           0 :         keyState.keycodes[KEY_SLASH] = core::InputKeyCode::SLASH;
    1643           0 :         keyState.keycodes[KEY_BACKSLASH] = core::InputKeyCode::BACKSLASH;
    1644           0 :         keyState.keycodes[KEY_ESC] = core::InputKeyCode::ESCAPE;
    1645           0 :         keyState.keycodes[KEY_TAB] = core::InputKeyCode::TAB;
    1646           0 :         keyState.keycodes[KEY_LEFTSHIFT] = core::InputKeyCode::LEFT_SHIFT;
    1647           0 :         keyState.keycodes[KEY_RIGHTSHIFT] = core::InputKeyCode::RIGHT_SHIFT;
    1648           0 :         keyState.keycodes[KEY_LEFTCTRL] = core::InputKeyCode::LEFT_CONTROL;
    1649           0 :         keyState.keycodes[KEY_RIGHTCTRL] = core::InputKeyCode::RIGHT_CONTROL;
    1650           0 :         keyState.keycodes[KEY_LEFTALT] = core::InputKeyCode::LEFT_ALT;
    1651           0 :         keyState.keycodes[KEY_RIGHTALT] = core::InputKeyCode::RIGHT_ALT;
    1652           0 :         keyState.keycodes[KEY_LEFTMETA] = core::InputKeyCode::LEFT_SUPER;
    1653           0 :         keyState.keycodes[KEY_RIGHTMETA] = core::InputKeyCode::RIGHT_SUPER;
    1654           0 :         keyState.keycodes[KEY_COMPOSE] = core::InputKeyCode::MENU;
    1655           0 :         keyState.keycodes[KEY_NUMLOCK] = core::InputKeyCode::NUM_LOCK;
    1656           0 :         keyState.keycodes[KEY_CAPSLOCK] = core::InputKeyCode::CAPS_LOCK;
    1657           0 :         keyState.keycodes[KEY_PRINT] = core::InputKeyCode::PRINT_SCREEN;
    1658           0 :         keyState.keycodes[KEY_SCROLLLOCK] = core::InputKeyCode::SCROLL_LOCK;
    1659           0 :         keyState.keycodes[KEY_PAUSE] = core::InputKeyCode::PAUSE;
    1660           0 :         keyState.keycodes[KEY_DELETE] = core::InputKeyCode::DELETE;
    1661           0 :         keyState.keycodes[KEY_BACKSPACE] = core::InputKeyCode::BACKSPACE;
    1662           0 :         keyState.keycodes[KEY_ENTER] = core::InputKeyCode::ENTER;
    1663           0 :         keyState.keycodes[KEY_HOME] = core::InputKeyCode::HOME;
    1664           0 :         keyState.keycodes[KEY_END] = core::InputKeyCode::END;
    1665           0 :         keyState.keycodes[KEY_PAGEUP] = core::InputKeyCode::PAGE_UP;
    1666           0 :         keyState.keycodes[KEY_PAGEDOWN] = core::InputKeyCode::PAGE_DOWN;
    1667           0 :         keyState.keycodes[KEY_INSERT] = core::InputKeyCode::INSERT;
    1668           0 :         keyState.keycodes[KEY_LEFT] = core::InputKeyCode::LEFT;
    1669           0 :         keyState.keycodes[KEY_RIGHT] = core::InputKeyCode::RIGHT;
    1670           0 :         keyState.keycodes[KEY_DOWN] = core::InputKeyCode::DOWN;
    1671           0 :         keyState.keycodes[KEY_UP] = core::InputKeyCode::UP;
    1672           0 :         keyState.keycodes[KEY_F1] = core::InputKeyCode::F1;
    1673           0 :         keyState.keycodes[KEY_F2] = core::InputKeyCode::F2;
    1674           0 :         keyState.keycodes[KEY_F3] = core::InputKeyCode::F3;
    1675           0 :         keyState.keycodes[KEY_F4] = core::InputKeyCode::F4;
    1676           0 :         keyState.keycodes[KEY_F5] = core::InputKeyCode::F5;
    1677           0 :         keyState.keycodes[KEY_F6] = core::InputKeyCode::F6;
    1678           0 :         keyState.keycodes[KEY_F7] = core::InputKeyCode::F7;
    1679           0 :         keyState.keycodes[KEY_F8] = core::InputKeyCode::F8;
    1680           0 :         keyState.keycodes[KEY_F9] = core::InputKeyCode::F9;
    1681           0 :         keyState.keycodes[KEY_F10] = core::InputKeyCode::F10;
    1682           0 :         keyState.keycodes[KEY_F11] = core::InputKeyCode::F11;
    1683           0 :         keyState.keycodes[KEY_F12] = core::InputKeyCode::F12;
    1684           0 :         keyState.keycodes[KEY_F13] = core::InputKeyCode::F13;
    1685           0 :         keyState.keycodes[KEY_F14] = core::InputKeyCode::F14;
    1686           0 :         keyState.keycodes[KEY_F15] = core::InputKeyCode::F15;
    1687           0 :         keyState.keycodes[KEY_F16] = core::InputKeyCode::F16;
    1688           0 :         keyState.keycodes[KEY_F17] = core::InputKeyCode::F17;
    1689           0 :         keyState.keycodes[KEY_F18] = core::InputKeyCode::F18;
    1690           0 :         keyState.keycodes[KEY_F19] = core::InputKeyCode::F19;
    1691           0 :         keyState.keycodes[KEY_F20] = core::InputKeyCode::F20;
    1692           0 :         keyState.keycodes[KEY_F21] = core::InputKeyCode::F21;
    1693           0 :         keyState.keycodes[KEY_F22] = core::InputKeyCode::F22;
    1694           0 :         keyState.keycodes[KEY_F23] = core::InputKeyCode::F23;
    1695           0 :         keyState.keycodes[KEY_F24] = core::InputKeyCode::F24;
    1696           0 :         keyState.keycodes[KEY_KPSLASH] = core::InputKeyCode::KP_DIVIDE;
    1697           0 :         keyState.keycodes[KEY_KPASTERISK] = core::InputKeyCode::KP_MULTIPLY;
    1698           0 :         keyState.keycodes[KEY_KPMINUS] = core::InputKeyCode::KP_SUBTRACT;
    1699           0 :         keyState.keycodes[KEY_KPPLUS] = core::InputKeyCode::KP_ADD;
    1700           0 :         keyState.keycodes[KEY_KP0] = core::InputKeyCode::KP_0;
    1701           0 :         keyState.keycodes[KEY_KP1] = core::InputKeyCode::KP_1;
    1702           0 :         keyState.keycodes[KEY_KP2] = core::InputKeyCode::KP_2;
    1703           0 :         keyState.keycodes[KEY_KP3] = core::InputKeyCode::KP_3;
    1704           0 :         keyState.keycodes[KEY_KP4] = core::InputKeyCode::KP_4;
    1705           0 :         keyState.keycodes[KEY_KP5] = core::InputKeyCode::KP_5;
    1706           0 :         keyState.keycodes[KEY_KP6] = core::InputKeyCode::KP_6;
    1707           0 :         keyState.keycodes[KEY_KP7] = core::InputKeyCode::KP_7;
    1708           0 :         keyState.keycodes[KEY_KP8] = core::InputKeyCode::KP_8;
    1709           0 :         keyState.keycodes[KEY_KP9] = core::InputKeyCode::KP_9;
    1710           0 :         keyState.keycodes[KEY_KPDOT] = core::InputKeyCode::KP_DECIMAL;
    1711           0 :         keyState.keycodes[KEY_KPEQUAL] = core::InputKeyCode::KP_EQUAL;
    1712           0 :         keyState.keycodes[KEY_KPENTER] = core::InputKeyCode::KP_ENTER;
    1713           0 :         keyState.keycodes[KEY_102ND] = core::InputKeyCode::WORLD_2;
    1714             : 
    1715           0 :         return true;
    1716             : }
    1717             : 
    1718             : static struct wl_surface_listener cursor_surface_listener = {
    1719           0 :         [] (void *data, wl_surface *surface, wl_output *output) {
    1720           0 :                 auto seat = (WaylandSeat *)data;
    1721           0 :                 if (!WaylandLibrary::ownsProxy(output)) {
    1722           0 :                         return;
    1723             :                 }
    1724             : 
    1725           0 :                 auto out = (WaylandOutput *)seat->wayland->wl_output_get_user_data(output);
    1726           0 :                 seat->pointerOutputs.emplace(out);
    1727           0 :                 seat->tryUpdateCursor();
    1728             :         },
    1729           0 :         [] (void *data, struct wl_surface *wl_surface, struct wl_output *output) {
    1730           0 :                 auto seat = (WaylandSeat *)data;
    1731           0 :                 if (!WaylandLibrary::ownsProxy(output)) {
    1732           0 :                         return;
    1733             :                 }
    1734             : 
    1735           0 :                 auto out = (WaylandOutput *)seat->wayland->wl_output_get_user_data(output);
    1736           0 :                 seat->pointerOutputs.erase(out);
    1737             :         }
    1738             : };
    1739             : 
    1740           0 : void WaylandSeat::initCursors() {
    1741           0 :         auto lib = DBusLibrary::get();
    1742           0 :         auto theme = lib.getCurrentInterfaceTheme();
    1743             : 
    1744           0 :         theme.cursorSize *= pointerScale;
    1745             : 
    1746           0 :         if (!cursorTheme || cursorTheme->cursorSize != theme.cursorSize || cursorTheme->cursorName != String(theme.cursorTheme)) {
    1747           0 :                 cursorTheme = Rc<WaylandCursorTheme>::create(root, theme.cursorTheme, theme.cursorSize);
    1748             :         }
    1749             : 
    1750           0 :         if (!cursorSurface) {
    1751           0 :                 cursorSurface = wayland->wl_compositor_create_surface(root->compositor);
    1752           0 :                 wayland->wl_surface_add_listener(cursorSurface, &cursor_surface_listener, this);
    1753             :         }
    1754           0 : }
    1755             : 
    1756           0 : void WaylandSeat::tryUpdateCursor() {
    1757           0 :         int32_t scale = 1;
    1758             : 
    1759           0 :         for (auto &it : pointerOutputs) {
    1760           0 :                 scale = std::max(scale, it->scale);
    1761             :         }
    1762             : 
    1763           0 :         if (scale != pointerScale) {
    1764           0 :                 pointerScale = scale;
    1765           0 :                 initCursors();
    1766           0 :                 if (cursorTheme) {
    1767           0 :                         cursorTheme->setCursor(this);
    1768             :                 }
    1769             :         }
    1770           0 : }
    1771             : 
    1772           0 : void WaylandSeat::update() {
    1773           0 :         if (!root->seatDirty) {
    1774           0 :                 return;
    1775             :         }
    1776             : 
    1777           0 :         root->seatDirty = false;
    1778             : 
    1779           0 :         if ((capabilities & WL_SEAT_CAPABILITY_POINTER) != 0 && !pointer) {
    1780           0 :                 pointer = wayland->wl_seat_get_pointer(seat);
    1781           0 :                 wayland->wl_pointer_add_listener(pointer, &s_WaylandPointerListener, this);
    1782           0 :                 pointerScale = 1;
    1783           0 :                 initCursors();
    1784           0 :         } else if ((capabilities & WL_SEAT_CAPABILITY_POINTER) == 0 && pointer) {
    1785           0 :                 wayland->wl_pointer_release(pointer);
    1786           0 :                 pointer = NULL;
    1787             :         }
    1788             : 
    1789           0 :         if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) != 0 && !keyboard) {
    1790           0 :                 keyboard = wayland->wl_seat_get_keyboard(seat);
    1791           0 :                 wayland->wl_keyboard_add_listener(keyboard, &s_WaylandKeyboardListener, this);
    1792           0 :         } else if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) == 0 && keyboard) {
    1793           0 :                 wayland->wl_keyboard_release(keyboard);
    1794           0 :                 keyboard = NULL;
    1795             :         }
    1796             : 
    1797           0 :         if ((capabilities & WL_SEAT_CAPABILITY_TOUCH) != 0 && !touch) {
    1798           0 :                 touch = wayland->wl_seat_get_touch(seat);
    1799           0 :                 wayland->wl_touch_add_listener(touch, &s_WaylandTouchListener, this);
    1800           0 :         } else if ((capabilities & WL_SEAT_CAPABILITY_TOUCH) == 0 && touch) {
    1801           0 :                 wayland->wl_touch_release(touch);
    1802           0 :                 touch = NULL;
    1803             :         }
    1804             : 
    1805             :         // wayland->wl_display_roundtrip(root->display);
    1806             : }
    1807             : 
    1808           0 : core::InputKeyCode WaylandSeat::translateKey(uint32_t scancode) const {
    1809           0 :         if (scancode < sizeof(keyState.keycodes) / sizeof(keyState.keycodes[0])) {
    1810           0 :                 return keyState.keycodes[scancode];
    1811             :         }
    1812             : 
    1813           0 :         return core::InputKeyCode::Unknown;
    1814             : }
    1815             : 
    1816           0 : xkb_keysym_t WaylandSeat::composeSymbol(xkb_keysym_t sym, core::InputKeyComposeState &composeState) const {
    1817           0 :         if (sym == XKB_KEY_NoSymbol || !compose) {
    1818           0 :                 return sym;
    1819             :         }
    1820           0 :         if (root->xkb->xkb_compose_state_feed(compose, sym) != XKB_COMPOSE_FEED_ACCEPTED) {
    1821           0 :                 return sym;
    1822             :         }
    1823           0 :         switch (root->xkb->xkb_compose_state_get_status(compose)) {
    1824           0 :         case XKB_COMPOSE_COMPOSED:
    1825           0 :                 composeState = core::InputKeyComposeState::Composed;
    1826           0 :                 return root->xkb->xkb_compose_state_get_one_sym(compose);
    1827           0 :         case XKB_COMPOSE_COMPOSING:
    1828           0 :                 composeState = core::InputKeyComposeState::Composing;
    1829           0 :                 return sym;
    1830           0 :         case XKB_COMPOSE_CANCELLED:
    1831           0 :                 return sym;
    1832           0 :         case XKB_COMPOSE_NOTHING:
    1833             :         default:
    1834           0 :                 return sym;
    1835             :         }
    1836             : }
    1837             : 
    1838           0 : WaylandDecoration::~WaylandDecoration() {
    1839           0 :         if (viewport) {
    1840           0 :                 wayland->wp_viewport_destroy(viewport);
    1841           0 :                 viewport = nullptr;
    1842             :         }
    1843           0 :         if (subsurface) {
    1844           0 :                 wayland->wl_subsurface_destroy(subsurface);
    1845           0 :                 subsurface = nullptr;
    1846             :         }
    1847           0 :         if (surface) {
    1848           0 :                 display->destroyDecorationSurface(surface);
    1849           0 :                 surface = nullptr;
    1850             :         }
    1851           0 : }
    1852             : 
    1853           0 : bool WaylandDecoration::init(WaylandViewInterface *view, Rc<WaylandBuffer> &&b, Rc<WaylandBuffer> &&a, WaylandDecorationName n) {
    1854           0 :         root = view;
    1855           0 :         display = view->getDisplay();
    1856           0 :         wayland = display->wayland;
    1857           0 :         surface = display->createDecorationSurface(this);
    1858           0 :         name = n;
    1859           0 :         switch (n) {
    1860           0 :         case WaylandDecorationName::RightSide: image = WaylandCursorImage::RightSide; break;
    1861           0 :         case WaylandDecorationName::TopRigntCorner: image = WaylandCursorImage::TopRigntCorner; break;
    1862           0 :         case WaylandDecorationName::TopSide: image = WaylandCursorImage::TopSide; break;
    1863           0 :         case WaylandDecorationName::TopLeftCorner: image = WaylandCursorImage::TopLeftCorner; break;
    1864           0 :         case WaylandDecorationName::BottomRightCorner: image = WaylandCursorImage::BottomRightCorner; break;
    1865           0 :         case WaylandDecorationName::BottomSide: image = WaylandCursorImage::BottomSide; break;
    1866           0 :         case WaylandDecorationName::BottomLeftCorner: image = WaylandCursorImage::BottomLeftCorner; break;
    1867           0 :         case WaylandDecorationName::LeftSide: image = WaylandCursorImage::LeftSide; break;
    1868           0 :         default:
    1869           0 :                 image = WaylandCursorImage::LeftPtr;
    1870           0 :                 break;
    1871             :         }
    1872           0 :         buffer = move(b);
    1873           0 :         if (a) {
    1874           0 :                 active = move(a);
    1875             :         }
    1876             : 
    1877           0 :         auto parent = root->getSurface();
    1878             : 
    1879           0 :         subsurface = wayland->wl_subcompositor_get_subsurface(display->subcompositor, surface, parent);
    1880           0 :         wayland->wl_subsurface_place_below(subsurface, parent);
    1881           0 :         wayland->wl_subsurface_set_sync(subsurface);
    1882             : 
    1883           0 :         viewport = wayland->wp_viewporter_get_viewport(display->viewporter, surface);
    1884           0 :         wayland->wl_surface_attach(surface, buffer->buffer, 0, 0);
    1885             : 
    1886           0 :         dirty = true;
    1887             : 
    1888           0 :         return true;
    1889             : }
    1890             : 
    1891           0 : bool WaylandDecoration::init(WaylandViewInterface *view, Rc<WaylandBuffer> &&b, WaylandDecorationName n) {
    1892           0 :         return init(view, move(b), nullptr, n);
    1893             : }
    1894             : 
    1895           0 : void WaylandDecoration::setAltBuffers(Rc<WaylandBuffer> &&b, Rc<WaylandBuffer> &&a) {
    1896           0 :         altBuffer = move(b);
    1897           0 :         altActive = move(a);
    1898           0 : }
    1899             : 
    1900           0 : void WaylandDecoration::handlePress(uint32_t s, uint32_t button, uint32_t state) {
    1901           0 :         serial = s;
    1902           0 :         waitForMove = false;
    1903           0 :         if (isTouchable()) {
    1904           0 :                 if (state == WL_POINTER_BUTTON_STATE_RELEASED && button == BTN_LEFT) {
    1905           0 :                         root->handleDecorationPress(this, serial);
    1906             :                 }
    1907           0 :         } else if (image == WaylandCursorImage::LeftPtr) {
    1908           0 :                 if (state == WL_POINTER_BUTTON_STATE_RELEASED && button == BTN_LEFT) {
    1909           0 :                         auto n = Time::now().toMicros();
    1910           0 :                         if (n - lastTouch < 500'000) {
    1911           0 :                                 root->handleDecorationPress(this, serial, true);
    1912             :                         }
    1913           0 :                         lastTouch = n;
    1914           0 :                 } else if (state == WL_POINTER_BUTTON_STATE_PRESSED && button == BTN_LEFT) {
    1915           0 :                         waitForMove = true;
    1916             :                         //root->handleDecorationPress(this, serial);
    1917             :                 }
    1918             :         } else {
    1919           0 :                 if (state == WL_POINTER_BUTTON_STATE_PRESSED && button == BTN_LEFT) {
    1920           0 :                         root->handleDecorationPress(this, serial);
    1921             :                 }
    1922             :         }
    1923           0 : }
    1924             : 
    1925           0 : void WaylandDecoration::handleMotion() {
    1926           0 :         if (waitForMove) {
    1927           0 :                 root->handleDecorationPress(this, serial);
    1928             :         }
    1929           0 : }
    1930             : 
    1931           0 : void WaylandDecoration::onEnter() {
    1932           0 :         if (isTouchable() && !isActive) {
    1933           0 :                 isActive = true;
    1934           0 :                 auto &b = (active && isActive) ? active : buffer;
    1935           0 :                 wayland->wl_surface_attach(surface, b->buffer, 0, 0);
    1936           0 :                 wayland->wl_surface_damage_buffer(surface, 0, 0, b->width, b->height);
    1937           0 :                 dirty = true;
    1938             :         }
    1939           0 : }
    1940             : 
    1941           0 : void WaylandDecoration::onLeave() {
    1942           0 :         if (isTouchable() && isActive) {
    1943           0 :                 isActive = false;
    1944           0 :                 auto &b = (active && isActive) ? active : buffer;
    1945           0 :                 wayland->wl_surface_attach(surface, b->buffer, 0, 0);
    1946           0 :                 wayland->wl_surface_damage_buffer(surface, 0, 0, b->width, b->height);
    1947           0 :                 dirty = true;
    1948             :         }
    1949           0 : }
    1950             : 
    1951           0 : void WaylandDecoration::setActive(bool val) {
    1952           0 :         if (!isTouchable()) {
    1953           0 :                 if (val != isActive) {
    1954           0 :                         isActive = val;
    1955           0 :                         auto &b = (active && isActive) ? active : buffer;
    1956           0 :                         wayland->wl_surface_attach(surface, b->buffer, 0, 0);
    1957           0 :                         wayland->wl_surface_damage_buffer(surface, 0, 0, b->width, b->height);
    1958           0 :                         dirty = true;
    1959             :                 }
    1960             :         }
    1961           0 : }
    1962             : 
    1963           0 : void WaylandDecoration::setVisible(bool val) {
    1964           0 :         if (val != visible) {
    1965           0 :                 visible = val;
    1966           0 :                 if (visible) {
    1967           0 :                         auto &b = (active && isActive) ? active : buffer;
    1968           0 :                         wayland->wl_surface_attach(surface, b->buffer, 0, 0);
    1969           0 :                         wayland->wl_surface_damage_buffer(surface, 0, 0, b->width, b->height);
    1970             :                 } else {
    1971           0 :                         wayland->wl_surface_attach(surface, nullptr, 0, 0);
    1972             :                 }
    1973           0 :                 dirty = true;
    1974             :         }
    1975           0 : }
    1976             : 
    1977           0 : void WaylandDecoration::setAlternative(bool val) {
    1978           0 :         if (!altBuffer || !altActive) {
    1979           0 :                 return;
    1980             :         }
    1981             : 
    1982           0 :         if (alternative != val) {
    1983           0 :                 alternative = val;
    1984           0 :                 auto tmpA = move(altBuffer);
    1985           0 :                 auto tmpB = move(altActive);
    1986             : 
    1987           0 :                 altBuffer = move(buffer);
    1988           0 :                 altActive = move(active);
    1989             : 
    1990           0 :                 buffer = move(tmpA);
    1991           0 :                 active = move(tmpB);
    1992             : 
    1993           0 :                 auto &b = (active && isActive) ? active : buffer;
    1994           0 :                 wayland->wl_surface_attach(surface, b->buffer, 0, 0);
    1995           0 :                 wayland->wl_surface_damage_buffer(surface, 0, 0, b->width, b->height);
    1996           0 :                 dirty = true;
    1997           0 :         }
    1998             : }
    1999             : 
    2000           0 : void WaylandDecoration::setGeometry(int32_t x, int32_t y, int32_t width, int32_t height) {
    2001           0 :         if (_x == x && _y == y && _width == width && _height == height) {
    2002           0 :                 return;
    2003             :         }
    2004             : 
    2005           0 :         _x = x;
    2006           0 :         _y = y;
    2007           0 :         _width = width;
    2008           0 :         _height = height;
    2009             : 
    2010           0 :         wayland->wl_subsurface_set_position(subsurface, _x,_y);
    2011           0 :         wayland->wp_viewport_set_destination(viewport, _width, _height);
    2012             : 
    2013           0 :         auto &b = (active && isActive) ? active : buffer;
    2014           0 :         wayland->wl_surface_damage_buffer(surface, 0, 0, b->width, b->height);
    2015           0 :         dirty = true;
    2016             : }
    2017             : 
    2018           0 : bool WaylandDecoration::commit() {
    2019           0 :         if (dirty) {
    2020           0 :                 wayland->wl_surface_commit(surface);
    2021           0 :                 dirty = false;
    2022           0 :                 return true;
    2023             :         }
    2024           0 :         return false;
    2025             : }
    2026             : 
    2027           0 : bool WaylandDecoration::isTouchable() const {
    2028           0 :         switch (name) {
    2029           0 :         case WaylandDecorationName::IconClose:
    2030             :         case WaylandDecorationName::IconMaximize:
    2031             :         case WaylandDecorationName::IconMinimize:
    2032             :         case WaylandDecorationName::IconRestore:
    2033           0 :                 return true;
    2034             :                 break;
    2035           0 :         default:
    2036           0 :                 break;
    2037             :         }
    2038           0 :         return false;
    2039             : }
    2040             : 
    2041             : }

Generated by: LCOV version 1.14