volviewer

Volumetric Data Toy Viewer
git clone anongit@rnpnr.xyz:volviewer.git
Log | Files | Refs | Feed | LICENSE

wl_window.c (102558B)


      1 //========================================================================
      2 // GLFW 3.4 Wayland (modified for raylib) - www.glfw.org; www.raylib.com
      3 //------------------------------------------------------------------------
      4 // Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
      5 // Copyright (c) 2024 M374LX <wilsalx@gmail.com>
      6 //
      7 // This software is provided 'as-is', without any express or implied
      8 // warranty. In no event will the authors be held liable for any damages
      9 // arising from the use of this software.
     10 //
     11 // Permission is granted to anyone to use this software for any purpose,
     12 // including commercial applications, and to alter it and redistribute it
     13 // freely, subject to the following restrictions:
     14 //
     15 // 1. The origin of this software must not be misrepresented; you must not
     16 //    claim that you wrote the original software. If you use this software
     17 //    in a product, an acknowledgment in the product documentation would
     18 //    be appreciated but is not required.
     19 //
     20 // 2. Altered source versions must be plainly marked as such, and must not
     21 //    be misrepresented as being the original software.
     22 //
     23 // 3. This notice may not be removed or altered from any source
     24 //    distribution.
     25 //
     26 //========================================================================
     27 
     28 #define _GNU_SOURCE
     29 
     30 #include "internal.h"
     31 
     32 #if defined(_GLFW_WAYLAND)
     33 
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <errno.h>
     37 #include <assert.h>
     38 #include <unistd.h>
     39 #include <string.h>
     40 #include <fcntl.h>
     41 #include <sys/mman.h>
     42 #include <sys/timerfd.h>
     43 #include <poll.h>
     44 #include <linux/input-event-codes.h>
     45 
     46 #include "wayland-client-protocol.h"
     47 #include "xdg-shell-client-protocol.h"
     48 #include "xdg-decoration-unstable-v1-client-protocol.h"
     49 #include "viewporter-client-protocol.h"
     50 #include "relative-pointer-unstable-v1-client-protocol.h"
     51 #include "pointer-constraints-unstable-v1-client-protocol.h"
     52 #include "xdg-activation-v1-client-protocol.h"
     53 #include "idle-inhibit-unstable-v1-client-protocol.h"
     54 #include "fractional-scale-v1-client-protocol.h"
     55 
     56 #define GLFW_BORDER_SIZE    4
     57 #define GLFW_CAPTION_HEIGHT 24
     58 
     59 static int createTmpfileCloexec(char* tmpname)
     60 {
     61     int fd;
     62 
     63     fd = mkostemp(tmpname, O_CLOEXEC);
     64     if (fd >= 0)
     65         unlink(tmpname);
     66 
     67     return fd;
     68 }
     69 
     70 /*
     71  * Create a new, unique, anonymous file of the given size, and
     72  * return the file descriptor for it. The file descriptor is set
     73  * CLOEXEC. The file is immediately suitable for mmap()'ing
     74  * the given size at offset zero.
     75  *
     76  * The file should not have a permanent backing store like a disk,
     77  * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
     78  *
     79  * The file name is deleted from the file system.
     80  *
     81  * The file is suitable for buffer sharing between processes by
     82  * transmitting the file descriptor over Unix sockets using the
     83  * SCM_RIGHTS methods.
     84  *
     85  * posix_fallocate() is used to guarantee that disk space is available
     86  * for the file at the given size. If disk space is insufficient, errno
     87  * is set to ENOSPC. If posix_fallocate() is not supported, program may
     88  * receive SIGBUS on accessing mmap()'ed file contents instead.
     89  */
     90 static int createAnonymousFile(off_t size)
     91 {
     92     static const char template[] = "/glfw-shared-XXXXXX";
     93     const char* path;
     94     char* name;
     95     int fd;
     96     int ret;
     97 
     98 #ifdef HAVE_MEMFD_CREATE
     99     fd = memfd_create("glfw-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING);
    100     if (fd >= 0)
    101     {
    102         // We can add this seal before calling posix_fallocate(), as the file
    103         // is currently zero-sized anyway.
    104         //
    105         // There is also no need to check for the return value, we couldn’t do
    106         // anything with it anyway.
    107         fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
    108     }
    109     else
    110 #elif defined(SHM_ANON)
    111     fd = shm_open(SHM_ANON, O_RDWR | O_CLOEXEC, 0600);
    112     if (fd < 0)
    113 #endif
    114     {
    115         path = getenv("XDG_RUNTIME_DIR");
    116         if (!path)
    117         {
    118             errno = ENOENT;
    119             return -1;
    120         }
    121 
    122         name = _glfw_calloc(strlen(path) + sizeof(template), 1);
    123         strcpy(name, path);
    124         strcat(name, template);
    125 
    126         fd = createTmpfileCloexec(name);
    127         _glfw_free(name);
    128         if (fd < 0)
    129             return -1;
    130     }
    131 
    132 #if defined(SHM_ANON)
    133     // posix_fallocate does not work on SHM descriptors
    134     ret = ftruncate(fd, size);
    135 #else
    136     ret = posix_fallocate(fd, 0, size);
    137 #endif
    138     if (ret != 0)
    139     {
    140         close(fd);
    141         errno = ret;
    142         return -1;
    143     }
    144     return fd;
    145 }
    146 
    147 static struct wl_buffer* createShmBuffer(const GLFWimage* image)
    148 {
    149     const int stride = image->width * 4;
    150     const int length = image->width * image->height * 4;
    151 
    152     const int fd = createAnonymousFile(length);
    153     if (fd < 0)
    154     {
    155         _glfwInputError(GLFW_PLATFORM_ERROR,
    156                         "Wayland: Failed to create buffer file of size %d: %s",
    157                         length, strerror(errno));
    158         return NULL;
    159     }
    160 
    161     void* data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    162     if (data == MAP_FAILED)
    163     {
    164         _glfwInputError(GLFW_PLATFORM_ERROR,
    165                         "Wayland: Failed to map file: %s", strerror(errno));
    166         close(fd);
    167         return NULL;
    168     }
    169 
    170     struct wl_shm_pool* pool = wl_shm_create_pool(_glfw.wl.shm, fd, length);
    171 
    172     close(fd);
    173 
    174     unsigned char* source = (unsigned char*) image->pixels;
    175     unsigned char* target = data;
    176     for (int i = 0;  i < image->width * image->height;  i++, source += 4)
    177     {
    178         unsigned int alpha = source[3];
    179 
    180         *target++ = (unsigned char) ((source[2] * alpha) / 255);
    181         *target++ = (unsigned char) ((source[1] * alpha) / 255);
    182         *target++ = (unsigned char) ((source[0] * alpha) / 255);
    183         *target++ = (unsigned char) alpha;
    184     }
    185 
    186     struct wl_buffer* buffer =
    187         wl_shm_pool_create_buffer(pool, 0,
    188                                   image->width,
    189                                   image->height,
    190                                   stride, WL_SHM_FORMAT_ARGB8888);
    191     munmap(data, length);
    192     wl_shm_pool_destroy(pool);
    193 
    194     return buffer;
    195 }
    196 
    197 static void createFallbackEdge(_GLFWwindow* window,
    198                                _GLFWfallbackEdgeWayland* edge,
    199                                struct wl_surface* parent,
    200                                struct wl_buffer* buffer,
    201                                int x, int y,
    202                                int width, int height)
    203 {
    204     edge->surface = wl_compositor_create_surface(_glfw.wl.compositor);
    205     wl_surface_set_user_data(edge->surface, window);
    206     wl_proxy_set_tag((struct wl_proxy*) edge->surface, &_glfw.wl.tag);
    207     edge->subsurface = wl_subcompositor_get_subsurface(_glfw.wl.subcompositor,
    208                                                        edge->surface, parent);
    209     wl_subsurface_set_position(edge->subsurface, x, y);
    210     edge->viewport = wp_viewporter_get_viewport(_glfw.wl.viewporter,
    211                                                 edge->surface);
    212     wp_viewport_set_destination(edge->viewport, width, height);
    213     wl_surface_attach(edge->surface, buffer, 0, 0);
    214 
    215     struct wl_region* region = wl_compositor_create_region(_glfw.wl.compositor);
    216     wl_region_add(region, 0, 0, width, height);
    217     wl_surface_set_opaque_region(edge->surface, region);
    218     wl_surface_commit(edge->surface);
    219     wl_region_destroy(region);
    220 }
    221 
    222 static void createFallbackDecorations(_GLFWwindow* window)
    223 {
    224     unsigned char data[] = { 224, 224, 224, 255 };
    225     const GLFWimage image = { 1, 1, data };
    226 
    227     if (!_glfw.wl.viewporter)
    228         return;
    229 
    230     if (!window->wl.fallback.buffer)
    231         window->wl.fallback.buffer = createShmBuffer(&image);
    232     if (!window->wl.fallback.buffer)
    233         return;
    234 
    235     createFallbackEdge(window, &window->wl.fallback.top, window->wl.surface,
    236                        window->wl.fallback.buffer,
    237                        0, -GLFW_CAPTION_HEIGHT,
    238                        window->wl.width, GLFW_CAPTION_HEIGHT);
    239     createFallbackEdge(window, &window->wl.fallback.left, window->wl.surface,
    240                        window->wl.fallback.buffer,
    241                        -GLFW_BORDER_SIZE, -GLFW_CAPTION_HEIGHT,
    242                        GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT);
    243     createFallbackEdge(window, &window->wl.fallback.right, window->wl.surface,
    244                        window->wl.fallback.buffer,
    245                        window->wl.width, -GLFW_CAPTION_HEIGHT,
    246                        GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT);
    247     createFallbackEdge(window, &window->wl.fallback.bottom, window->wl.surface,
    248                        window->wl.fallback.buffer,
    249                        -GLFW_BORDER_SIZE, window->wl.height,
    250                        window->wl.width + GLFW_BORDER_SIZE * 2, GLFW_BORDER_SIZE);
    251 
    252     window->wl.fallback.decorations = GLFW_TRUE;
    253 }
    254 
    255 static void destroyFallbackEdge(_GLFWfallbackEdgeWayland* edge)
    256 {
    257     if (edge->subsurface)
    258         wl_subsurface_destroy(edge->subsurface);
    259     if (edge->surface)
    260         wl_surface_destroy(edge->surface);
    261     if (edge->viewport)
    262         wp_viewport_destroy(edge->viewport);
    263 
    264     edge->surface = NULL;
    265     edge->subsurface = NULL;
    266     edge->viewport = NULL;
    267 }
    268 
    269 static void destroyFallbackDecorations(_GLFWwindow* window)
    270 {
    271     window->wl.fallback.decorations = GLFW_FALSE;
    272 
    273     destroyFallbackEdge(&window->wl.fallback.top);
    274     destroyFallbackEdge(&window->wl.fallback.left);
    275     destroyFallbackEdge(&window->wl.fallback.right);
    276     destroyFallbackEdge(&window->wl.fallback.bottom);
    277 }
    278 
    279 static void xdgDecorationHandleConfigure(void* userData,
    280                                          struct zxdg_toplevel_decoration_v1* decoration,
    281                                          uint32_t mode)
    282 {
    283     _GLFWwindow* window = userData;
    284 
    285     window->wl.xdg.decorationMode = mode;
    286 
    287     if (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE)
    288     {
    289         if (window->decorated && !window->monitor)
    290             createFallbackDecorations(window);
    291     }
    292     else
    293         destroyFallbackDecorations(window);
    294 }
    295 
    296 static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener =
    297 {
    298     xdgDecorationHandleConfigure,
    299 };
    300 
    301 // Makes the surface considered as XRGB instead of ARGB.
    302 static void setContentAreaOpaque(_GLFWwindow* window)
    303 {
    304     struct wl_region* region;
    305 
    306     region = wl_compositor_create_region(_glfw.wl.compositor);
    307     if (!region)
    308         return;
    309 
    310     wl_region_add(region, 0, 0, window->wl.width, window->wl.height);
    311     wl_surface_set_opaque_region(window->wl.surface, region);
    312     wl_region_destroy(region);
    313 }
    314 
    315 static void resizeFramebuffer(_GLFWwindow* window)
    316 {
    317     if (window->wl.fractionalScale)
    318     {
    319         window->wl.fbWidth = (window->wl.width * window->wl.scalingNumerator) / 120;
    320         window->wl.fbHeight = (window->wl.height * window->wl.scalingNumerator) / 120;
    321     }
    322     else
    323     {
    324         window->wl.fbWidth = window->wl.width * window->wl.bufferScale;
    325         window->wl.fbHeight = window->wl.height * window->wl.bufferScale;
    326     }
    327 
    328     if (window->wl.egl.window)
    329     {
    330         wl_egl_window_resize(window->wl.egl.window,
    331                              window->wl.fbWidth,
    332                              window->wl.fbHeight,
    333                              0, 0);
    334     }
    335 
    336     if (!window->wl.transparent)
    337         setContentAreaOpaque(window);
    338 
    339     _glfwInputFramebufferSize(window, window->wl.fbWidth, window->wl.fbHeight);
    340 }
    341 
    342 static GLFWbool resizeWindow(_GLFWwindow* window, int width, int height)
    343 {
    344     width = _glfw_max(width, 1);
    345     height = _glfw_max(height, 1);
    346 
    347     if (width == window->wl.width && height == window->wl.height)
    348         return GLFW_FALSE;
    349 
    350     window->wl.width = width;
    351     window->wl.height = height;
    352 
    353     resizeFramebuffer(window);
    354 
    355     if (window->wl.scalingViewport)
    356     {
    357         wp_viewport_set_destination(window->wl.scalingViewport,
    358                                     window->wl.width,
    359                                     window->wl.height);
    360     }
    361 
    362     if (window->wl.fallback.decorations)
    363     {
    364         wp_viewport_set_destination(window->wl.fallback.top.viewport,
    365                                     window->wl.width,
    366                                     GLFW_CAPTION_HEIGHT);
    367         wl_surface_commit(window->wl.fallback.top.surface);
    368 
    369         wp_viewport_set_destination(window->wl.fallback.left.viewport,
    370                                     GLFW_BORDER_SIZE,
    371                                     window->wl.height + GLFW_CAPTION_HEIGHT);
    372         wl_surface_commit(window->wl.fallback.left.surface);
    373 
    374         wl_subsurface_set_position(window->wl.fallback.right.subsurface,
    375                                 window->wl.width, -GLFW_CAPTION_HEIGHT);
    376         wp_viewport_set_destination(window->wl.fallback.right.viewport,
    377                                     GLFW_BORDER_SIZE,
    378                                     window->wl.height + GLFW_CAPTION_HEIGHT);
    379         wl_surface_commit(window->wl.fallback.right.surface);
    380 
    381         wl_subsurface_set_position(window->wl.fallback.bottom.subsurface,
    382                                 -GLFW_BORDER_SIZE, window->wl.height);
    383         wp_viewport_set_destination(window->wl.fallback.bottom.viewport,
    384                                     window->wl.width + GLFW_BORDER_SIZE * 2,
    385                                     GLFW_BORDER_SIZE);
    386         wl_surface_commit(window->wl.fallback.bottom.surface);
    387     }
    388 
    389     return GLFW_TRUE;
    390 }
    391 
    392 void _glfwUpdateBufferScaleFromOutputsWayland(_GLFWwindow* window)
    393 {
    394     if (wl_compositor_get_version(_glfw.wl.compositor) <
    395         WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION)
    396     {
    397         return;
    398     }
    399 
    400     if (!window->wl.scaleFramebuffer)
    401         return;
    402 
    403     // When using fractional scaling, the buffer scale should remain at 1
    404     if (window->wl.fractionalScale)
    405         return;
    406 
    407     // Get the scale factor from the highest scale monitor.
    408     int32_t maxScale = 1;
    409 
    410     for (size_t i = 0; i < window->wl.outputScaleCount; i++)
    411         maxScale = _glfw_max(window->wl.outputScales[i].factor, maxScale);
    412 
    413     // Only change the framebuffer size if the scale changed.
    414     if (window->wl.bufferScale != maxScale)
    415     {
    416         window->wl.bufferScale = maxScale;
    417         wl_surface_set_buffer_scale(window->wl.surface, maxScale);
    418         _glfwInputWindowContentScale(window, maxScale, maxScale);
    419         resizeFramebuffer(window);
    420 
    421         if (window->wl.visible)
    422             _glfwInputWindowDamage(window);
    423     }
    424 }
    425 
    426 static void surfaceHandleEnter(void* userData,
    427                                struct wl_surface* surface,
    428                                struct wl_output* output)
    429 {
    430     if (wl_proxy_get_tag((struct wl_proxy*) output) != &_glfw.wl.tag)
    431         return;
    432 
    433     _GLFWwindow* window = userData;
    434     _GLFWmonitor* monitor = wl_output_get_user_data(output);
    435     if (!window || !monitor)
    436         return;
    437 
    438     if (window->wl.outputScaleCount + 1 > window->wl.outputScaleSize)
    439     {
    440         window->wl.outputScaleSize++;
    441         window->wl.outputScales =
    442             _glfw_realloc(window->wl.outputScales,
    443                           window->wl.outputScaleSize * sizeof(_GLFWscaleWayland));
    444     }
    445 
    446     window->wl.outputScaleCount++;
    447     window->wl.outputScales[window->wl.outputScaleCount - 1] =
    448         (_GLFWscaleWayland) { output, monitor->wl.scale };
    449 
    450     _glfwUpdateBufferScaleFromOutputsWayland(window);
    451 }
    452 
    453 static void surfaceHandleLeave(void* userData,
    454                                struct wl_surface* surface,
    455                                struct wl_output* output)
    456 {
    457     if (wl_proxy_get_tag((struct wl_proxy*) output) != &_glfw.wl.tag)
    458         return;
    459 
    460     _GLFWwindow* window = userData;
    461 
    462     for (size_t i = 0; i < window->wl.outputScaleCount; i++)
    463     {
    464         if (window->wl.outputScales[i].output == output)
    465         {
    466             window->wl.outputScales[i] =
    467                 window->wl.outputScales[window->wl.outputScaleCount - 1];
    468             window->wl.outputScaleCount--;
    469             break;
    470         }
    471     }
    472 
    473     _glfwUpdateBufferScaleFromOutputsWayland(window);
    474 }
    475 
    476 static const struct wl_surface_listener surfaceListener =
    477 {
    478     surfaceHandleEnter,
    479     surfaceHandleLeave
    480 };
    481 
    482 static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable)
    483 {
    484     if (enable && !window->wl.idleInhibitor && _glfw.wl.idleInhibitManager)
    485     {
    486         window->wl.idleInhibitor =
    487             zwp_idle_inhibit_manager_v1_create_inhibitor(
    488                 _glfw.wl.idleInhibitManager, window->wl.surface);
    489         if (!window->wl.idleInhibitor)
    490             _glfwInputError(GLFW_PLATFORM_ERROR,
    491                             "Wayland: Failed to create idle inhibitor");
    492     }
    493     else if (!enable && window->wl.idleInhibitor)
    494     {
    495         zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor);
    496         window->wl.idleInhibitor = NULL;
    497     }
    498 }
    499 
    500 // Make the specified window and its video mode active on its monitor
    501 //
    502 static void acquireMonitorWayland(_GLFWwindow* window)
    503 {
    504     if (window->wl.libdecor.frame)
    505     {
    506         libdecor_frame_set_fullscreen(window->wl.libdecor.frame,
    507                                       window->monitor->wl.output);
    508     }
    509     else if (window->wl.xdg.toplevel)
    510     {
    511         xdg_toplevel_set_fullscreen(window->wl.xdg.toplevel,
    512                                     window->monitor->wl.output);
    513     }
    514 
    515     setIdleInhibitor(window, GLFW_TRUE);
    516 
    517     if (window->wl.fallback.decorations)
    518         destroyFallbackDecorations(window);
    519 }
    520 
    521 // Remove the window and restore the original video mode
    522 //
    523 static void releaseMonitorWayland(_GLFWwindow* window)
    524 {
    525     if (window->wl.libdecor.frame)
    526         libdecor_frame_unset_fullscreen(window->wl.libdecor.frame);
    527     else if (window->wl.xdg.toplevel)
    528         xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);
    529 
    530     setIdleInhibitor(window, GLFW_FALSE);
    531 
    532     if (!window->wl.libdecor.frame &&
    533         window->wl.xdg.decorationMode != ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE)
    534     {
    535         if (window->decorated)
    536             createFallbackDecorations(window);
    537     }
    538 }
    539 
    540 void fractionalScaleHandlePreferredScale(void* userData,
    541                                          struct wp_fractional_scale_v1* fractionalScale,
    542                                          uint32_t numerator)
    543 {
    544     _GLFWwindow* window = userData;
    545 
    546     window->wl.scalingNumerator = numerator;
    547     _glfwInputWindowContentScale(window, numerator / 120.f, numerator / 120.f);
    548     resizeFramebuffer(window);
    549 
    550     if (window->wl.visible)
    551         _glfwInputWindowDamage(window);
    552 }
    553 
    554 const struct wp_fractional_scale_v1_listener fractionalScaleListener =
    555 {
    556     fractionalScaleHandlePreferredScale,
    557 };
    558 
    559 static void xdgToplevelHandleConfigure(void* userData,
    560                                        struct xdg_toplevel* toplevel,
    561                                        int32_t width,
    562                                        int32_t height,
    563                                        struct wl_array* states)
    564 {
    565     _GLFWwindow* window = userData;
    566     uint32_t* state;
    567 
    568     window->wl.pending.activated  = GLFW_FALSE;
    569     window->wl.pending.maximized  = GLFW_FALSE;
    570     window->wl.pending.fullscreen = GLFW_FALSE;
    571 
    572     wl_array_for_each(state, states)
    573     {
    574         switch (*state)
    575         {
    576             case XDG_TOPLEVEL_STATE_MAXIMIZED:
    577                 window->wl.pending.maximized = GLFW_TRUE;
    578                 break;
    579             case XDG_TOPLEVEL_STATE_FULLSCREEN:
    580                 window->wl.pending.fullscreen = GLFW_TRUE;
    581                 break;
    582             case XDG_TOPLEVEL_STATE_RESIZING:
    583                 break;
    584             case XDG_TOPLEVEL_STATE_ACTIVATED:
    585                 window->wl.pending.activated = GLFW_TRUE;
    586                 break;
    587         }
    588     }
    589 
    590     if (width && height)
    591     {
    592         if (window->wl.fallback.decorations)
    593         {
    594             window->wl.pending.width  = _glfw_max(0, width - GLFW_BORDER_SIZE * 2);
    595             window->wl.pending.height =
    596                 _glfw_max(0, height - GLFW_BORDER_SIZE - GLFW_CAPTION_HEIGHT);
    597         }
    598         else
    599         {
    600             window->wl.pending.width  = width;
    601             window->wl.pending.height = height;
    602         }
    603     }
    604     else
    605     {
    606         window->wl.pending.width  = window->wl.width;
    607         window->wl.pending.height = window->wl.height;
    608     }
    609 }
    610 
    611 static void xdgToplevelHandleClose(void* userData,
    612                                    struct xdg_toplevel* toplevel)
    613 {
    614     _GLFWwindow* window = userData;
    615     _glfwInputWindowCloseRequest(window);
    616 }
    617 
    618 static const struct xdg_toplevel_listener xdgToplevelListener =
    619 {
    620     xdgToplevelHandleConfigure,
    621     xdgToplevelHandleClose
    622 };
    623 
    624 static void xdgSurfaceHandleConfigure(void* userData,
    625                                       struct xdg_surface* surface,
    626                                       uint32_t serial)
    627 {
    628     _GLFWwindow* window = userData;
    629 
    630     xdg_surface_ack_configure(surface, serial);
    631 
    632     if (window->wl.activated != window->wl.pending.activated)
    633     {
    634         window->wl.activated = window->wl.pending.activated;
    635         if (!window->wl.activated)
    636         {
    637             if (window->monitor && window->autoIconify)
    638                 xdg_toplevel_set_minimized(window->wl.xdg.toplevel);
    639         }
    640     }
    641 
    642     if (window->wl.maximized != window->wl.pending.maximized)
    643     {
    644         window->wl.maximized = window->wl.pending.maximized;
    645         _glfwInputWindowMaximize(window, window->wl.maximized);
    646     }
    647 
    648     window->wl.fullscreen = window->wl.pending.fullscreen;
    649 
    650     int width  = window->wl.pending.width;
    651     int height = window->wl.pending.height;
    652 
    653     if (!window->wl.maximized && !window->wl.fullscreen)
    654     {
    655         if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)
    656         {
    657             const float aspectRatio = (float) width / (float) height;
    658             const float targetRatio = (float) window->numer / (float) window->denom;
    659             if (aspectRatio < targetRatio)
    660                 height = width / targetRatio;
    661             else if (aspectRatio > targetRatio)
    662                 width = height * targetRatio;
    663         }
    664     }
    665 
    666     if (resizeWindow(window, width, height))
    667     {
    668         _glfwInputWindowSize(window, window->wl.width, window->wl.height);
    669 
    670         if (window->wl.visible)
    671             _glfwInputWindowDamage(window);
    672     }
    673 
    674     if (!window->wl.visible)
    675     {
    676         // Allow the window to be mapped only if it either has no XDG
    677         // decorations or they have already received a configure event
    678         if (!window->wl.xdg.decoration || window->wl.xdg.decorationMode)
    679         {
    680             window->wl.visible = GLFW_TRUE;
    681             _glfwInputWindowDamage(window);
    682         }
    683     }
    684 }
    685 
    686 static const struct xdg_surface_listener xdgSurfaceListener =
    687 {
    688     xdgSurfaceHandleConfigure
    689 };
    690 
    691 void libdecorFrameHandleConfigure(struct libdecor_frame* frame,
    692                                   struct libdecor_configuration* config,
    693                                   void* userData)
    694 {
    695     _GLFWwindow* window = userData;
    696     int width, height;
    697 
    698     enum libdecor_window_state windowState;
    699     GLFWbool fullscreen, activated, maximized;
    700 
    701     if (libdecor_configuration_get_window_state(config, &windowState))
    702     {
    703         fullscreen = (windowState & LIBDECOR_WINDOW_STATE_FULLSCREEN) != 0;
    704         activated = (windowState & LIBDECOR_WINDOW_STATE_ACTIVE) != 0;
    705         maximized = (windowState & LIBDECOR_WINDOW_STATE_MAXIMIZED) != 0;
    706     }
    707     else
    708     {
    709         fullscreen = window->wl.fullscreen;
    710         activated = window->wl.activated;
    711         maximized = window->wl.maximized;
    712     }
    713 
    714     if (!libdecor_configuration_get_content_size(config, frame, &width, &height))
    715     {
    716         width = window->wl.width;
    717         height = window->wl.height;
    718     }
    719 
    720     if (!maximized && !fullscreen)
    721     {
    722         if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)
    723         {
    724             const float aspectRatio = (float) width / (float) height;
    725             const float targetRatio = (float) window->numer / (float) window->denom;
    726             if (aspectRatio < targetRatio)
    727                 height = width / targetRatio;
    728             else if (aspectRatio > targetRatio)
    729                 width = height * targetRatio;
    730         }
    731     }
    732 
    733     struct libdecor_state* frameState = libdecor_state_new(width, height);
    734     libdecor_frame_commit(frame, frameState, config);
    735     libdecor_state_free(frameState);
    736 
    737     if (window->wl.activated != activated)
    738     {
    739         window->wl.activated = activated;
    740         if (!window->wl.activated)
    741         {
    742             if (window->monitor && window->autoIconify)
    743                 libdecor_frame_set_minimized(window->wl.libdecor.frame);
    744         }
    745     }
    746 
    747     if (window->wl.maximized != maximized)
    748     {
    749         window->wl.maximized = maximized;
    750         _glfwInputWindowMaximize(window, window->wl.maximized);
    751     }
    752 
    753     window->wl.fullscreen = fullscreen;
    754 
    755     GLFWbool damaged = GLFW_FALSE;
    756 
    757     if (!window->wl.visible)
    758     {
    759         window->wl.visible = GLFW_TRUE;
    760         damaged = GLFW_TRUE;
    761     }
    762 
    763     if (resizeWindow(window, width, height))
    764     {
    765         _glfwInputWindowSize(window, window->wl.width, window->wl.height);
    766         damaged = GLFW_TRUE;
    767     }
    768 
    769     if (damaged)
    770         _glfwInputWindowDamage(window);
    771     else
    772         wl_surface_commit(window->wl.surface);
    773 }
    774 
    775 void libdecorFrameHandleClose(struct libdecor_frame* frame, void* userData)
    776 {
    777     _GLFWwindow* window = userData;
    778     _glfwInputWindowCloseRequest(window);
    779 }
    780 
    781 void libdecorFrameHandleCommit(struct libdecor_frame* frame, void* userData)
    782 {
    783     _GLFWwindow* window = userData;
    784     wl_surface_commit(window->wl.surface);
    785 }
    786 
    787 void libdecorFrameHandleDismissPopup(struct libdecor_frame* frame,
    788                                      const char* seatName,
    789                                      void* userData)
    790 {
    791 }
    792 
    793 static const struct libdecor_frame_interface libdecorFrameInterface =
    794 {
    795     libdecorFrameHandleConfigure,
    796     libdecorFrameHandleClose,
    797     libdecorFrameHandleCommit,
    798     libdecorFrameHandleDismissPopup
    799 };
    800 
    801 static GLFWbool createLibdecorFrame(_GLFWwindow* window)
    802 {
    803     // Allow libdecor to finish initialization of itself and its plugin
    804     while (!_glfw.wl.libdecor.ready)
    805         _glfwWaitEventsWayland();
    806 
    807     window->wl.libdecor.frame = libdecor_decorate(_glfw.wl.libdecor.context,
    808                                                   window->wl.surface,
    809                                                   &libdecorFrameInterface,
    810                                                   window);
    811     if (!window->wl.libdecor.frame)
    812     {
    813         _glfwInputError(GLFW_PLATFORM_ERROR,
    814                         "Wayland: Failed to create libdecor frame");
    815         return GLFW_FALSE;
    816     }
    817 
    818     struct libdecor_state* frameState =
    819         libdecor_state_new(window->wl.width, window->wl.height);
    820     libdecor_frame_commit(window->wl.libdecor.frame, frameState, NULL);
    821     libdecor_state_free(frameState);
    822 
    823     if (strlen(window->wl.appId))
    824         libdecor_frame_set_app_id(window->wl.libdecor.frame, window->wl.appId);
    825 
    826     libdecor_frame_set_title(window->wl.libdecor.frame, window->title);
    827 
    828     if (window->minwidth != GLFW_DONT_CARE &&
    829         window->minheight != GLFW_DONT_CARE)
    830     {
    831         libdecor_frame_set_min_content_size(window->wl.libdecor.frame,
    832                                             window->minwidth,
    833                                             window->minheight);
    834     }
    835 
    836     if (window->maxwidth != GLFW_DONT_CARE &&
    837         window->maxheight != GLFW_DONT_CARE)
    838     {
    839         libdecor_frame_set_max_content_size(window->wl.libdecor.frame,
    840                                             window->maxwidth,
    841                                             window->maxheight);
    842     }
    843 
    844     if (!window->resizable)
    845     {
    846         libdecor_frame_unset_capabilities(window->wl.libdecor.frame,
    847                                           LIBDECOR_ACTION_RESIZE);
    848     }
    849 
    850     if (window->monitor)
    851     {
    852         libdecor_frame_set_fullscreen(window->wl.libdecor.frame,
    853                                       window->monitor->wl.output);
    854         setIdleInhibitor(window, GLFW_TRUE);
    855     }
    856     else
    857     {
    858         if (window->wl.maximized)
    859             libdecor_frame_set_maximized(window->wl.libdecor.frame);
    860 
    861         if (!window->decorated)
    862             libdecor_frame_set_visibility(window->wl.libdecor.frame, false);
    863 
    864         setIdleInhibitor(window, GLFW_FALSE);
    865     }
    866 
    867     libdecor_frame_map(window->wl.libdecor.frame);
    868     wl_display_roundtrip(_glfw.wl.display);
    869     return GLFW_TRUE;
    870 }
    871 
    872 static void updateXdgSizeLimits(_GLFWwindow* window)
    873 {
    874     int minwidth, minheight, maxwidth, maxheight;
    875 
    876     if (window->resizable)
    877     {
    878         if (window->minwidth == GLFW_DONT_CARE || window->minheight == GLFW_DONT_CARE)
    879             minwidth = minheight = 0;
    880         else
    881         {
    882             minwidth  = window->minwidth;
    883             minheight = window->minheight;
    884 
    885             if (window->wl.fallback.decorations)
    886             {
    887                 minwidth  += GLFW_BORDER_SIZE * 2;
    888                 minheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE;
    889             }
    890         }
    891 
    892         if (window->maxwidth == GLFW_DONT_CARE || window->maxheight == GLFW_DONT_CARE)
    893             maxwidth = maxheight = 0;
    894         else
    895         {
    896             maxwidth  = window->maxwidth;
    897             maxheight = window->maxheight;
    898 
    899             if (window->wl.fallback.decorations)
    900             {
    901                 maxwidth  += GLFW_BORDER_SIZE * 2;
    902                 maxheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE;
    903             }
    904         }
    905     }
    906     else
    907     {
    908         minwidth = maxwidth = window->wl.width;
    909         minheight = maxheight = window->wl.height;
    910     }
    911 
    912     xdg_toplevel_set_min_size(window->wl.xdg.toplevel, minwidth, minheight);
    913     xdg_toplevel_set_max_size(window->wl.xdg.toplevel, maxwidth, maxheight);
    914 }
    915 
    916 static GLFWbool createXdgShellObjects(_GLFWwindow* window)
    917 {
    918     window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase,
    919                                                          window->wl.surface);
    920     if (!window->wl.xdg.surface)
    921     {
    922         _glfwInputError(GLFW_PLATFORM_ERROR,
    923                         "Wayland: Failed to create xdg-surface for window");
    924         return GLFW_FALSE;
    925     }
    926 
    927     xdg_surface_add_listener(window->wl.xdg.surface, &xdgSurfaceListener, window);
    928 
    929     window->wl.xdg.toplevel = xdg_surface_get_toplevel(window->wl.xdg.surface);
    930     if (!window->wl.xdg.toplevel)
    931     {
    932         _glfwInputError(GLFW_PLATFORM_ERROR,
    933                         "Wayland: Failed to create xdg-toplevel for window");
    934         return GLFW_FALSE;
    935     }
    936 
    937     xdg_toplevel_add_listener(window->wl.xdg.toplevel, &xdgToplevelListener, window);
    938 
    939     if (window->wl.appId)
    940         xdg_toplevel_set_app_id(window->wl.xdg.toplevel, window->wl.appId);
    941 
    942     xdg_toplevel_set_title(window->wl.xdg.toplevel, window->title);
    943 
    944     if (window->monitor)
    945     {
    946         xdg_toplevel_set_fullscreen(window->wl.xdg.toplevel, window->monitor->wl.output);
    947         setIdleInhibitor(window, GLFW_TRUE);
    948     }
    949     else
    950     {
    951         if (window->wl.maximized)
    952             xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
    953 
    954         setIdleInhibitor(window, GLFW_FALSE);
    955     }
    956 
    957     if (_glfw.wl.decorationManager)
    958     {
    959         window->wl.xdg.decoration =
    960             zxdg_decoration_manager_v1_get_toplevel_decoration(
    961                 _glfw.wl.decorationManager, window->wl.xdg.toplevel);
    962         zxdg_toplevel_decoration_v1_add_listener(window->wl.xdg.decoration,
    963                                                  &xdgDecorationListener,
    964                                                  window);
    965 
    966         uint32_t mode;
    967 
    968         if (window->decorated)
    969             mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE;
    970         else
    971             mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
    972 
    973         zxdg_toplevel_decoration_v1_set_mode(window->wl.xdg.decoration, mode);
    974     }
    975     else
    976     {
    977         if (window->decorated && !window->monitor)
    978             createFallbackDecorations(window);
    979     }
    980 
    981     updateXdgSizeLimits(window);
    982 
    983     wl_surface_commit(window->wl.surface);
    984     wl_display_roundtrip(_glfw.wl.display);
    985     return GLFW_TRUE;
    986 }
    987 
    988 static GLFWbool createShellObjects(_GLFWwindow* window)
    989 {
    990     if (_glfw.wl.libdecor.context)
    991     {
    992         if (createLibdecorFrame(window))
    993             return GLFW_TRUE;
    994     }
    995 
    996     return createXdgShellObjects(window);
    997 }
    998 
    999 static void destroyShellObjects(_GLFWwindow* window)
   1000 {
   1001     destroyFallbackDecorations(window);
   1002 
   1003     if (window->wl.libdecor.frame)
   1004         libdecor_frame_unref(window->wl.libdecor.frame);
   1005 
   1006     if (window->wl.xdg.decoration)
   1007         zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration);
   1008 
   1009     if (window->wl.xdg.toplevel)
   1010         xdg_toplevel_destroy(window->wl.xdg.toplevel);
   1011 
   1012     if (window->wl.xdg.surface)
   1013         xdg_surface_destroy(window->wl.xdg.surface);
   1014 
   1015     window->wl.libdecor.frame = NULL;
   1016     window->wl.xdg.decoration = NULL;
   1017     window->wl.xdg.decorationMode = 0;
   1018     window->wl.xdg.toplevel = NULL;
   1019     window->wl.xdg.surface = NULL;
   1020 }
   1021 
   1022 static GLFWbool createNativeSurface(_GLFWwindow* window,
   1023                                     const _GLFWwndconfig* wndconfig,
   1024                                     const _GLFWfbconfig* fbconfig)
   1025 {
   1026     window->wl.surface = wl_compositor_create_surface(_glfw.wl.compositor);
   1027     if (!window->wl.surface)
   1028     {
   1029         _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to create window surface");
   1030         return GLFW_FALSE;
   1031     }
   1032 
   1033     wl_proxy_set_tag((struct wl_proxy*) window->wl.surface, &_glfw.wl.tag);
   1034     wl_surface_add_listener(window->wl.surface,
   1035                             &surfaceListener,
   1036                             window);
   1037 
   1038     window->wl.width = wndconfig->width;
   1039     window->wl.height = wndconfig->height;
   1040     window->wl.fbWidth = wndconfig->width;
   1041     window->wl.fbHeight = wndconfig->height;
   1042     window->wl.appId = _glfw_strdup(wndconfig->wl.appId);
   1043 
   1044     window->wl.bufferScale = 1;
   1045     window->wl.scalingNumerator = 120;
   1046     window->wl.scaleFramebuffer = wndconfig->scaleFramebuffer;
   1047 
   1048     window->wl.maximized = wndconfig->maximized;
   1049 
   1050     window->wl.transparent = fbconfig->transparent;
   1051     if (!window->wl.transparent)
   1052         setContentAreaOpaque(window);
   1053 
   1054     if (_glfw.wl.fractionalScaleManager)
   1055     {
   1056         if (window->wl.scaleFramebuffer)
   1057         {
   1058             window->wl.scalingViewport =
   1059                 wp_viewporter_get_viewport(_glfw.wl.viewporter, window->wl.surface);
   1060 
   1061             wp_viewport_set_destination(window->wl.scalingViewport,
   1062                                         window->wl.width,
   1063                                         window->wl.height);
   1064 
   1065             window->wl.fractionalScale =
   1066                 wp_fractional_scale_manager_v1_get_fractional_scale(
   1067                     _glfw.wl.fractionalScaleManager,
   1068                     window->wl.surface);
   1069 
   1070             wp_fractional_scale_v1_add_listener(window->wl.fractionalScale,
   1071                                                 &fractionalScaleListener,
   1072                                                 window);
   1073         }
   1074     }
   1075 
   1076     return GLFW_TRUE;
   1077 }
   1078 
   1079 static void setCursorImage(_GLFWwindow* window,
   1080                            _GLFWcursorWayland* cursorWayland)
   1081 {
   1082     struct itimerspec timer = {0};
   1083     struct wl_cursor* wlCursor = cursorWayland->cursor;
   1084     struct wl_cursor_image* image;
   1085     struct wl_buffer* buffer;
   1086     struct wl_surface* surface = _glfw.wl.cursorSurface;
   1087     int scale = 1;
   1088 
   1089     if (!wlCursor)
   1090         buffer = cursorWayland->buffer;
   1091     else
   1092     {
   1093         if (window->wl.bufferScale > 1 && cursorWayland->cursorHiDPI)
   1094         {
   1095             wlCursor = cursorWayland->cursorHiDPI;
   1096             scale = 2;
   1097         }
   1098 
   1099         image = wlCursor->images[cursorWayland->currentImage];
   1100         buffer = wl_cursor_image_get_buffer(image);
   1101         if (!buffer)
   1102             return;
   1103 
   1104         timer.it_value.tv_sec = image->delay / 1000;
   1105         timer.it_value.tv_nsec = (image->delay % 1000) * 1000000;
   1106         timerfd_settime(_glfw.wl.cursorTimerfd, 0, &timer, NULL);
   1107 
   1108         cursorWayland->width = image->width;
   1109         cursorWayland->height = image->height;
   1110         cursorWayland->xhot = image->hotspot_x;
   1111         cursorWayland->yhot = image->hotspot_y;
   1112     }
   1113 
   1114     wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial,
   1115                           surface,
   1116                           cursorWayland->xhot / scale,
   1117                           cursorWayland->yhot / scale);
   1118     wl_surface_set_buffer_scale(surface, scale);
   1119     wl_surface_attach(surface, buffer, 0, 0);
   1120     wl_surface_damage(surface, 0, 0,
   1121                       cursorWayland->width, cursorWayland->height);
   1122     wl_surface_commit(surface);
   1123 }
   1124 
   1125 static void incrementCursorImage(_GLFWwindow* window)
   1126 {
   1127     _GLFWcursor* cursor;
   1128 
   1129     if (!window || !window->wl.hovered)
   1130         return;
   1131 
   1132     cursor = window->wl.currentCursor;
   1133     if (cursor && cursor->wl.cursor)
   1134     {
   1135         cursor->wl.currentImage += 1;
   1136         cursor->wl.currentImage %= cursor->wl.cursor->image_count;
   1137         setCursorImage(window, &cursor->wl);
   1138     }
   1139 }
   1140 
   1141 static GLFWbool flushDisplay(void)
   1142 {
   1143     while (wl_display_flush(_glfw.wl.display) == -1)
   1144     {
   1145         if (errno != EAGAIN)
   1146             return GLFW_FALSE;
   1147 
   1148         struct pollfd fd = { wl_display_get_fd(_glfw.wl.display), POLLOUT };
   1149 
   1150         while (poll(&fd, 1, -1) == -1)
   1151         {
   1152             if (errno != EINTR && errno != EAGAIN)
   1153                 return GLFW_FALSE;
   1154         }
   1155     }
   1156 
   1157     return GLFW_TRUE;
   1158 }
   1159 
   1160 static int translateKeyWayland(uint32_t scancode)
   1161 {
   1162     if (scancode < sizeof(_glfw.wl.keycodes) / sizeof(_glfw.wl.keycodes[0]))
   1163         return _glfw.wl.keycodes[scancode];
   1164 
   1165     return GLFW_KEY_UNKNOWN;
   1166 }
   1167 
   1168 static xkb_keysym_t composeSymbol(xkb_keysym_t sym)
   1169 {
   1170     if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState)
   1171         return sym;
   1172     if (xkb_compose_state_feed(_glfw.wl.xkb.composeState, sym)
   1173             != XKB_COMPOSE_FEED_ACCEPTED)
   1174         return sym;
   1175     switch (xkb_compose_state_get_status(_glfw.wl.xkb.composeState))
   1176     {
   1177         case XKB_COMPOSE_COMPOSED:
   1178             return xkb_compose_state_get_one_sym(_glfw.wl.xkb.composeState);
   1179         case XKB_COMPOSE_COMPOSING:
   1180         case XKB_COMPOSE_CANCELLED:
   1181             return XKB_KEY_NoSymbol;
   1182         case XKB_COMPOSE_NOTHING:
   1183         default:
   1184             return sym;
   1185     }
   1186 }
   1187 
   1188 static void inputText(_GLFWwindow* window, uint32_t scancode)
   1189 {
   1190     const xkb_keysym_t* keysyms;
   1191     const xkb_keycode_t keycode = scancode + 8;
   1192 
   1193     if (xkb_state_key_get_syms(_glfw.wl.xkb.state, keycode, &keysyms) == 1)
   1194     {
   1195         const xkb_keysym_t keysym = composeSymbol(keysyms[0]);
   1196         const uint32_t codepoint = _glfwKeySym2Unicode(keysym);
   1197         if (codepoint != GLFW_INVALID_CODEPOINT)
   1198         {
   1199             const int mods = _glfw.wl.xkb.modifiers;
   1200             const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
   1201             _glfwInputChar(window, codepoint, mods, plain);
   1202         }
   1203     }
   1204 }
   1205 
   1206 static void handleEvents(double* timeout)
   1207 {
   1208 #if defined(GLFW_BUILD_LINUX_JOYSTICK)
   1209     if (_glfw.joysticksInitialized)
   1210         _glfwDetectJoystickConnectionLinux();
   1211 #endif
   1212 
   1213     GLFWbool event = GLFW_FALSE;
   1214     enum { DISPLAY_FD, KEYREPEAT_FD, CURSOR_FD, LIBDECOR_FD };
   1215     struct pollfd fds[] =
   1216     {
   1217         [DISPLAY_FD] = { wl_display_get_fd(_glfw.wl.display), POLLIN },
   1218         [KEYREPEAT_FD] = { _glfw.wl.keyRepeatTimerfd, POLLIN },
   1219         [CURSOR_FD] = { _glfw.wl.cursorTimerfd, POLLIN },
   1220         [LIBDECOR_FD] = { -1, POLLIN }
   1221     };
   1222 
   1223     if (_glfw.wl.libdecor.context)
   1224         fds[LIBDECOR_FD].fd = libdecor_get_fd(_glfw.wl.libdecor.context);
   1225 
   1226     while (!event)
   1227     {
   1228         while (wl_display_prepare_read(_glfw.wl.display) != 0)
   1229         {
   1230             if (wl_display_dispatch_pending(_glfw.wl.display) > 0)
   1231                 return;
   1232         }
   1233 
   1234         // If an error other than EAGAIN happens, we have likely been disconnected
   1235         // from the Wayland session; try to handle that the best we can.
   1236         if (!flushDisplay())
   1237         {
   1238             wl_display_cancel_read(_glfw.wl.display);
   1239 
   1240             _GLFWwindow* window = _glfw.windowListHead;
   1241             while (window)
   1242             {
   1243                 _glfwInputWindowCloseRequest(window);
   1244                 window = window->next;
   1245             }
   1246 
   1247             return;
   1248         }
   1249 
   1250         if (!_glfwPollPOSIX(fds, sizeof(fds) / sizeof(fds[0]), timeout))
   1251         {
   1252             wl_display_cancel_read(_glfw.wl.display);
   1253             return;
   1254         }
   1255 
   1256         if (fds[DISPLAY_FD].revents & POLLIN)
   1257         {
   1258             wl_display_read_events(_glfw.wl.display);
   1259             if (wl_display_dispatch_pending(_glfw.wl.display) > 0)
   1260                 event = GLFW_TRUE;
   1261         }
   1262         else
   1263             wl_display_cancel_read(_glfw.wl.display);
   1264 
   1265         if (fds[KEYREPEAT_FD].revents & POLLIN)
   1266         {
   1267             uint64_t repeats;
   1268 
   1269             if (read(_glfw.wl.keyRepeatTimerfd, &repeats, sizeof(repeats)) == 8)
   1270             {
   1271                 for (uint64_t i = 0; i < repeats; i++)
   1272                 {
   1273                     _glfwInputKey(_glfw.wl.keyboardFocus,
   1274                                   translateKeyWayland(_glfw.wl.keyRepeatScancode),
   1275                                   _glfw.wl.keyRepeatScancode,
   1276                                   GLFW_PRESS,
   1277                                   _glfw.wl.xkb.modifiers);
   1278                     inputText(_glfw.wl.keyboardFocus, _glfw.wl.keyRepeatScancode);
   1279                 }
   1280 
   1281                 event = GLFW_TRUE;
   1282             }
   1283         }
   1284 
   1285         if (fds[CURSOR_FD].revents & POLLIN)
   1286         {
   1287             uint64_t repeats;
   1288 
   1289             if (read(_glfw.wl.cursorTimerfd, &repeats, sizeof(repeats)) == 8)
   1290                 incrementCursorImage(_glfw.wl.pointerFocus);
   1291         }
   1292 
   1293         if (fds[LIBDECOR_FD].revents & POLLIN)
   1294         {
   1295             if (libdecor_dispatch(_glfw.wl.libdecor.context, 0) > 0)
   1296                 event = GLFW_TRUE;
   1297         }
   1298     }
   1299 }
   1300 
   1301 // Reads the specified data offer as the specified MIME type
   1302 //
   1303 static char* readDataOfferAsString(struct wl_data_offer* offer, const char* mimeType)
   1304 {
   1305     int fds[2];
   1306 
   1307     if (pipe2(fds, O_CLOEXEC) == -1)
   1308     {
   1309         _glfwInputError(GLFW_PLATFORM_ERROR,
   1310                         "Wayland: Failed to create pipe for data offer: %s",
   1311                         strerror(errno));
   1312         return NULL;
   1313     }
   1314 
   1315     wl_data_offer_receive(offer, mimeType, fds[1]);
   1316     flushDisplay();
   1317     close(fds[1]);
   1318 
   1319     char* string = NULL;
   1320     size_t size = 0;
   1321     size_t length = 0;
   1322 
   1323     for (;;)
   1324     {
   1325         const size_t readSize = 4096;
   1326         const size_t requiredSize = length + readSize + 1;
   1327         if (requiredSize > size)
   1328         {
   1329             char* longer = _glfw_realloc(string, requiredSize);
   1330             if (!longer)
   1331             {
   1332                 _glfwInputError(GLFW_OUT_OF_MEMORY, NULL);
   1333                 close(fds[0]);
   1334                 return NULL;
   1335             }
   1336 
   1337             string = longer;
   1338             size = requiredSize;
   1339         }
   1340 
   1341         const ssize_t result = read(fds[0], string + length, readSize);
   1342         if (result == 0)
   1343             break;
   1344         else if (result == -1)
   1345         {
   1346             if (errno == EINTR)
   1347                 continue;
   1348 
   1349             _glfwInputError(GLFW_PLATFORM_ERROR,
   1350                             "Wayland: Failed to read from data offer pipe: %s",
   1351                             strerror(errno));
   1352             close(fds[0]);
   1353             return NULL;
   1354         }
   1355 
   1356         length += result;
   1357     }
   1358 
   1359     close(fds[0]);
   1360 
   1361     string[length] = '\0';
   1362     return string;
   1363 }
   1364 
   1365 static void pointerHandleEnter(void* userData,
   1366                                struct wl_pointer* pointer,
   1367                                uint32_t serial,
   1368                                struct wl_surface* surface,
   1369                                wl_fixed_t sx,
   1370                                wl_fixed_t sy)
   1371 {
   1372     // Happens in the case we just destroyed the surface.
   1373     if (!surface)
   1374         return;
   1375 
   1376     if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag)
   1377         return;
   1378 
   1379     _GLFWwindow* window = wl_surface_get_user_data(surface);
   1380 
   1381     _glfw.wl.serial = serial;
   1382     _glfw.wl.pointerEnterSerial = serial;
   1383     _glfw.wl.pointerFocus = window;
   1384 
   1385     if (surface == window->wl.surface)
   1386     {
   1387         window->wl.hovered = GLFW_TRUE;
   1388         _glfwSetCursorWayland(window, window->wl.currentCursor);
   1389         _glfwInputCursorEnter(window, GLFW_TRUE);
   1390     }
   1391     else
   1392     {
   1393         if (window->wl.fallback.decorations)
   1394             window->wl.fallback.focus = surface;
   1395     }
   1396 }
   1397 
   1398 static void pointerHandleLeave(void* userData,
   1399                                struct wl_pointer* pointer,
   1400                                uint32_t serial,
   1401                                struct wl_surface* surface)
   1402 {
   1403     if (!surface)
   1404         return;
   1405 
   1406     if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag)
   1407         return;
   1408 
   1409     _GLFWwindow* window = _glfw.wl.pointerFocus;
   1410     if (!window)
   1411         return;
   1412 
   1413     _glfw.wl.serial = serial;
   1414     _glfw.wl.pointerFocus = NULL;
   1415     _glfw.wl.cursorPreviousName = NULL;
   1416 
   1417     if (window->wl.hovered)
   1418     {
   1419         window->wl.hovered = GLFW_FALSE;
   1420         _glfwInputCursorEnter(window, GLFW_FALSE);
   1421     }
   1422     else
   1423     {
   1424         if (window->wl.fallback.decorations)
   1425             window->wl.fallback.focus = NULL;
   1426     }
   1427 }
   1428 
   1429 static void pointerHandleMotion(void* userData,
   1430                                 struct wl_pointer* pointer,
   1431                                 uint32_t time,
   1432                                 wl_fixed_t sx,
   1433                                 wl_fixed_t sy)
   1434 {
   1435     _GLFWwindow* window = _glfw.wl.pointerFocus;
   1436     if (!window)
   1437         return;
   1438 
   1439     if (window->cursorMode == GLFW_CURSOR_DISABLED)
   1440         return;
   1441 
   1442     const double xpos = wl_fixed_to_double(sx);
   1443     const double ypos = wl_fixed_to_double(sy);
   1444     window->wl.cursorPosX = xpos;
   1445     window->wl.cursorPosY = ypos;
   1446 
   1447     if (window->wl.hovered)
   1448     {
   1449         _glfw.wl.cursorPreviousName = NULL;
   1450         _glfwInputCursorPos(window, xpos, ypos);
   1451         return;
   1452     }
   1453 
   1454     if (window->wl.fallback.decorations)
   1455     {
   1456         const char* cursorName = "left_ptr";
   1457 
   1458         if (window->resizable)
   1459         {
   1460             if (window->wl.fallback.focus == window->wl.fallback.top.surface)
   1461             {
   1462                 if (ypos < GLFW_BORDER_SIZE)
   1463                     cursorName = "n-resize";
   1464             }
   1465             else if (window->wl.fallback.focus == window->wl.fallback.left.surface)
   1466             {
   1467                 if (ypos < GLFW_BORDER_SIZE)
   1468                     cursorName = "nw-resize";
   1469                 else
   1470                     cursorName = "w-resize";
   1471             }
   1472             else if (window->wl.fallback.focus == window->wl.fallback.right.surface)
   1473             {
   1474                 if (ypos < GLFW_BORDER_SIZE)
   1475                     cursorName = "ne-resize";
   1476                 else
   1477                     cursorName = "e-resize";
   1478             }
   1479             else if (window->wl.fallback.focus == window->wl.fallback.bottom.surface)
   1480             {
   1481                 if (xpos < GLFW_BORDER_SIZE)
   1482                     cursorName = "sw-resize";
   1483                 else if (xpos > window->wl.width + GLFW_BORDER_SIZE)
   1484                     cursorName = "se-resize";
   1485                 else
   1486                     cursorName = "s-resize";
   1487             }
   1488         }
   1489 
   1490         if (_glfw.wl.cursorPreviousName != cursorName)
   1491         {
   1492             struct wl_surface* surface = _glfw.wl.cursorSurface;
   1493             struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;
   1494             int scale = 1;
   1495 
   1496             if (window->wl.bufferScale > 1 && _glfw.wl.cursorThemeHiDPI)
   1497             {
   1498                 // We only support up to scale=2 for now, since libwayland-cursor
   1499                 // requires us to load a different theme for each size.
   1500                 scale = 2;
   1501                 theme = _glfw.wl.cursorThemeHiDPI;
   1502             }
   1503 
   1504             struct wl_cursor* cursor = wl_cursor_theme_get_cursor(theme, cursorName);
   1505             if (!cursor)
   1506                 return;
   1507 
   1508             // TODO: handle animated cursors too.
   1509             struct wl_cursor_image* image = cursor->images[0];
   1510             if (!image)
   1511                 return;
   1512 
   1513             struct wl_buffer* buffer = wl_cursor_image_get_buffer(image);
   1514             if (!buffer)
   1515                 return;
   1516 
   1517             wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial,
   1518                                   surface,
   1519                                   image->hotspot_x / scale,
   1520                                   image->hotspot_y / scale);
   1521             wl_surface_set_buffer_scale(surface, scale);
   1522             wl_surface_attach(surface, buffer, 0, 0);
   1523             wl_surface_damage(surface, 0, 0, image->width, image->height);
   1524             wl_surface_commit(surface);
   1525 
   1526             _glfw.wl.cursorPreviousName = cursorName;
   1527         }
   1528     }
   1529 }
   1530 
   1531 static void pointerHandleButton(void* userData,
   1532                                 struct wl_pointer* pointer,
   1533                                 uint32_t serial,
   1534                                 uint32_t time,
   1535                                 uint32_t button,
   1536                                 uint32_t state)
   1537 {
   1538     _GLFWwindow* window = _glfw.wl.pointerFocus;
   1539     if (!window)
   1540         return;
   1541 
   1542     if (window->wl.hovered)
   1543     {
   1544         _glfw.wl.serial = serial;
   1545 
   1546         _glfwInputMouseClick(window,
   1547                              button - BTN_LEFT,
   1548                              state == WL_POINTER_BUTTON_STATE_PRESSED,
   1549                              _glfw.wl.xkb.modifiers);
   1550         return;
   1551     }
   1552 
   1553     if (window->wl.fallback.decorations)
   1554     {
   1555         if (button == BTN_LEFT)
   1556         {
   1557             uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
   1558 
   1559             if (window->wl.fallback.focus == window->wl.fallback.top.surface)
   1560             {
   1561                 if (window->wl.cursorPosY < GLFW_BORDER_SIZE)
   1562                     edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
   1563                 else
   1564                     xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
   1565             }
   1566             else if (window->wl.fallback.focus == window->wl.fallback.left.surface)
   1567             {
   1568                 if (window->wl.cursorPosY < GLFW_BORDER_SIZE)
   1569                     edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
   1570                 else
   1571                     edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
   1572             }
   1573             else if (window->wl.fallback.focus == window->wl.fallback.right.surface)
   1574             {
   1575                 if (window->wl.cursorPosY < GLFW_BORDER_SIZE)
   1576                     edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
   1577                 else
   1578                     edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
   1579             }
   1580             else if (window->wl.fallback.focus == window->wl.fallback.bottom.surface)
   1581             {
   1582                 if (window->wl.cursorPosX < GLFW_BORDER_SIZE)
   1583                     edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
   1584                 else if (window->wl.cursorPosX > window->wl.width + GLFW_BORDER_SIZE)
   1585                     edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
   1586                 else
   1587                     edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
   1588             }
   1589 
   1590             if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE)
   1591             {
   1592                 xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat,
   1593                                     serial, edges);
   1594             }
   1595         }
   1596         else if (button == BTN_RIGHT)
   1597         {
   1598             if (window->wl.xdg.toplevel)
   1599             {
   1600                 xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
   1601                                               _glfw.wl.seat, serial,
   1602                                               window->wl.cursorPosX,
   1603                                               window->wl.cursorPosY);
   1604             }
   1605         }
   1606     }
   1607 }
   1608 
   1609 static void pointerHandleAxis(void* userData,
   1610                               struct wl_pointer* pointer,
   1611                               uint32_t time,
   1612                               uint32_t axis,
   1613                               wl_fixed_t value)
   1614 {
   1615     _GLFWwindow* window = _glfw.wl.pointerFocus;
   1616     if (!window)
   1617         return;
   1618 
   1619     // NOTE: 10 units of motion per mouse wheel step seems to be a common ratio
   1620     if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
   1621         _glfwInputScroll(window, -wl_fixed_to_double(value) / 10.0, 0.0);
   1622     else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
   1623         _glfwInputScroll(window, 0.0, -wl_fixed_to_double(value) / 10.0);
   1624 }
   1625 
   1626 static const struct wl_pointer_listener pointerListener =
   1627 {
   1628     pointerHandleEnter,
   1629     pointerHandleLeave,
   1630     pointerHandleMotion,
   1631     pointerHandleButton,
   1632     pointerHandleAxis,
   1633 };
   1634 
   1635 static void keyboardHandleKeymap(void* userData,
   1636                                  struct wl_keyboard* keyboard,
   1637                                  uint32_t format,
   1638                                  int fd,
   1639                                  uint32_t size)
   1640 {
   1641     struct xkb_keymap* keymap;
   1642     struct xkb_state* state;
   1643     struct xkb_compose_table* composeTable;
   1644     struct xkb_compose_state* composeState;
   1645 
   1646     char* mapStr;
   1647     const char* locale;
   1648 
   1649     if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
   1650     {
   1651         close(fd);
   1652         return;
   1653     }
   1654 
   1655     mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
   1656     if (mapStr == MAP_FAILED) {
   1657         close(fd);
   1658         return;
   1659     }
   1660 
   1661     keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context,
   1662                                         mapStr,
   1663                                         XKB_KEYMAP_FORMAT_TEXT_V1,
   1664                                         0);
   1665     munmap(mapStr, size);
   1666     close(fd);
   1667 
   1668     if (!keymap)
   1669     {
   1670         _glfwInputError(GLFW_PLATFORM_ERROR,
   1671                         "Wayland: Failed to compile keymap");
   1672         return;
   1673     }
   1674 
   1675     state = xkb_state_new(keymap);
   1676     if (!state)
   1677     {
   1678         _glfwInputError(GLFW_PLATFORM_ERROR,
   1679                         "Wayland: Failed to create XKB state");
   1680         xkb_keymap_unref(keymap);
   1681         return;
   1682     }
   1683 
   1684     // Look up the preferred locale, falling back to "C" as default.
   1685     locale = getenv("LC_ALL");
   1686     if (!locale)
   1687         locale = getenv("LC_CTYPE");
   1688     if (!locale)
   1689         locale = getenv("LANG");
   1690     if (!locale)
   1691         locale = "C";
   1692 
   1693     composeTable =
   1694         xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale,
   1695                                           XKB_COMPOSE_COMPILE_NO_FLAGS);
   1696     if (composeTable)
   1697     {
   1698         composeState =
   1699             xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS);
   1700         xkb_compose_table_unref(composeTable);
   1701         if (composeState)
   1702             _glfw.wl.xkb.composeState = composeState;
   1703         else
   1704             _glfwInputError(GLFW_PLATFORM_ERROR,
   1705                             "Wayland: Failed to create XKB compose state");
   1706     }
   1707     else
   1708     {
   1709         _glfwInputError(GLFW_PLATFORM_ERROR,
   1710                         "Wayland: Failed to create XKB compose table");
   1711     }
   1712 
   1713     xkb_keymap_unref(_glfw.wl.xkb.keymap);
   1714     xkb_state_unref(_glfw.wl.xkb.state);
   1715     _glfw.wl.xkb.keymap = keymap;
   1716     _glfw.wl.xkb.state = state;
   1717 
   1718     _glfw.wl.xkb.controlIndex  = xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Control");
   1719     _glfw.wl.xkb.altIndex      = xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod1");
   1720     _glfw.wl.xkb.shiftIndex    = xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift");
   1721     _glfw.wl.xkb.superIndex    = xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4");
   1722     _glfw.wl.xkb.capsLockIndex = xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock");
   1723     _glfw.wl.xkb.numLockIndex  = xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2");
   1724 }
   1725 
   1726 static void keyboardHandleEnter(void* userData,
   1727                                 struct wl_keyboard* keyboard,
   1728                                 uint32_t serial,
   1729                                 struct wl_surface* surface,
   1730                                 struct wl_array* keys)
   1731 {
   1732     // Happens in the case we just destroyed the surface.
   1733     if (!surface)
   1734         return;
   1735 
   1736     if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag)
   1737         return;
   1738 
   1739     _GLFWwindow* window = wl_surface_get_user_data(surface);
   1740     if (surface != window->wl.surface)
   1741         return;
   1742 
   1743     _glfw.wl.serial = serial;
   1744     _glfw.wl.keyboardFocus = window;
   1745     _glfwInputWindowFocus(window, GLFW_TRUE);
   1746 }
   1747 
   1748 static void keyboardHandleLeave(void* userData,
   1749                                 struct wl_keyboard* keyboard,
   1750                                 uint32_t serial,
   1751                                 struct wl_surface* surface)
   1752 {
   1753     _GLFWwindow* window = _glfw.wl.keyboardFocus;
   1754 
   1755     if (!window)
   1756         return;
   1757 
   1758     struct itimerspec timer = {0};
   1759     timerfd_settime(_glfw.wl.keyRepeatTimerfd, 0, &timer, NULL);
   1760 
   1761     _glfw.wl.serial = serial;
   1762     _glfw.wl.keyboardFocus = NULL;
   1763     _glfwInputWindowFocus(window, GLFW_FALSE);
   1764 }
   1765 
   1766 static void keyboardHandleKey(void* userData,
   1767                               struct wl_keyboard* keyboard,
   1768                               uint32_t serial,
   1769                               uint32_t time,
   1770                               uint32_t scancode,
   1771                               uint32_t state)
   1772 {
   1773     _GLFWwindow* window = _glfw.wl.keyboardFocus;
   1774     if (!window)
   1775         return;
   1776 
   1777     const int key = translateKeyWayland(scancode);
   1778     const int action =
   1779         state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE;
   1780 
   1781     _glfw.wl.serial = serial;
   1782 
   1783     struct itimerspec timer = {0};
   1784 
   1785     if (action == GLFW_PRESS)
   1786     {
   1787         const xkb_keycode_t keycode = scancode + 8;
   1788 
   1789         if (xkb_keymap_key_repeats(_glfw.wl.xkb.keymap, keycode) &&
   1790             _glfw.wl.keyRepeatRate > 0)
   1791         {
   1792             _glfw.wl.keyRepeatScancode = scancode;
   1793             if (_glfw.wl.keyRepeatRate > 1)
   1794                 timer.it_interval.tv_nsec = 1000000000 / _glfw.wl.keyRepeatRate;
   1795             else
   1796                 timer.it_interval.tv_sec = 1;
   1797 
   1798             timer.it_value.tv_sec = _glfw.wl.keyRepeatDelay / 1000;
   1799             timer.it_value.tv_nsec = (_glfw.wl.keyRepeatDelay % 1000) * 1000000;
   1800         }
   1801     }
   1802 
   1803     timerfd_settime(_glfw.wl.keyRepeatTimerfd, 0, &timer, NULL);
   1804 
   1805     _glfwInputKey(window, key, scancode, action, _glfw.wl.xkb.modifiers);
   1806 
   1807     if (action == GLFW_PRESS)
   1808         inputText(window, scancode);
   1809 }
   1810 
   1811 static void keyboardHandleModifiers(void* userData,
   1812                                     struct wl_keyboard* keyboard,
   1813                                     uint32_t serial,
   1814                                     uint32_t modsDepressed,
   1815                                     uint32_t modsLatched,
   1816                                     uint32_t modsLocked,
   1817                                     uint32_t group)
   1818 {
   1819     _glfw.wl.serial = serial;
   1820 
   1821     if (!_glfw.wl.xkb.keymap)
   1822         return;
   1823 
   1824     xkb_state_update_mask(_glfw.wl.xkb.state,
   1825                           modsDepressed,
   1826                           modsLatched,
   1827                           modsLocked,
   1828                           0,
   1829                           0,
   1830                           group);
   1831 
   1832     _glfw.wl.xkb.modifiers = 0;
   1833 
   1834     struct
   1835     {
   1836         xkb_mod_index_t index;
   1837         unsigned int bit;
   1838     } modifiers[] =
   1839     {
   1840         { _glfw.wl.xkb.controlIndex,  GLFW_MOD_CONTROL },
   1841         { _glfw.wl.xkb.altIndex,      GLFW_MOD_ALT },
   1842         { _glfw.wl.xkb.shiftIndex,    GLFW_MOD_SHIFT },
   1843         { _glfw.wl.xkb.superIndex,    GLFW_MOD_SUPER },
   1844         { _glfw.wl.xkb.capsLockIndex, GLFW_MOD_CAPS_LOCK },
   1845         { _glfw.wl.xkb.numLockIndex,  GLFW_MOD_NUM_LOCK }
   1846     };
   1847 
   1848     for (size_t i = 0; i < sizeof(modifiers) / sizeof(modifiers[0]); i++)
   1849     {
   1850         if (xkb_state_mod_index_is_active(_glfw.wl.xkb.state,
   1851                                           modifiers[i].index,
   1852                                           XKB_STATE_MODS_EFFECTIVE) == 1)
   1853         {
   1854             _glfw.wl.xkb.modifiers |= modifiers[i].bit;
   1855         }
   1856     }
   1857 }
   1858 
   1859 static void keyboardHandleRepeatInfo(void* userData,
   1860                                      struct wl_keyboard* keyboard,
   1861                                      int32_t rate,
   1862                                      int32_t delay)
   1863 {
   1864     if (keyboard != _glfw.wl.keyboard)
   1865         return;
   1866 
   1867     _glfw.wl.keyRepeatRate = rate;
   1868     _glfw.wl.keyRepeatDelay = delay;
   1869 }
   1870 
   1871 static const struct wl_keyboard_listener keyboardListener =
   1872 {
   1873     keyboardHandleKeymap,
   1874     keyboardHandleEnter,
   1875     keyboardHandleLeave,
   1876     keyboardHandleKey,
   1877     keyboardHandleModifiers,
   1878     keyboardHandleRepeatInfo,
   1879 };
   1880 
   1881 static void seatHandleCapabilities(void* userData,
   1882                                    struct wl_seat* seat,
   1883                                    enum wl_seat_capability caps)
   1884 {
   1885     if ((caps & WL_SEAT_CAPABILITY_POINTER) && !_glfw.wl.pointer)
   1886     {
   1887         _glfw.wl.pointer = wl_seat_get_pointer(seat);
   1888         wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL);
   1889     }
   1890     else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer)
   1891     {
   1892         wl_pointer_destroy(_glfw.wl.pointer);
   1893         _glfw.wl.pointer = NULL;
   1894     }
   1895 
   1896     if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !_glfw.wl.keyboard)
   1897     {
   1898         _glfw.wl.keyboard = wl_seat_get_keyboard(seat);
   1899         wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL);
   1900     }
   1901     else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard)
   1902     {
   1903         wl_keyboard_destroy(_glfw.wl.keyboard);
   1904         _glfw.wl.keyboard = NULL;
   1905     }
   1906 }
   1907 
   1908 static void seatHandleName(void* userData,
   1909                            struct wl_seat* seat,
   1910                            const char* name)
   1911 {
   1912 }
   1913 
   1914 static const struct wl_seat_listener seatListener =
   1915 {
   1916     seatHandleCapabilities,
   1917     seatHandleName,
   1918 };
   1919 
   1920 static void dataOfferHandleOffer(void* userData,
   1921                                  struct wl_data_offer* offer,
   1922                                  const char* mimeType)
   1923 {
   1924     for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
   1925     {
   1926         if (_glfw.wl.offers[i].offer == offer)
   1927         {
   1928             if (strcmp(mimeType, "text/plain;charset=utf-8") == 0)
   1929                 _glfw.wl.offers[i].text_plain_utf8 = GLFW_TRUE;
   1930             else if (strcmp(mimeType, "text/uri-list") == 0)
   1931                 _glfw.wl.offers[i].text_uri_list = GLFW_TRUE;
   1932 
   1933             break;
   1934         }
   1935     }
   1936 }
   1937 
   1938 static const struct wl_data_offer_listener dataOfferListener =
   1939 {
   1940     dataOfferHandleOffer
   1941 };
   1942 
   1943 static void dataDeviceHandleDataOffer(void* userData,
   1944                                       struct wl_data_device* device,
   1945                                       struct wl_data_offer* offer)
   1946 {
   1947     _GLFWofferWayland* offers =
   1948         _glfw_realloc(_glfw.wl.offers,
   1949                       sizeof(_GLFWofferWayland) * (_glfw.wl.offerCount + 1));
   1950     if (!offers)
   1951     {
   1952         _glfwInputError(GLFW_OUT_OF_MEMORY, NULL);
   1953         return;
   1954     }
   1955 
   1956     _glfw.wl.offers = offers;
   1957     _glfw.wl.offerCount++;
   1958 
   1959     _glfw.wl.offers[_glfw.wl.offerCount - 1] = (_GLFWofferWayland) { offer };
   1960     wl_data_offer_add_listener(offer, &dataOfferListener, NULL);
   1961 }
   1962 
   1963 static void dataDeviceHandleEnter(void* userData,
   1964                                   struct wl_data_device* device,
   1965                                   uint32_t serial,
   1966                                   struct wl_surface* surface,
   1967                                   wl_fixed_t x,
   1968                                   wl_fixed_t y,
   1969                                   struct wl_data_offer* offer)
   1970 {
   1971     if (_glfw.wl.dragOffer)
   1972     {
   1973         wl_data_offer_destroy(_glfw.wl.dragOffer);
   1974         _glfw.wl.dragOffer = NULL;
   1975         _glfw.wl.dragFocus = NULL;
   1976     }
   1977 
   1978     for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
   1979     {
   1980         if (_glfw.wl.offers[i].offer == offer)
   1981         {
   1982             _GLFWwindow* window = NULL;
   1983 
   1984             if (surface)
   1985             {
   1986                 if (wl_proxy_get_tag((struct wl_proxy*) surface) == &_glfw.wl.tag)
   1987                     window = wl_surface_get_user_data(surface);
   1988             }
   1989 
   1990             if (surface == window->wl.surface && _glfw.wl.offers[i].text_uri_list)
   1991             {
   1992                 _glfw.wl.dragOffer = offer;
   1993                 _glfw.wl.dragFocus = window;
   1994                 _glfw.wl.dragSerial = serial;
   1995             }
   1996 
   1997             _glfw.wl.offers[i] = _glfw.wl.offers[_glfw.wl.offerCount - 1];
   1998             _glfw.wl.offerCount--;
   1999             break;
   2000         }
   2001     }
   2002 
   2003     if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag)
   2004         return;
   2005 
   2006     if (_glfw.wl.dragOffer)
   2007         wl_data_offer_accept(offer, serial, "text/uri-list");
   2008     else
   2009     {
   2010         wl_data_offer_accept(offer, serial, NULL);
   2011         wl_data_offer_destroy(offer);
   2012     }
   2013 }
   2014 
   2015 static void dataDeviceHandleLeave(void* userData,
   2016                                   struct wl_data_device* device)
   2017 {
   2018     if (_glfw.wl.dragOffer)
   2019     {
   2020         wl_data_offer_destroy(_glfw.wl.dragOffer);
   2021         _glfw.wl.dragOffer = NULL;
   2022         _glfw.wl.dragFocus = NULL;
   2023     }
   2024 }
   2025 
   2026 static void dataDeviceHandleMotion(void* userData,
   2027                                    struct wl_data_device* device,
   2028                                    uint32_t time,
   2029                                    wl_fixed_t x,
   2030                                    wl_fixed_t y)
   2031 {
   2032 }
   2033 
   2034 static void dataDeviceHandleDrop(void* userData,
   2035                                  struct wl_data_device* device)
   2036 {
   2037     if (!_glfw.wl.dragOffer)
   2038         return;
   2039 
   2040     char* string = readDataOfferAsString(_glfw.wl.dragOffer, "text/uri-list");
   2041     if (string)
   2042     {
   2043         int count;
   2044         char** paths = _glfwParseUriList(string, &count);
   2045         if (paths)
   2046             _glfwInputDrop(_glfw.wl.dragFocus, count, (const char**) paths);
   2047 
   2048         for (int i = 0; i < count; i++)
   2049             _glfw_free(paths[i]);
   2050 
   2051         _glfw_free(paths);
   2052     }
   2053 
   2054     _glfw_free(string);
   2055 }
   2056 
   2057 static void dataDeviceHandleSelection(void* userData,
   2058                                       struct wl_data_device* device,
   2059                                       struct wl_data_offer* offer)
   2060 {
   2061     if (_glfw.wl.selectionOffer)
   2062     {
   2063         wl_data_offer_destroy(_glfw.wl.selectionOffer);
   2064         _glfw.wl.selectionOffer = NULL;
   2065     }
   2066 
   2067     for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
   2068     {
   2069         if (_glfw.wl.offers[i].offer == offer)
   2070         {
   2071             if (_glfw.wl.offers[i].text_plain_utf8)
   2072                 _glfw.wl.selectionOffer = offer;
   2073             else
   2074                 wl_data_offer_destroy(offer);
   2075 
   2076             _glfw.wl.offers[i] = _glfw.wl.offers[_glfw.wl.offerCount - 1];
   2077             _glfw.wl.offerCount--;
   2078             break;
   2079         }
   2080     }
   2081 }
   2082 
   2083 const struct wl_data_device_listener dataDeviceListener =
   2084 {
   2085     dataDeviceHandleDataOffer,
   2086     dataDeviceHandleEnter,
   2087     dataDeviceHandleLeave,
   2088     dataDeviceHandleMotion,
   2089     dataDeviceHandleDrop,
   2090     dataDeviceHandleSelection,
   2091 };
   2092 
   2093 static void xdgActivationHandleDone(void* userData,
   2094                                     struct xdg_activation_token_v1* activationToken,
   2095                                     const char* token)
   2096 {
   2097     _GLFWwindow* window = userData;
   2098 
   2099     if (activationToken != window->wl.activationToken)
   2100         return;
   2101 
   2102     xdg_activation_v1_activate(_glfw.wl.activationManager, token, window->wl.surface);
   2103     xdg_activation_token_v1_destroy(window->wl.activationToken);
   2104     window->wl.activationToken = NULL;
   2105 }
   2106 
   2107 static const struct xdg_activation_token_v1_listener xdgActivationListener =
   2108 {
   2109     xdgActivationHandleDone
   2110 };
   2111 
   2112 void _glfwAddSeatListenerWayland(struct wl_seat* seat)
   2113 {
   2114     wl_seat_add_listener(seat, &seatListener, NULL);
   2115 }
   2116 
   2117 void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device)
   2118 {
   2119     wl_data_device_add_listener(device, &dataDeviceListener, NULL);
   2120 }
   2121 
   2122 
   2123 //////////////////////////////////////////////////////////////////////////
   2124 //////                       GLFW platform API                      //////
   2125 //////////////////////////////////////////////////////////////////////////
   2126 
   2127 GLFWbool _glfwCreateWindowWayland(_GLFWwindow* window,
   2128                                   const _GLFWwndconfig* wndconfig,
   2129                                   const _GLFWctxconfig* ctxconfig,
   2130                                   const _GLFWfbconfig* fbconfig)
   2131 {
   2132     if (!createNativeSurface(window, wndconfig, fbconfig))
   2133         return GLFW_FALSE;
   2134 
   2135     if (ctxconfig->client != GLFW_NO_API)
   2136     {
   2137         if (ctxconfig->source == GLFW_EGL_CONTEXT_API ||
   2138             ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
   2139         {
   2140             window->wl.egl.window = wl_egl_window_create(window->wl.surface,
   2141                                                          window->wl.fbWidth,
   2142                                                          window->wl.fbHeight);
   2143             if (!window->wl.egl.window)
   2144             {
   2145                 _glfwInputError(GLFW_PLATFORM_ERROR,
   2146                                 "Wayland: Failed to create EGL window");
   2147                 return GLFW_FALSE;
   2148             }
   2149 
   2150             if (!_glfwInitEGL())
   2151                 return GLFW_FALSE;
   2152             if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
   2153                 return GLFW_FALSE;
   2154         }
   2155         else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
   2156         {
   2157             if (!_glfwInitOSMesa())
   2158                 return GLFW_FALSE;
   2159             if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
   2160                 return GLFW_FALSE;
   2161         }
   2162 
   2163         if (!_glfwRefreshContextAttribs(window, ctxconfig))
   2164             return GLFW_FALSE;
   2165     }
   2166 
   2167     if (wndconfig->mousePassthrough)
   2168         _glfwSetWindowMousePassthroughWayland(window, GLFW_TRUE);
   2169 
   2170     if (window->monitor || wndconfig->visible)
   2171     {
   2172         if (!createShellObjects(window))
   2173             return GLFW_FALSE;
   2174     }
   2175 
   2176     return GLFW_TRUE;
   2177 }
   2178 
   2179 void _glfwDestroyWindowWayland(_GLFWwindow* window)
   2180 {
   2181     if (window == _glfw.wl.pointerFocus)
   2182         _glfw.wl.pointerFocus = NULL;
   2183 
   2184     if (window == _glfw.wl.keyboardFocus)
   2185         _glfw.wl.keyboardFocus = NULL;
   2186 
   2187     if (window->wl.activationToken)
   2188         xdg_activation_token_v1_destroy(window->wl.activationToken);
   2189 
   2190     if (window->wl.idleInhibitor)
   2191         zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor);
   2192 
   2193     if (window->wl.relativePointer)
   2194         zwp_relative_pointer_v1_destroy(window->wl.relativePointer);
   2195 
   2196     if (window->wl.lockedPointer)
   2197         zwp_locked_pointer_v1_destroy(window->wl.lockedPointer);
   2198 
   2199     if (window->wl.confinedPointer)
   2200         zwp_confined_pointer_v1_destroy(window->wl.confinedPointer);
   2201 
   2202     if (window->context.destroy)
   2203         window->context.destroy(window);
   2204 
   2205     destroyShellObjects(window);
   2206 
   2207     if (window->wl.fallback.buffer)
   2208         wl_buffer_destroy(window->wl.fallback.buffer);
   2209 
   2210     if (window->wl.egl.window)
   2211         wl_egl_window_destroy(window->wl.egl.window);
   2212 
   2213     if (window->wl.surface)
   2214         wl_surface_destroy(window->wl.surface);
   2215 
   2216     _glfw_free(window->wl.appId);
   2217     _glfw_free(window->wl.outputScales);
   2218 }
   2219 
   2220 void _glfwSetWindowTitleWayland(_GLFWwindow* window, const char* title)
   2221 {
   2222     if (window->wl.libdecor.frame)
   2223         libdecor_frame_set_title(window->wl.libdecor.frame, title);
   2224     else if (window->wl.xdg.toplevel)
   2225         xdg_toplevel_set_title(window->wl.xdg.toplevel, title);
   2226 }
   2227 
   2228 void _glfwSetWindowIconWayland(_GLFWwindow* window,
   2229                                int count, const GLFWimage* images)
   2230 {
   2231     _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
   2232                     "Wayland: The platform does not support setting the window icon");
   2233 }
   2234 
   2235 void _glfwGetWindowPosWayland(_GLFWwindow* window, int* xpos, int* ypos)
   2236 {
   2237     // A Wayland client is not aware of its position, so just warn and leave it
   2238     // as (0, 0)
   2239 
   2240     _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
   2241                     "Wayland: The platform does not provide the window position");
   2242 }
   2243 
   2244 void _glfwSetWindowPosWayland(_GLFWwindow* window, int xpos, int ypos)
   2245 {
   2246     // A Wayland client can not set its position, so just warn
   2247 
   2248     _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
   2249                     "Wayland: The platform does not support setting the window position");
   2250 }
   2251 
   2252 void _glfwGetWindowSizeWayland(_GLFWwindow* window, int* width, int* height)
   2253 {
   2254     if (width)
   2255         *width = window->wl.width;
   2256     if (height)
   2257         *height = window->wl.height;
   2258 }
   2259 
   2260 void _glfwSetWindowSizeWayland(_GLFWwindow* window, int width, int height)
   2261 {
   2262     if (window->monitor)
   2263     {
   2264         // Video mode setting is not available on Wayland
   2265     }
   2266     else
   2267     {
   2268         if (!resizeWindow(window, width, height))
   2269             return;
   2270 
   2271         if (window->wl.libdecor.frame)
   2272         {
   2273             struct libdecor_state* frameState =
   2274                 libdecor_state_new(window->wl.width, window->wl.height);
   2275             libdecor_frame_commit(window->wl.libdecor.frame, frameState, NULL);
   2276             libdecor_state_free(frameState);
   2277         }
   2278 
   2279         if (window->wl.visible)
   2280             _glfwInputWindowDamage(window);
   2281     }
   2282 }
   2283 
   2284 void _glfwSetWindowSizeLimitsWayland(_GLFWwindow* window,
   2285                                      int minwidth, int minheight,
   2286                                      int maxwidth, int maxheight)
   2287 {
   2288     if (window->wl.libdecor.frame)
   2289     {
   2290         if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE)
   2291             minwidth = minheight = 0;
   2292 
   2293         if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)
   2294             maxwidth = maxheight = 0;
   2295 
   2296         libdecor_frame_set_min_content_size(window->wl.libdecor.frame,
   2297                                             minwidth, minheight);
   2298         libdecor_frame_set_max_content_size(window->wl.libdecor.frame,
   2299                                             maxwidth, maxheight);
   2300     }
   2301     else if (window->wl.xdg.toplevel)
   2302         updateXdgSizeLimits(window);
   2303 }
   2304 
   2305 void _glfwSetWindowAspectRatioWayland(_GLFWwindow* window, int numer, int denom)
   2306 {
   2307     if (window->wl.maximized || window->wl.fullscreen)
   2308         return;
   2309 
   2310     int width = window->wl.width, height = window->wl.height;
   2311 
   2312     if (numer != GLFW_DONT_CARE && denom != GLFW_DONT_CARE)
   2313     {
   2314         const float aspectRatio = (float) width / (float) height;
   2315         const float targetRatio = (float) numer / (float) denom;
   2316         if (aspectRatio < targetRatio)
   2317             height /= targetRatio;
   2318         else if (aspectRatio > targetRatio)
   2319             width *= targetRatio;
   2320     }
   2321 
   2322     if (resizeWindow(window, width, height))
   2323     {
   2324         if (window->wl.libdecor.frame)
   2325         {
   2326             struct libdecor_state* frameState =
   2327                 libdecor_state_new(window->wl.width, window->wl.height);
   2328             libdecor_frame_commit(window->wl.libdecor.frame, frameState, NULL);
   2329             libdecor_state_free(frameState);
   2330         }
   2331 
   2332         _glfwInputWindowSize(window, window->wl.width, window->wl.height);
   2333 
   2334         if (window->wl.visible)
   2335             _glfwInputWindowDamage(window);
   2336     }
   2337 }
   2338 
   2339 void _glfwGetFramebufferSizeWayland(_GLFWwindow* window, int* width, int* height)
   2340 {
   2341     if (width)
   2342         *width = window->wl.fbWidth;
   2343     if (height)
   2344         *height = window->wl.fbHeight;
   2345 }
   2346 
   2347 void _glfwGetWindowFrameSizeWayland(_GLFWwindow* window,
   2348                                     int* left, int* top,
   2349                                     int* right, int* bottom)
   2350 {
   2351     if (window->wl.fallback.decorations)
   2352     {
   2353         if (top)
   2354             *top = GLFW_CAPTION_HEIGHT;
   2355         if (left)
   2356             *left = GLFW_BORDER_SIZE;
   2357         if (right)
   2358             *right = GLFW_BORDER_SIZE;
   2359         if (bottom)
   2360             *bottom = GLFW_BORDER_SIZE;
   2361     }
   2362 }
   2363 
   2364 void _glfwGetWindowContentScaleWayland(_GLFWwindow* window,
   2365                                        float* xscale, float* yscale)
   2366 {
   2367     if (window->wl.fractionalScale)
   2368     {
   2369         if (xscale)
   2370             *xscale = (float) window->wl.scalingNumerator / 120.f;
   2371         if (yscale)
   2372             *yscale = (float) window->wl.scalingNumerator / 120.f;
   2373     }
   2374     else
   2375     {
   2376         if (xscale)
   2377             *xscale = (float) window->wl.bufferScale;
   2378         if (yscale)
   2379             *yscale = (float) window->wl.bufferScale;
   2380     }
   2381 }
   2382 
   2383 void _glfwIconifyWindowWayland(_GLFWwindow* window)
   2384 {
   2385     if (window->wl.libdecor.frame)
   2386         libdecor_frame_set_minimized(window->wl.libdecor.frame);
   2387     else if (window->wl.xdg.toplevel)
   2388         xdg_toplevel_set_minimized(window->wl.xdg.toplevel);
   2389 }
   2390 
   2391 void _glfwRestoreWindowWayland(_GLFWwindow* window)
   2392 {
   2393     if (window->monitor)
   2394     {
   2395         // There is no way to unset minimized, or even to know if we are
   2396         // minimized, so there is nothing to do in this case.
   2397     }
   2398     else
   2399     {
   2400         // We assume we are not minimized and act only on maximization
   2401 
   2402         if (window->wl.maximized)
   2403         {
   2404             if (window->wl.libdecor.frame)
   2405                 libdecor_frame_unset_maximized(window->wl.libdecor.frame);
   2406             else if (window->wl.xdg.toplevel)
   2407                 xdg_toplevel_unset_maximized(window->wl.xdg.toplevel);
   2408             else
   2409                 window->wl.maximized = GLFW_FALSE;
   2410         }
   2411     }
   2412 }
   2413 
   2414 void _glfwMaximizeWindowWayland(_GLFWwindow* window)
   2415 {
   2416     if (window->wl.libdecor.frame)
   2417         libdecor_frame_set_maximized(window->wl.libdecor.frame);
   2418     else if (window->wl.xdg.toplevel)
   2419         xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
   2420     else
   2421         window->wl.maximized = GLFW_TRUE;
   2422 }
   2423 
   2424 void _glfwShowWindowWayland(_GLFWwindow* window)
   2425 {
   2426     if (!window->wl.libdecor.frame && !window->wl.xdg.toplevel)
   2427     {
   2428         // NOTE: The XDG surface and role are created here so command-line applications
   2429         //       with off-screen windows do not appear in for example the Unity dock
   2430         createShellObjects(window);
   2431     }
   2432 }
   2433 
   2434 void _glfwHideWindowWayland(_GLFWwindow* window)
   2435 {
   2436     if (window->wl.visible)
   2437     {
   2438         window->wl.visible = GLFW_FALSE;
   2439         destroyShellObjects(window);
   2440 
   2441         wl_surface_attach(window->wl.surface, NULL, 0, 0);
   2442         wl_surface_commit(window->wl.surface);
   2443     }
   2444 }
   2445 
   2446 void _glfwRequestWindowAttentionWayland(_GLFWwindow* window)
   2447 {
   2448     if (!_glfw.wl.activationManager)
   2449         return;
   2450 
   2451     // We're about to overwrite this with a new request
   2452     if (window->wl.activationToken)
   2453         xdg_activation_token_v1_destroy(window->wl.activationToken);
   2454 
   2455     window->wl.activationToken =
   2456         xdg_activation_v1_get_activation_token(_glfw.wl.activationManager);
   2457     xdg_activation_token_v1_add_listener(window->wl.activationToken,
   2458                                          &xdgActivationListener,
   2459                                          window);
   2460 
   2461     xdg_activation_token_v1_commit(window->wl.activationToken);
   2462 }
   2463 
   2464 void _glfwFocusWindowWayland(_GLFWwindow* window)
   2465 {
   2466     if (!_glfw.wl.activationManager)
   2467         return;
   2468 
   2469     if (window->wl.activationToken)
   2470         xdg_activation_token_v1_destroy(window->wl.activationToken);
   2471 
   2472     window->wl.activationToken =
   2473         xdg_activation_v1_get_activation_token(_glfw.wl.activationManager);
   2474     xdg_activation_token_v1_add_listener(window->wl.activationToken,
   2475                                          &xdgActivationListener,
   2476                                          window);
   2477 
   2478     xdg_activation_token_v1_set_serial(window->wl.activationToken,
   2479                                        _glfw.wl.serial,
   2480                                        _glfw.wl.seat);
   2481 
   2482     _GLFWwindow* requester = _glfw.wl.keyboardFocus;
   2483     if (requester)
   2484     {
   2485         xdg_activation_token_v1_set_surface(window->wl.activationToken,
   2486                                             requester->wl.surface);
   2487 
   2488         if (requester->wl.appId)
   2489         {
   2490             xdg_activation_token_v1_set_app_id(window->wl.activationToken,
   2491                                                requester->wl.appId);
   2492         }
   2493     }
   2494 
   2495     xdg_activation_token_v1_commit(window->wl.activationToken);
   2496 }
   2497 
   2498 void _glfwSetWindowMonitorWayland(_GLFWwindow* window,
   2499                                   _GLFWmonitor* monitor,
   2500                                   int xpos, int ypos,
   2501                                   int width, int height,
   2502                                   int refreshRate)
   2503 {
   2504     if (window->monitor == monitor)
   2505     {
   2506         if (!monitor)
   2507             _glfwSetWindowSizeWayland(window, width, height);
   2508 
   2509         return;
   2510     }
   2511 
   2512     if (window->monitor)
   2513         releaseMonitorWayland(window);
   2514 
   2515     _glfwInputWindowMonitor(window, monitor);
   2516 
   2517     if (window->monitor)
   2518         acquireMonitorWayland(window);
   2519     else
   2520         _glfwSetWindowSizeWayland(window, width, height);
   2521 }
   2522 
   2523 GLFWbool _glfwWindowFocusedWayland(_GLFWwindow* window)
   2524 {
   2525     return _glfw.wl.keyboardFocus == window;
   2526 }
   2527 
   2528 GLFWbool _glfwWindowIconifiedWayland(_GLFWwindow* window)
   2529 {
   2530     // xdg-shell doesn’t give any way to request whether a surface is
   2531     // iconified.
   2532     return GLFW_FALSE;
   2533 }
   2534 
   2535 GLFWbool _glfwWindowVisibleWayland(_GLFWwindow* window)
   2536 {
   2537     return window->wl.visible;
   2538 }
   2539 
   2540 GLFWbool _glfwWindowMaximizedWayland(_GLFWwindow* window)
   2541 {
   2542     return window->wl.maximized;
   2543 }
   2544 
   2545 GLFWbool _glfwWindowHoveredWayland(_GLFWwindow* window)
   2546 {
   2547     return window->wl.hovered;
   2548 }
   2549 
   2550 GLFWbool _glfwFramebufferTransparentWayland(_GLFWwindow* window)
   2551 {
   2552     return window->wl.transparent;
   2553 }
   2554 
   2555 void _glfwSetWindowResizableWayland(_GLFWwindow* window, GLFWbool enabled)
   2556 {
   2557     if (window->wl.libdecor.frame)
   2558     {
   2559         if (enabled)
   2560         {
   2561             libdecor_frame_set_capabilities(window->wl.libdecor.frame,
   2562                                             LIBDECOR_ACTION_RESIZE);
   2563         }
   2564         else
   2565         {
   2566             libdecor_frame_unset_capabilities(window->wl.libdecor.frame,
   2567                                               LIBDECOR_ACTION_RESIZE);
   2568         }
   2569     }
   2570     else if (window->wl.xdg.toplevel)
   2571         updateXdgSizeLimits(window);
   2572 }
   2573 
   2574 void _glfwSetWindowDecoratedWayland(_GLFWwindow* window, GLFWbool enabled)
   2575 {
   2576     if (window->wl.libdecor.frame)
   2577     {
   2578         libdecor_frame_set_visibility(window->wl.libdecor.frame, enabled);
   2579     }
   2580     else if (window->wl.xdg.decoration)
   2581     {
   2582         uint32_t mode;
   2583 
   2584         if (enabled)
   2585             mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE;
   2586         else
   2587             mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
   2588 
   2589         zxdg_toplevel_decoration_v1_set_mode(window->wl.xdg.decoration, mode);
   2590     }
   2591     else if (window->wl.xdg.toplevel)
   2592     {
   2593         if (enabled)
   2594             createFallbackDecorations(window);
   2595         else
   2596             destroyFallbackDecorations(window);
   2597     }
   2598 }
   2599 
   2600 void _glfwSetWindowFloatingWayland(_GLFWwindow* window, GLFWbool enabled)
   2601 {
   2602     _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
   2603                     "Wayland: Platform does not support making a window floating");
   2604 }
   2605 
   2606 void _glfwSetWindowMousePassthroughWayland(_GLFWwindow* window, GLFWbool enabled)
   2607 {
   2608     if (enabled)
   2609     {
   2610         struct wl_region* region = wl_compositor_create_region(_glfw.wl.compositor);
   2611         wl_surface_set_input_region(window->wl.surface, region);
   2612         wl_region_destroy(region);
   2613     }
   2614     else
   2615         wl_surface_set_input_region(window->wl.surface, NULL);
   2616 }
   2617 
   2618 float _glfwGetWindowOpacityWayland(_GLFWwindow* window)
   2619 {
   2620     return 1.f;
   2621 }
   2622 
   2623 void _glfwSetWindowOpacityWayland(_GLFWwindow* window, float opacity)
   2624 {
   2625     _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
   2626                     "Wayland: The platform does not support setting the window opacity");
   2627 }
   2628 
   2629 void _glfwSetRawMouseMotionWayland(_GLFWwindow* window, GLFWbool enabled)
   2630 {
   2631     // This is handled in relativePointerHandleRelativeMotion
   2632 }
   2633 
   2634 GLFWbool _glfwRawMouseMotionSupportedWayland(void)
   2635 {
   2636     return GLFW_TRUE;
   2637 }
   2638 
   2639 void _glfwPollEventsWayland(void)
   2640 {
   2641     double timeout = 0.0;
   2642     handleEvents(&timeout);
   2643 }
   2644 
   2645 void _glfwWaitEventsWayland(void)
   2646 {
   2647     handleEvents(NULL);
   2648 }
   2649 
   2650 void _glfwWaitEventsTimeoutWayland(double timeout)
   2651 {
   2652     handleEvents(&timeout);
   2653 }
   2654 
   2655 void _glfwPostEmptyEventWayland(void)
   2656 {
   2657     wl_display_sync(_glfw.wl.display);
   2658     flushDisplay();
   2659 }
   2660 
   2661 void _glfwGetCursorPosWayland(_GLFWwindow* window, double* xpos, double* ypos)
   2662 {
   2663     if (xpos)
   2664         *xpos = window->wl.cursorPosX;
   2665     if (ypos)
   2666         *ypos = window->wl.cursorPosY;
   2667 }
   2668 
   2669 void _glfwSetCursorPosWayland(_GLFWwindow* window, double x, double y)
   2670 {
   2671     _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
   2672                     "Wayland: The platform does not support setting the cursor position");
   2673 }
   2674 
   2675 void _glfwSetCursorModeWayland(_GLFWwindow* window, int mode)
   2676 {
   2677     _glfwSetCursorWayland(window, window->wl.currentCursor);
   2678 }
   2679 
   2680 const char* _glfwGetScancodeNameWayland(int scancode)
   2681 {
   2682     if (scancode < 0 || scancode > 255)
   2683     {
   2684         _glfwInputError(GLFW_INVALID_VALUE,
   2685                         "Wayland: Invalid scancode %i",
   2686                         scancode);
   2687         return NULL;
   2688     }
   2689 
   2690     const int key = _glfw.wl.keycodes[scancode];
   2691     if (key == GLFW_KEY_UNKNOWN)
   2692         return NULL;
   2693 
   2694     const xkb_keycode_t keycode = scancode + 8;
   2695     const xkb_layout_index_t layout =
   2696         xkb_state_key_get_layout(_glfw.wl.xkb.state, keycode);
   2697     if (layout == XKB_LAYOUT_INVALID)
   2698     {
   2699         _glfwInputError(GLFW_PLATFORM_ERROR,
   2700                         "Wayland: Failed to retrieve layout for key name");
   2701         return NULL;
   2702     }
   2703 
   2704     const xkb_keysym_t* keysyms = NULL;
   2705     xkb_keymap_key_get_syms_by_level(_glfw.wl.xkb.keymap,
   2706                                      keycode,
   2707                                      layout,
   2708                                      0,
   2709                                      &keysyms);
   2710     if (keysyms == NULL)
   2711     {
   2712         _glfwInputError(GLFW_PLATFORM_ERROR,
   2713                         "Wayland: Failed to retrieve keysym for key name");
   2714         return NULL;
   2715     }
   2716 
   2717     const uint32_t codepoint = _glfwKeySym2Unicode(keysyms[0]);
   2718     if (codepoint == GLFW_INVALID_CODEPOINT)
   2719     {
   2720         _glfwInputError(GLFW_PLATFORM_ERROR,
   2721                         "Wayland: Failed to retrieve codepoint for key name");
   2722         return NULL;
   2723     }
   2724 
   2725     const size_t count = _glfwEncodeUTF8(_glfw.wl.keynames[key],  codepoint);
   2726     if (count == 0)
   2727     {
   2728         _glfwInputError(GLFW_PLATFORM_ERROR,
   2729                         "Wayland: Failed to encode codepoint for key name");
   2730         return NULL;
   2731     }
   2732 
   2733     _glfw.wl.keynames[key][count] = '\0';
   2734     return _glfw.wl.keynames[key];
   2735 }
   2736 
   2737 int _glfwGetKeyScancodeWayland(int key)
   2738 {
   2739     return _glfw.wl.scancodes[key];
   2740 }
   2741 
   2742 GLFWbool _glfwCreateCursorWayland(_GLFWcursor* cursor,
   2743                                   const GLFWimage* image,
   2744                                   int xhot, int yhot)
   2745 {
   2746     cursor->wl.buffer = createShmBuffer(image);
   2747     if (!cursor->wl.buffer)
   2748         return GLFW_FALSE;
   2749 
   2750     cursor->wl.width = image->width;
   2751     cursor->wl.height = image->height;
   2752     cursor->wl.xhot = xhot;
   2753     cursor->wl.yhot = yhot;
   2754     return GLFW_TRUE;
   2755 }
   2756 
   2757 GLFWbool _glfwCreateStandardCursorWayland(_GLFWcursor* cursor, int shape)
   2758 {
   2759     const char* name = NULL;
   2760 
   2761     // Try the XDG names first
   2762     switch (shape)
   2763     {
   2764         case GLFW_ARROW_CURSOR:
   2765             name = "default";
   2766             break;
   2767         case GLFW_IBEAM_CURSOR:
   2768             name = "text";
   2769             break;
   2770         case GLFW_CROSSHAIR_CURSOR:
   2771             name = "crosshair";
   2772             break;
   2773         case GLFW_POINTING_HAND_CURSOR:
   2774             name = "pointer";
   2775             break;
   2776         case GLFW_RESIZE_EW_CURSOR:
   2777             name = "ew-resize";
   2778             break;
   2779         case GLFW_RESIZE_NS_CURSOR:
   2780             name = "ns-resize";
   2781             break;
   2782         case GLFW_RESIZE_NWSE_CURSOR:
   2783             name = "nwse-resize";
   2784             break;
   2785         case GLFW_RESIZE_NESW_CURSOR:
   2786             name = "nesw-resize";
   2787             break;
   2788         case GLFW_RESIZE_ALL_CURSOR:
   2789             name = "all-scroll";
   2790             break;
   2791         case GLFW_NOT_ALLOWED_CURSOR:
   2792             name = "not-allowed";
   2793             break;
   2794     }
   2795 
   2796     cursor->wl.cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, name);
   2797 
   2798     if (_glfw.wl.cursorThemeHiDPI)
   2799     {
   2800         cursor->wl.cursorHiDPI =
   2801             wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, name);
   2802     }
   2803 
   2804     if (!cursor->wl.cursor)
   2805     {
   2806         // Fall back to the core X11 names
   2807         switch (shape)
   2808         {
   2809             case GLFW_ARROW_CURSOR:
   2810                 name = "left_ptr";
   2811                 break;
   2812             case GLFW_IBEAM_CURSOR:
   2813                 name = "xterm";
   2814                 break;
   2815             case GLFW_CROSSHAIR_CURSOR:
   2816                 name = "crosshair";
   2817                 break;
   2818             case GLFW_POINTING_HAND_CURSOR:
   2819                 name = "hand2";
   2820                 break;
   2821             case GLFW_RESIZE_EW_CURSOR:
   2822                 name = "sb_h_double_arrow";
   2823                 break;
   2824             case GLFW_RESIZE_NS_CURSOR:
   2825                 name = "sb_v_double_arrow";
   2826                 break;
   2827             case GLFW_RESIZE_ALL_CURSOR:
   2828                 name = "fleur";
   2829                 break;
   2830             default:
   2831                 _glfwInputError(GLFW_CURSOR_UNAVAILABLE,
   2832                                 "Wayland: Standard cursor shape unavailable");
   2833                 return GLFW_FALSE;
   2834         }
   2835 
   2836         cursor->wl.cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, name);
   2837         if (!cursor->wl.cursor)
   2838         {
   2839             _glfwInputError(GLFW_CURSOR_UNAVAILABLE,
   2840                             "Wayland: Failed to create standard cursor \"%s\"",
   2841                             name);
   2842             return GLFW_FALSE;
   2843         }
   2844 
   2845         if (_glfw.wl.cursorThemeHiDPI)
   2846         {
   2847             if (!cursor->wl.cursorHiDPI)
   2848             {
   2849                 cursor->wl.cursorHiDPI =
   2850                     wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, name);
   2851             }
   2852         }
   2853     }
   2854 
   2855     return GLFW_TRUE;
   2856 }
   2857 
   2858 void _glfwDestroyCursorWayland(_GLFWcursor* cursor)
   2859 {
   2860     // If it's a standard cursor we don't need to do anything here
   2861     if (cursor->wl.cursor)
   2862         return;
   2863 
   2864     if (cursor->wl.buffer)
   2865         wl_buffer_destroy(cursor->wl.buffer);
   2866 }
   2867 
   2868 static void relativePointerHandleRelativeMotion(void* userData,
   2869                                                 struct zwp_relative_pointer_v1* pointer,
   2870                                                 uint32_t timeHi,
   2871                                                 uint32_t timeLo,
   2872                                                 wl_fixed_t dx,
   2873                                                 wl_fixed_t dy,
   2874                                                 wl_fixed_t dxUnaccel,
   2875                                                 wl_fixed_t dyUnaccel)
   2876 {
   2877     _GLFWwindow* window = userData;
   2878     double xpos = window->virtualCursorPosX;
   2879     double ypos = window->virtualCursorPosY;
   2880 
   2881     if (window->cursorMode != GLFW_CURSOR_DISABLED)
   2882         return;
   2883 
   2884     if (window->rawMouseMotion)
   2885     {
   2886         xpos += wl_fixed_to_double(dxUnaccel);
   2887         ypos += wl_fixed_to_double(dyUnaccel);
   2888     }
   2889     else
   2890     {
   2891         xpos += wl_fixed_to_double(dx);
   2892         ypos += wl_fixed_to_double(dy);
   2893     }
   2894 
   2895     _glfwInputCursorPos(window, xpos, ypos);
   2896 }
   2897 
   2898 static const struct zwp_relative_pointer_v1_listener relativePointerListener =
   2899 {
   2900     relativePointerHandleRelativeMotion
   2901 };
   2902 
   2903 static void lockedPointerHandleLocked(void* userData,
   2904                                       struct zwp_locked_pointer_v1* lockedPointer)
   2905 {
   2906 }
   2907 
   2908 static void lockedPointerHandleUnlocked(void* userData,
   2909                                         struct zwp_locked_pointer_v1* lockedPointer)
   2910 {
   2911 }
   2912 
   2913 static const struct zwp_locked_pointer_v1_listener lockedPointerListener =
   2914 {
   2915     lockedPointerHandleLocked,
   2916     lockedPointerHandleUnlocked
   2917 };
   2918 
   2919 static void lockPointer(_GLFWwindow* window)
   2920 {
   2921     if (!_glfw.wl.relativePointerManager)
   2922     {
   2923         _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
   2924                         "Wayland: The compositor does not support pointer locking");
   2925         return;
   2926     }
   2927 
   2928     window->wl.relativePointer =
   2929         zwp_relative_pointer_manager_v1_get_relative_pointer(
   2930             _glfw.wl.relativePointerManager,
   2931             _glfw.wl.pointer);
   2932     zwp_relative_pointer_v1_add_listener(window->wl.relativePointer,
   2933                                          &relativePointerListener,
   2934                                          window);
   2935 
   2936     window->wl.lockedPointer =
   2937         zwp_pointer_constraints_v1_lock_pointer(
   2938             _glfw.wl.pointerConstraints,
   2939             window->wl.surface,
   2940             _glfw.wl.pointer,
   2941             NULL,
   2942             ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
   2943     zwp_locked_pointer_v1_add_listener(window->wl.lockedPointer,
   2944                                        &lockedPointerListener,
   2945                                        window);
   2946 }
   2947 
   2948 static void unlockPointer(_GLFWwindow* window)
   2949 {
   2950     zwp_relative_pointer_v1_destroy(window->wl.relativePointer);
   2951     window->wl.relativePointer = NULL;
   2952 
   2953     zwp_locked_pointer_v1_destroy(window->wl.lockedPointer);
   2954     window->wl.lockedPointer = NULL;
   2955 }
   2956 
   2957 static void confinedPointerHandleConfined(void* userData,
   2958                                           struct zwp_confined_pointer_v1* confinedPointer)
   2959 {
   2960 }
   2961 
   2962 static void confinedPointerHandleUnconfined(void* userData,
   2963                                             struct zwp_confined_pointer_v1* confinedPointer)
   2964 {
   2965 }
   2966 
   2967 static const struct zwp_confined_pointer_v1_listener confinedPointerListener =
   2968 {
   2969     confinedPointerHandleConfined,
   2970     confinedPointerHandleUnconfined
   2971 };
   2972 
   2973 static void confinePointer(_GLFWwindow* window)
   2974 {
   2975     window->wl.confinedPointer =
   2976         zwp_pointer_constraints_v1_confine_pointer(
   2977             _glfw.wl.pointerConstraints,
   2978             window->wl.surface,
   2979             _glfw.wl.pointer,
   2980             NULL,
   2981             ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
   2982 
   2983     zwp_confined_pointer_v1_add_listener(window->wl.confinedPointer,
   2984                                          &confinedPointerListener,
   2985                                          window);
   2986 }
   2987 
   2988 static void unconfinePointer(_GLFWwindow* window)
   2989 {
   2990     zwp_confined_pointer_v1_destroy(window->wl.confinedPointer);
   2991     window->wl.confinedPointer = NULL;
   2992 }
   2993 
   2994 void _glfwSetCursorWayland(_GLFWwindow* window, _GLFWcursor* cursor)
   2995 {
   2996     if (!_glfw.wl.pointer)
   2997         return;
   2998 
   2999     window->wl.currentCursor = cursor;
   3000 
   3001     // If we're not in the correct window just save the cursor
   3002     // the next time the pointer enters the window the cursor will change
   3003     if (!window->wl.hovered)
   3004         return;
   3005 
   3006     // Update pointer lock to match cursor mode
   3007     if (window->cursorMode == GLFW_CURSOR_DISABLED)
   3008     {
   3009         if (window->wl.confinedPointer)
   3010             unconfinePointer(window);
   3011         if (!window->wl.lockedPointer)
   3012             lockPointer(window);
   3013     }
   3014     else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
   3015     {
   3016         if (window->wl.lockedPointer)
   3017             unlockPointer(window);
   3018         if (!window->wl.confinedPointer)
   3019             confinePointer(window);
   3020     }
   3021     else if (window->cursorMode == GLFW_CURSOR_NORMAL ||
   3022              window->cursorMode == GLFW_CURSOR_HIDDEN)
   3023     {
   3024         if (window->wl.lockedPointer)
   3025             unlockPointer(window);
   3026         else if (window->wl.confinedPointer)
   3027             unconfinePointer(window);
   3028     }
   3029 
   3030     if (window->cursorMode == GLFW_CURSOR_NORMAL ||
   3031         window->cursorMode == GLFW_CURSOR_CAPTURED)
   3032     {
   3033         if (cursor)
   3034             setCursorImage(window, &cursor->wl);
   3035         else
   3036         {
   3037             struct wl_cursor* defaultCursor =
   3038                 wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, "left_ptr");
   3039             if (!defaultCursor)
   3040             {
   3041                 _glfwInputError(GLFW_PLATFORM_ERROR,
   3042                                 "Wayland: Standard cursor not found");
   3043                 return;
   3044             }
   3045 
   3046             struct wl_cursor* defaultCursorHiDPI = NULL;
   3047             if (_glfw.wl.cursorThemeHiDPI)
   3048             {
   3049                 defaultCursorHiDPI =
   3050                     wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, "left_ptr");
   3051             }
   3052 
   3053             _GLFWcursorWayland cursorWayland =
   3054             {
   3055                 defaultCursor,
   3056                 defaultCursorHiDPI,
   3057                 NULL,
   3058                 0, 0,
   3059                 0, 0,
   3060                 0
   3061             };
   3062 
   3063             setCursorImage(window, &cursorWayland);
   3064         }
   3065     }
   3066     else if (window->cursorMode == GLFW_CURSOR_HIDDEN ||
   3067              window->cursorMode == GLFW_CURSOR_DISABLED)
   3068     {
   3069         wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial, NULL, 0, 0);
   3070     }
   3071 }
   3072 
   3073 static void dataSourceHandleTarget(void* userData,
   3074                                    struct wl_data_source* source,
   3075                                    const char* mimeType)
   3076 {
   3077     if (_glfw.wl.selectionSource != source)
   3078     {
   3079         _glfwInputError(GLFW_PLATFORM_ERROR,
   3080                         "Wayland: Unknown clipboard data source");
   3081         return;
   3082     }
   3083 }
   3084 
   3085 static void dataSourceHandleSend(void* userData,
   3086                                  struct wl_data_source* source,
   3087                                  const char* mimeType,
   3088                                  int fd)
   3089 {
   3090     // Ignore it if this is an outdated or invalid request
   3091     if (_glfw.wl.selectionSource != source ||
   3092         strcmp(mimeType, "text/plain;charset=utf-8") != 0)
   3093     {
   3094         close(fd);
   3095         return;
   3096     }
   3097 
   3098     char* string = _glfw.wl.clipboardString;
   3099     size_t length = strlen(string);
   3100 
   3101     while (length > 0)
   3102     {
   3103         const ssize_t result = write(fd, string, length);
   3104         if (result == -1)
   3105         {
   3106             if (errno == EINTR)
   3107                 continue;
   3108 
   3109             _glfwInputError(GLFW_PLATFORM_ERROR,
   3110                             "Wayland: Error while writing the clipboard: %s",
   3111                             strerror(errno));
   3112             break;
   3113         }
   3114 
   3115         length -= result;
   3116         string += result;
   3117     }
   3118 
   3119     close(fd);
   3120 }
   3121 
   3122 static void dataSourceHandleCancelled(void* userData,
   3123                                       struct wl_data_source* source)
   3124 {
   3125     wl_data_source_destroy(source);
   3126 
   3127     if (_glfw.wl.selectionSource != source)
   3128         return;
   3129 
   3130     _glfw.wl.selectionSource = NULL;
   3131 }
   3132 
   3133 static const struct wl_data_source_listener dataSourceListener =
   3134 {
   3135     dataSourceHandleTarget,
   3136     dataSourceHandleSend,
   3137     dataSourceHandleCancelled,
   3138 };
   3139 
   3140 void _glfwSetClipboardStringWayland(const char* string)
   3141 {
   3142     if (_glfw.wl.selectionSource)
   3143     {
   3144         wl_data_source_destroy(_glfw.wl.selectionSource);
   3145         _glfw.wl.selectionSource = NULL;
   3146     }
   3147 
   3148     char* copy = _glfw_strdup(string);
   3149     if (!copy)
   3150     {
   3151         _glfwInputError(GLFW_OUT_OF_MEMORY, NULL);
   3152         return;
   3153     }
   3154 
   3155     _glfw_free(_glfw.wl.clipboardString);
   3156     _glfw.wl.clipboardString = copy;
   3157 
   3158     _glfw.wl.selectionSource =
   3159         wl_data_device_manager_create_data_source(_glfw.wl.dataDeviceManager);
   3160     if (!_glfw.wl.selectionSource)
   3161     {
   3162         _glfwInputError(GLFW_PLATFORM_ERROR,
   3163                         "Wayland: Failed to create clipboard data source");
   3164         return;
   3165     }
   3166     wl_data_source_add_listener(_glfw.wl.selectionSource,
   3167                                 &dataSourceListener,
   3168                                 NULL);
   3169     wl_data_source_offer(_glfw.wl.selectionSource, "text/plain;charset=utf-8");
   3170     wl_data_device_set_selection(_glfw.wl.dataDevice,
   3171                                  _glfw.wl.selectionSource,
   3172                                  _glfw.wl.serial);
   3173 }
   3174 
   3175 const char* _glfwGetClipboardStringWayland(void)
   3176 {
   3177     if (!_glfw.wl.selectionOffer)
   3178     {
   3179         _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
   3180                         "Wayland: No clipboard data available");
   3181         return NULL;
   3182     }
   3183 
   3184     if (_glfw.wl.selectionSource)
   3185         return _glfw.wl.clipboardString;
   3186 
   3187     _glfw_free(_glfw.wl.clipboardString);
   3188     _glfw.wl.clipboardString =
   3189         readDataOfferAsString(_glfw.wl.selectionOffer, "text/plain;charset=utf-8");
   3190     return _glfw.wl.clipboardString;
   3191 }
   3192 
   3193 EGLenum _glfwGetEGLPlatformWayland(EGLint** attribs)
   3194 {
   3195     if (_glfw.egl.EXT_platform_base && _glfw.egl.EXT_platform_wayland)
   3196         return EGL_PLATFORM_WAYLAND_EXT;
   3197     else
   3198         return 0;
   3199 }
   3200 
   3201 EGLNativeDisplayType _glfwGetEGLNativeDisplayWayland(void)
   3202 {
   3203     return _glfw.wl.display;
   3204 }
   3205 
   3206 EGLNativeWindowType _glfwGetEGLNativeWindowWayland(_GLFWwindow* window)
   3207 {
   3208     return window->wl.egl.window;
   3209 }
   3210 
   3211 void _glfwGetRequiredInstanceExtensionsWayland(char** extensions)
   3212 {
   3213     if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_wayland_surface)
   3214         return;
   3215 
   3216     extensions[0] = "VK_KHR_surface";
   3217     extensions[1] = "VK_KHR_wayland_surface";
   3218 }
   3219 
   3220 GLFWbool _glfwGetPhysicalDevicePresentationSupportWayland(VkInstance instance,
   3221                                                           VkPhysicalDevice device,
   3222                                                           uint32_t queuefamily)
   3223 {
   3224     PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
   3225         vkGetPhysicalDeviceWaylandPresentationSupportKHR =
   3226         (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)
   3227         vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR");
   3228     if (!vkGetPhysicalDeviceWaylandPresentationSupportKHR)
   3229     {
   3230         _glfwInputError(GLFW_API_UNAVAILABLE,
   3231                         "Wayland: Vulkan instance missing VK_KHR_wayland_surface extension");
   3232         return VK_NULL_HANDLE;
   3233     }
   3234 
   3235     return vkGetPhysicalDeviceWaylandPresentationSupportKHR(device,
   3236                                                             queuefamily,
   3237                                                             _glfw.wl.display);
   3238 }
   3239 
   3240 VkResult _glfwCreateWindowSurfaceWayland(VkInstance instance,
   3241                                          _GLFWwindow* window,
   3242                                          const VkAllocationCallbacks* allocator,
   3243                                          VkSurfaceKHR* surface)
   3244 {
   3245     VkResult err;
   3246     VkWaylandSurfaceCreateInfoKHR sci;
   3247     PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR;
   3248 
   3249     vkCreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR)
   3250         vkGetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR");
   3251     if (!vkCreateWaylandSurfaceKHR)
   3252     {
   3253         _glfwInputError(GLFW_API_UNAVAILABLE,
   3254                         "Wayland: Vulkan instance missing VK_KHR_wayland_surface extension");
   3255         return VK_ERROR_EXTENSION_NOT_PRESENT;
   3256     }
   3257 
   3258     memset(&sci, 0, sizeof(sci));
   3259     sci.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
   3260     sci.display = _glfw.wl.display;
   3261     sci.surface = window->wl.surface;
   3262 
   3263     err = vkCreateWaylandSurfaceKHR(instance, &sci, allocator, surface);
   3264     if (err)
   3265     {
   3266         _glfwInputError(GLFW_PLATFORM_ERROR,
   3267                         "Wayland: Failed to create Vulkan surface: %s",
   3268                         _glfwGetVulkanResultString(err));
   3269     }
   3270 
   3271     return err;
   3272 }
   3273 
   3274 
   3275 //////////////////////////////////////////////////////////////////////////
   3276 //////                        GLFW native API                       //////
   3277 //////////////////////////////////////////////////////////////////////////
   3278 
   3279 GLFWAPI struct wl_display* glfwGetWaylandDisplay(void)
   3280 {
   3281     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
   3282 
   3283     if (_glfw.platform.platformID != GLFW_PLATFORM_WAYLAND)
   3284     {
   3285         _glfwInputError(GLFW_PLATFORM_UNAVAILABLE,
   3286                         "Wayland: Platform not initialized");
   3287         return NULL;
   3288     }
   3289 
   3290     return _glfw.wl.display;
   3291 }
   3292 
   3293 GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* handle)
   3294 {
   3295     _GLFWwindow* window = (_GLFWwindow*) handle;
   3296     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
   3297 
   3298     if (_glfw.platform.platformID != GLFW_PLATFORM_WAYLAND)
   3299     {
   3300         _glfwInputError(GLFW_PLATFORM_UNAVAILABLE,
   3301                         "Wayland: Platform not initialized");
   3302         return NULL;
   3303     }
   3304 
   3305     return window->wl.surface;
   3306 }
   3307 
   3308 #endif // _GLFW_WAYLAND
   3309