medfall

A super great game engine
Log | Files | Refs

wl_window.cc (32545B)


      1 //========================================================================
      2 // GLFW 3.3 Wayland - www.glfw.org
      3 //------------------------------------------------------------------------
      4 // Copyright (c) 2014 Jonas Ã…dahl <jadahl@gmail.com>
      5 //
      6 // This software is provided 'as-is', without any express or implied
      7 // warranty. In no event will the authors be held liable for any damages
      8 // arising from the use of this software.
      9 //
     10 // Permission is granted to anyone to use this software for any purpose,
     11 // including commercial applications, and to alter it and redistribute it
     12 // freely, subject to the following restrictions:
     13 //
     14 // 1. The origin of this software must not be misrepresented; you must not
     15 //    claim that you wrote the original software. If you use this software
     16 //    in a product, an acknowledgment in the product documentation would
     17 //    be appreciated but is not required.
     18 //
     19 // 2. Altered source versions must be plainly marked as such, and must not
     20 //    be misrepresented as being the original software.
     21 //
     22 // 3. This notice may not be removed or altered from any source
     23 //    distribution.
     24 //
     25 //========================================================================
     26 
     27 #define _GNU_SOURCE
     28 
     29 #include "internal.h"
     30 
     31 #include <stdio.h>
     32 #include <stdlib.h>
     33 #include <errno.h>
     34 #include <unistd.h>
     35 #include <string.h>
     36 #include <fcntl.h>
     37 #include <sys/mman.h>
     38 #include <poll.h>
     39 
     40 #include <wayland-egl.h>
     41 #include <wayland-cursor.h>
     42 
     43 
     44 static void handlePing(void* data,
     45                        struct wl_shell_surface* shellSurface,
     46                        uint32_t serial)
     47 {
     48     wl_shell_surface_pong(shellSurface, serial);
     49 }
     50 
     51 static void handleConfigure(void* data,
     52                             struct wl_shell_surface* shellSurface,
     53                             uint32_t edges,
     54                             int32_t width,
     55                             int32_t height)
     56 {
     57     _GLFWwindow* window = data;
     58     float aspectRatio;
     59     float targetRatio;
     60 
     61     if (!window->monitor)
     62     {
     63         if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)
     64         {
     65             aspectRatio = (float)width / (float)height;
     66             targetRatio = (float)window->numer / (float)window->denom;
     67             if (aspectRatio < targetRatio)
     68                 height = width / targetRatio;
     69             else if (aspectRatio > targetRatio)
     70                 width = height * targetRatio;
     71         }
     72 
     73         if (window->minwidth != GLFW_DONT_CARE && width < window->minwidth)
     74             width = window->minwidth;
     75         else if (window->maxwidth != GLFW_DONT_CARE && width > window->maxwidth)
     76             width = window->maxwidth;
     77 
     78         if (window->minheight != GLFW_DONT_CARE && height < window->minheight)
     79             height = window->minheight;
     80         else if (window->maxheight != GLFW_DONT_CARE && height > window->maxheight)
     81             height = window->maxheight;
     82     }
     83 
     84     _glfwInputWindowSize(window, width, height);
     85     _glfwPlatformSetWindowSize(window, width, height);
     86     _glfwInputWindowDamage(window);
     87 }
     88 
     89 static void handlePopupDone(void* data,
     90                             struct wl_shell_surface* shellSurface)
     91 {
     92 }
     93 
     94 static const struct wl_shell_surface_listener shellSurfaceListener = {
     95     handlePing,
     96     handleConfigure,
     97     handlePopupDone
     98 };
     99 
    100 static void checkScaleChange(_GLFWwindow* window)
    101 {
    102     int scaledWidth, scaledHeight;
    103     int scale = 1;
    104     int i;
    105     int monitorScale;
    106 
    107     // Check if we will be able to set the buffer scale or not.
    108     if (_glfw.wl.compositorVersion < 3)
    109         return;
    110 
    111     // Get the scale factor from the highest scale monitor.
    112     for (i = 0; i < window->wl.monitorsCount; ++i)
    113     {
    114         monitorScale = window->wl.monitors[i]->wl.scale;
    115         if (scale < monitorScale)
    116             scale = monitorScale;
    117     }
    118 
    119     // Only change the framebuffer size if the scale changed.
    120     if (scale != window->wl.scale)
    121     {
    122         window->wl.scale = scale;
    123         scaledWidth = window->wl.width * scale;
    124         scaledHeight = window->wl.height * scale;
    125         wl_surface_set_buffer_scale(window->wl.surface, scale);
    126         wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0);
    127         _glfwInputFramebufferSize(window, scaledWidth, scaledHeight);
    128     }
    129 }
    130 
    131 static void handleEnter(void *data,
    132                         struct wl_surface *surface,
    133                         struct wl_output *output)
    134 {
    135     _GLFWwindow* window = data;
    136     _GLFWmonitor* monitor = wl_output_get_user_data(output);
    137 
    138     if (window->wl.monitorsCount + 1 > window->wl.monitorsSize)
    139     {
    140         ++window->wl.monitorsSize;
    141         window->wl.monitors =
    142             realloc(window->wl.monitors,
    143                     window->wl.monitorsSize * sizeof(_GLFWmonitor*));
    144     }
    145 
    146     window->wl.monitors[window->wl.monitorsCount++] = monitor;
    147 
    148     checkScaleChange(window);
    149 }
    150 
    151 static void handleLeave(void *data,
    152                         struct wl_surface *surface,
    153                         struct wl_output *output)
    154 {
    155     _GLFWwindow* window = data;
    156     _GLFWmonitor* monitor = wl_output_get_user_data(output);
    157     GLFWbool found;
    158     int i;
    159 
    160     for (i = 0, found = GLFW_FALSE; i < window->wl.monitorsCount - 1; ++i)
    161     {
    162         if (monitor == window->wl.monitors[i])
    163             found = GLFW_TRUE;
    164         if (found)
    165             window->wl.monitors[i] = window->wl.monitors[i + 1];
    166     }
    167     window->wl.monitors[--window->wl.monitorsCount] = NULL;
    168 
    169     checkScaleChange(window);
    170 }
    171 
    172 static const struct wl_surface_listener surfaceListener = {
    173     handleEnter,
    174     handleLeave
    175 };
    176 
    177 // Makes the surface considered as XRGB instead of ARGB.
    178 static void setOpaqueRegion(_GLFWwindow* window)
    179 {
    180     struct wl_region* region;
    181 
    182     region = wl_compositor_create_region(_glfw.wl.compositor);
    183     if (!region)
    184         return;
    185 
    186     wl_region_add(region, 0, 0, window->wl.width, window->wl.height);
    187     wl_surface_set_opaque_region(window->wl.surface, region);
    188     wl_surface_commit(window->wl.surface);
    189     wl_region_destroy(region);
    190 }
    191 
    192 static GLFWbool createSurface(_GLFWwindow* window,
    193                               const _GLFWwndconfig* wndconfig)
    194 {
    195     window->wl.surface = wl_compositor_create_surface(_glfw.wl.compositor);
    196     if (!window->wl.surface)
    197         return GLFW_FALSE;
    198 
    199     wl_surface_add_listener(window->wl.surface,
    200                             &surfaceListener,
    201                             window);
    202 
    203     wl_surface_set_user_data(window->wl.surface, window);
    204 
    205     window->wl.native = wl_egl_window_create(window->wl.surface,
    206                                              wndconfig->width,
    207                                              wndconfig->height);
    208     if (!window->wl.native)
    209         return GLFW_FALSE;
    210 
    211     window->wl.width = wndconfig->width;
    212     window->wl.height = wndconfig->height;
    213     window->wl.scale = 1;
    214 
    215     // TODO: make this optional once issue #197 is fixed.
    216     setOpaqueRegion(window);
    217 
    218     return GLFW_TRUE;
    219 }
    220 
    221 static GLFWbool createShellSurface(_GLFWwindow* window)
    222 {
    223     window->wl.shellSurface = wl_shell_get_shell_surface(_glfw.wl.shell,
    224                                                          window->wl.surface);
    225     if (!window->wl.shellSurface)
    226         return GLFW_FALSE;
    227 
    228     wl_shell_surface_add_listener(window->wl.shellSurface,
    229                                   &shellSurfaceListener,
    230                                   window);
    231 
    232     if (window->wl.title)
    233         wl_shell_surface_set_title(window->wl.shellSurface, window->wl.title);
    234 
    235     if (window->monitor)
    236     {
    237         wl_shell_surface_set_fullscreen(
    238             window->wl.shellSurface,
    239             WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
    240             0,
    241             window->monitor->wl.output);
    242     }
    243     else if (window->wl.maximized)
    244     {
    245         wl_shell_surface_set_maximized(window->wl.shellSurface, NULL);
    246     }
    247     else
    248     {
    249         wl_shell_surface_set_toplevel(window->wl.shellSurface);
    250     }
    251 
    252     wl_surface_commit(window->wl.surface);
    253 
    254     return GLFW_TRUE;
    255 }
    256 
    257 static int
    258 createTmpfileCloexec(char* tmpname)
    259 {
    260     int fd;
    261 
    262     fd = mkostemp(tmpname, O_CLOEXEC);
    263     if (fd >= 0)
    264         unlink(tmpname);
    265 
    266     return fd;
    267 }
    268 
    269 static void
    270 handleEvents(int timeout)
    271 {
    272     struct wl_display* display = _glfw.wl.display;
    273     struct pollfd fds[] = {
    274         { wl_display_get_fd(display), POLLIN },
    275     };
    276 
    277     while (wl_display_prepare_read(display) != 0)
    278         wl_display_dispatch_pending(display);
    279 
    280     // If an error different from EAGAIN happens, we have likely been
    281     // disconnected from the Wayland session, try to handle that the best we
    282     // can.
    283     if (wl_display_flush(display) < 0 && errno != EAGAIN)
    284     {
    285         _GLFWwindow* window = _glfw.windowListHead;
    286         while (window)
    287         {
    288             _glfwInputWindowCloseRequest(window);
    289             window = window->next;
    290         }
    291         wl_display_cancel_read(display);
    292         return;
    293     }
    294 
    295     if (poll(fds, 1, timeout) > 0)
    296     {
    297         wl_display_read_events(display);
    298         wl_display_dispatch_pending(display);
    299     }
    300     else
    301     {
    302         wl_display_cancel_read(display);
    303     }
    304 }
    305 
    306 /*
    307  * Create a new, unique, anonymous file of the given size, and
    308  * return the file descriptor for it. The file descriptor is set
    309  * CLOEXEC. The file is immediately suitable for mmap()'ing
    310  * the given size at offset zero.
    311  *
    312  * The file should not have a permanent backing store like a disk,
    313  * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
    314  *
    315  * The file name is deleted from the file system.
    316  *
    317  * The file is suitable for buffer sharing between processes by
    318  * transmitting the file descriptor over Unix sockets using the
    319  * SCM_RIGHTS methods.
    320  *
    321  * posix_fallocate() is used to guarantee that disk space is available
    322  * for the file at the given size. If disk space is insufficent, errno
    323  * is set to ENOSPC. If posix_fallocate() is not supported, program may
    324  * receive SIGBUS on accessing mmap()'ed file contents instead.
    325  */
    326 int
    327 createAnonymousFile(off_t size)
    328 {
    329     static const char template[] = "/glfw-shared-XXXXXX";
    330     const char* path;
    331     char* name;
    332     int fd;
    333     int ret;
    334 
    335     path = getenv("XDG_RUNTIME_DIR");
    336     if (!path)
    337     {
    338         errno = ENOENT;
    339         return -1;
    340     }
    341 
    342     name = calloc(strlen(path) + sizeof(template), 1);
    343     strcpy(name, path);
    344     strcat(name, template);
    345 
    346     fd = createTmpfileCloexec(name);
    347 
    348     free(name);
    349 
    350     if (fd < 0)
    351         return -1;
    352     ret = posix_fallocate(fd, 0, size);
    353     if (ret != 0)
    354     {
    355         close(fd);
    356         errno = ret;
    357         return -1;
    358     }
    359     return fd;
    360 }
    361 
    362 // Translates a GLFW standard cursor to a theme cursor name
    363 //
    364 static char *translateCursorShape(int shape)
    365 {
    366     switch (shape)
    367     {
    368         case GLFW_ARROW_CURSOR:
    369             return "left_ptr";
    370         case GLFW_IBEAM_CURSOR:
    371             return "xterm";
    372         case GLFW_CROSSHAIR_CURSOR:
    373             return "crosshair";
    374         case GLFW_HAND_CURSOR:
    375             return "grabbing";
    376         case GLFW_HRESIZE_CURSOR:
    377             return "sb_h_double_arrow";
    378         case GLFW_VRESIZE_CURSOR:
    379             return "sb_v_double_arrow";
    380     }
    381     return NULL;
    382 }
    383 
    384 //////////////////////////////////////////////////////////////////////////
    385 //////                       GLFW platform API                      //////
    386 //////////////////////////////////////////////////////////////////////////
    387 
    388 int _glfwPlatformCreateWindow(_GLFWwindow* window,
    389                               const _GLFWwndconfig* wndconfig,
    390                               const _GLFWctxconfig* ctxconfig,
    391                               const _GLFWfbconfig* fbconfig)
    392 {
    393     if (!createSurface(window, wndconfig))
    394         return GLFW_FALSE;
    395 
    396     if (ctxconfig->client != GLFW_NO_API)
    397     {
    398         if (ctxconfig->source == GLFW_EGL_CONTEXT_API ||
    399             ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
    400         {
    401             if (!_glfwInitEGL())
    402                 return GLFW_FALSE;
    403             if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
    404                 return GLFW_FALSE;
    405         }
    406         else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
    407         {
    408             if (!_glfwInitOSMesa())
    409                 return GLFW_FALSE;
    410             if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
    411                 return GLFW_FALSE;
    412         }
    413     }
    414 
    415     if (wndconfig->title)
    416         window->wl.title = strdup(wndconfig->title);
    417 
    418     if (wndconfig->visible)
    419     {
    420         if (!createShellSurface(window))
    421             return GLFW_FALSE;
    422 
    423         window->wl.visible = GLFW_TRUE;
    424     }
    425     else
    426     {
    427         window->wl.shellSurface = NULL;
    428         window->wl.visible = GLFW_FALSE;
    429     }
    430 
    431     window->wl.currentCursor = NULL;
    432 
    433     window->wl.monitors = calloc(1, sizeof(_GLFWmonitor*));
    434     window->wl.monitorsCount = 0;
    435     window->wl.monitorsSize = 1;
    436 
    437     return GLFW_TRUE;
    438 }
    439 
    440 void _glfwPlatformDestroyWindow(_GLFWwindow* window)
    441 {
    442     if (window == _glfw.wl.pointerFocus)
    443     {
    444         _glfw.wl.pointerFocus = NULL;
    445         _glfwInputCursorEnter(window, GLFW_FALSE);
    446     }
    447     if (window == _glfw.wl.keyboardFocus)
    448     {
    449         _glfw.wl.keyboardFocus = NULL;
    450         _glfwInputWindowFocus(window, GLFW_FALSE);
    451     }
    452 
    453     if (window->context.destroy)
    454         window->context.destroy(window);
    455 
    456     if (window->wl.native)
    457         wl_egl_window_destroy(window->wl.native);
    458 
    459     if (window->wl.shellSurface)
    460         wl_shell_surface_destroy(window->wl.shellSurface);
    461 
    462     if (window->wl.surface)
    463         wl_surface_destroy(window->wl.surface);
    464 
    465     free(window->wl.title);
    466     free(window->wl.monitors);
    467 }
    468 
    469 void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
    470 {
    471     if (window->wl.title)
    472         free(window->wl.title);
    473     window->wl.title = strdup(title);
    474     if (window->wl.shellSurface)
    475         wl_shell_surface_set_title(window->wl.shellSurface, title);
    476 }
    477 
    478 void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
    479                                 int count, const GLFWimage* images)
    480 {
    481     _glfwInputError(GLFW_PLATFORM_ERROR,
    482                     "Wayland: Setting window icon not supported");
    483 }
    484 
    485 void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
    486 {
    487     // A Wayland client is not aware of its position, so just warn and leave it
    488     // as (0, 0)
    489 
    490     _glfwInputError(GLFW_PLATFORM_ERROR,
    491                     "Wayland: Window position retrieval not supported");
    492 }
    493 
    494 void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
    495 {
    496     // A Wayland client can not set its position, so just warn
    497 
    498     _glfwInputError(GLFW_PLATFORM_ERROR,
    499                     "Wayland: Window position setting not supported");
    500 }
    501 
    502 void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
    503 {
    504     if (width)
    505         *width = window->wl.width;
    506     if (height)
    507         *height = window->wl.height;
    508 }
    509 
    510 void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
    511 {
    512     int scaledWidth = width * window->wl.scale;
    513     int scaledHeight = height * window->wl.scale;
    514     window->wl.width = width;
    515     window->wl.height = height;
    516     wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0);
    517     setOpaqueRegion(window);
    518     _glfwInputFramebufferSize(window, scaledWidth, scaledHeight);
    519 }
    520 
    521 void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
    522                                       int minwidth, int minheight,
    523                                       int maxwidth, int maxheight)
    524 {
    525     // TODO: find out how to trigger a resize.
    526     // The actual limits are checked in the wl_shell_surface::configure handler.
    527 }
    528 
    529 void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
    530 {
    531     // TODO: find out how to trigger a resize.
    532     // The actual limits are checked in the wl_shell_surface::configure handler.
    533 }
    534 
    535 void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
    536 {
    537     _glfwPlatformGetWindowSize(window, width, height);
    538     *width *= window->wl.scale;
    539     *height *= window->wl.scale;
    540 }
    541 
    542 void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
    543                                      int* left, int* top,
    544                                      int* right, int* bottom)
    545 {
    546     // TODO: will need a proper implementation once decorations are
    547     // implemented, but for now just leave everything as 0.
    548 }
    549 
    550 void _glfwPlatformIconifyWindow(_GLFWwindow* window)
    551 {
    552     // TODO: move to xdg_shell instead of wl_shell.
    553     _glfwInputError(GLFW_PLATFORM_ERROR,
    554                     "Wayland: Iconify window not supported");
    555 }
    556 
    557 void _glfwPlatformRestoreWindow(_GLFWwindow* window)
    558 {
    559     // TODO: also do the same for iconified.
    560     if (window->monitor || window->wl.maximized)
    561     {
    562         if (window->wl.shellSurface)
    563             wl_shell_surface_set_toplevel(window->wl.shellSurface);
    564 
    565         window->wl.maximized = GLFW_FALSE;
    566     }
    567 }
    568 
    569 void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
    570 {
    571     if (!window->monitor && !window->wl.maximized)
    572     {
    573         if (window->wl.shellSurface)
    574         {
    575             // Let the compositor select the best output.
    576             wl_shell_surface_set_maximized(window->wl.shellSurface, NULL);
    577         }
    578         window->wl.maximized = GLFW_TRUE;
    579     }
    580 }
    581 
    582 void _glfwPlatformShowWindow(_GLFWwindow* window)
    583 {
    584     if (!window->monitor)
    585     {
    586         if (!window->wl.shellSurface)
    587             createShellSurface(window);
    588         window->wl.visible = GLFW_TRUE;
    589     }
    590 }
    591 
    592 void _glfwPlatformHideWindow(_GLFWwindow* window)
    593 {
    594     if (!window->monitor)
    595     {
    596         if (window->wl.shellSurface)
    597             wl_shell_surface_destroy(window->wl.shellSurface);
    598         window->wl.visible = GLFW_FALSE;
    599     }
    600 }
    601 
    602 void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
    603 {
    604     // TODO
    605     _glfwInputError(GLFW_PLATFORM_ERROR,
    606                     "Wayland: Window attention request not implemented yet");
    607 }
    608 
    609 void _glfwPlatformFocusWindow(_GLFWwindow* window)
    610 {
    611     _glfwInputError(GLFW_PLATFORM_ERROR,
    612                     "Wayland: Focusing a window requires user interaction");
    613 }
    614 
    615 void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
    616                                    _GLFWmonitor* monitor,
    617                                    int xpos, int ypos,
    618                                    int width, int height,
    619                                    int refreshRate)
    620 {
    621     if (monitor)
    622     {
    623         wl_shell_surface_set_fullscreen(
    624             window->wl.shellSurface,
    625             WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
    626             refreshRate * 1000, // Convert Hz to mHz.
    627             monitor->wl.output);
    628     }
    629     else
    630     {
    631         wl_shell_surface_set_toplevel(window->wl.shellSurface);
    632     }
    633     _glfwInputWindowMonitorChange(window, monitor);
    634 }
    635 
    636 int _glfwPlatformWindowFocused(_GLFWwindow* window)
    637 {
    638     return _glfw.wl.keyboardFocus == window;
    639 }
    640 
    641 int _glfwPlatformWindowIconified(_GLFWwindow* window)
    642 {
    643     // TODO: move to xdg_shell, wl_shell doesn't have any iconified concept.
    644     return GLFW_FALSE;
    645 }
    646 
    647 int _glfwPlatformWindowVisible(_GLFWwindow* window)
    648 {
    649     return window->wl.visible;
    650 }
    651 
    652 int _glfwPlatformWindowMaximized(_GLFWwindow* window)
    653 {
    654     return window->wl.maximized;
    655 }
    656 
    657 void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
    658 {
    659     // TODO
    660     _glfwInputError(GLFW_PLATFORM_ERROR,
    661                     "Wayland: Window attribute setting not implemented yet");
    662 }
    663 
    664 void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled)
    665 {
    666     // TODO
    667     _glfwInputError(GLFW_PLATFORM_ERROR,
    668                     "Wayland: Window attribute setting not implemented yet");
    669 }
    670 
    671 void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
    672 {
    673     // TODO
    674     _glfwInputError(GLFW_PLATFORM_ERROR,
    675                     "Wayland: Window attribute setting not implemented yet");
    676 }
    677 
    678 void _glfwPlatformPollEvents(void)
    679 {
    680     handleEvents(0);
    681 }
    682 
    683 void _glfwPlatformWaitEvents(void)
    684 {
    685     handleEvents(-1);
    686 }
    687 
    688 void _glfwPlatformWaitEventsTimeout(double timeout)
    689 {
    690     handleEvents((int) (timeout * 1e3));
    691 }
    692 
    693 void _glfwPlatformPostEmptyEvent(void)
    694 {
    695     wl_display_sync(_glfw.wl.display);
    696 }
    697 
    698 void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
    699 {
    700     if (xpos)
    701         *xpos = window->wl.cursorPosX;
    702     if (ypos)
    703         *ypos = window->wl.cursorPosY;
    704 }
    705 
    706 static GLFWbool isPointerLocked(_GLFWwindow* window);
    707 
    708 void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
    709 {
    710     if (isPointerLocked(window))
    711     {
    712         zwp_locked_pointer_v1_set_cursor_position_hint(
    713             window->wl.pointerLock.lockedPointer,
    714             wl_fixed_from_double(x), wl_fixed_from_double(y));
    715         wl_surface_commit(window->wl.surface);
    716     }
    717 }
    718 
    719 void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
    720 {
    721     _glfwPlatformSetCursor(window, window->wl.currentCursor);
    722 }
    723 
    724 const char* _glfwPlatformGetScancodeName(int scancode)
    725 {
    726     // TODO
    727     return NULL;
    728 }
    729 
    730 int _glfwPlatformGetKeyScancode(int key)
    731 {
    732     return _glfw.wl.scancodes[key];
    733 }
    734 
    735 int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
    736                               const GLFWimage* image,
    737                               int xhot, int yhot)
    738 {
    739     struct wl_shm_pool* pool;
    740     int stride = image->width * 4;
    741     int length = image->width * image->height * 4;
    742     void* data;
    743     int fd, i;
    744 
    745     fd = createAnonymousFile(length);
    746     if (fd < 0)
    747     {
    748         _glfwInputError(GLFW_PLATFORM_ERROR,
    749                         "Wayland: Creating a buffer file for %d B failed: %m",
    750                         length);
    751         return GLFW_FALSE;
    752     }
    753 
    754     data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    755     if (data == MAP_FAILED)
    756     {
    757         _glfwInputError(GLFW_PLATFORM_ERROR,
    758                         "Wayland: Cursor mmap failed: %m");
    759         close(fd);
    760         return GLFW_FALSE;
    761     }
    762 
    763     pool = wl_shm_create_pool(_glfw.wl.shm, fd, length);
    764 
    765     close(fd);
    766     unsigned char* source = (unsigned char*) image->pixels;
    767     unsigned char* target = data;
    768     for (i = 0;  i < image->width * image->height;  i++, source += 4)
    769     {
    770         unsigned int alpha = source[3];
    771 
    772         *target++ = (unsigned char) ((source[2] * alpha) / 255);
    773         *target++ = (unsigned char) ((source[1] * alpha) / 255);
    774         *target++ = (unsigned char) ((source[0] * alpha) / 255);
    775         *target++ = (unsigned char) alpha;
    776     }
    777 
    778     cursor->wl.buffer =
    779         wl_shm_pool_create_buffer(pool, 0,
    780                                   image->width,
    781                                   image->height,
    782                                   stride, WL_SHM_FORMAT_ARGB8888);
    783     munmap(data, length);
    784     wl_shm_pool_destroy(pool);
    785 
    786     cursor->wl.width = image->width;
    787     cursor->wl.height = image->height;
    788     cursor->wl.xhot = xhot;
    789     cursor->wl.yhot = yhot;
    790     return GLFW_TRUE;
    791 }
    792 
    793 int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
    794 {
    795     struct wl_cursor* standardCursor;
    796 
    797     standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme,
    798                                                 translateCursorShape(shape));
    799     if (!standardCursor)
    800     {
    801         _glfwInputError(GLFW_PLATFORM_ERROR,
    802                         "Wayland: Standard cursor \"%s\" not found",
    803                         translateCursorShape(shape));
    804         return GLFW_FALSE;
    805     }
    806 
    807     cursor->wl.image = standardCursor->images[0];
    808     return GLFW_TRUE;
    809 }
    810 
    811 void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
    812 {
    813     // If it's a standard cursor we don't need to do anything here
    814     if (cursor->wl.image)
    815         return;
    816 
    817     if (cursor->wl.buffer)
    818         wl_buffer_destroy(cursor->wl.buffer);
    819 }
    820 
    821 static void handleRelativeMotion(void* data,
    822                                  struct zwp_relative_pointer_v1* pointer,
    823                                  uint32_t timeHi,
    824                                  uint32_t timeLo,
    825                                  wl_fixed_t dx,
    826                                  wl_fixed_t dy,
    827                                  wl_fixed_t dxUnaccel,
    828                                  wl_fixed_t dyUnaccel)
    829 {
    830     _GLFWwindow* window = data;
    831 
    832     if (window->cursorMode != GLFW_CURSOR_DISABLED)
    833         return;
    834 
    835     _glfwInputCursorPos(window,
    836                         window->virtualCursorPosX + wl_fixed_to_double(dxUnaccel),
    837                         window->virtualCursorPosY + wl_fixed_to_double(dyUnaccel));
    838 }
    839 
    840 static const struct zwp_relative_pointer_v1_listener relativePointerListener = {
    841     handleRelativeMotion
    842 };
    843 
    844 static void handleLocked(void* data,
    845                          struct zwp_locked_pointer_v1* lockedPointer)
    846 {
    847 }
    848 
    849 static void unlockPointer(_GLFWwindow* window)
    850 {
    851     struct zwp_relative_pointer_v1* relativePointer =
    852         window->wl.pointerLock.relativePointer;
    853     struct zwp_locked_pointer_v1* lockedPointer =
    854         window->wl.pointerLock.lockedPointer;
    855 
    856     zwp_relative_pointer_v1_destroy(relativePointer);
    857     zwp_locked_pointer_v1_destroy(lockedPointer);
    858 
    859     window->wl.pointerLock.relativePointer = NULL;
    860     window->wl.pointerLock.lockedPointer = NULL;
    861 }
    862 
    863 static void lockPointer(_GLFWwindow* window);
    864 
    865 static void handleUnlocked(void* data,
    866                            struct zwp_locked_pointer_v1* lockedPointer)
    867 {
    868 }
    869 
    870 static const struct zwp_locked_pointer_v1_listener lockedPointerListener = {
    871     handleLocked,
    872     handleUnlocked
    873 };
    874 
    875 static void lockPointer(_GLFWwindow* window)
    876 {
    877     struct zwp_relative_pointer_v1* relativePointer;
    878     struct zwp_locked_pointer_v1* lockedPointer;
    879 
    880     if (!_glfw.wl.relativePointerManager)
    881     {
    882         _glfwInputError(GLFW_PLATFORM_ERROR,
    883                         "Wayland: no relative pointer manager");
    884         return;
    885     }
    886 
    887     relativePointer =
    888         zwp_relative_pointer_manager_v1_get_relative_pointer(
    889             _glfw.wl.relativePointerManager,
    890             _glfw.wl.pointer);
    891     zwp_relative_pointer_v1_add_listener(relativePointer,
    892                                          &relativePointerListener,
    893                                          window);
    894 
    895     lockedPointer =
    896         zwp_pointer_constraints_v1_lock_pointer(
    897             _glfw.wl.pointerConstraints,
    898             window->wl.surface,
    899             _glfw.wl.pointer,
    900             NULL,
    901             ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
    902     zwp_locked_pointer_v1_add_listener(lockedPointer,
    903                                        &lockedPointerListener,
    904                                        window);
    905 
    906     window->wl.pointerLock.relativePointer = relativePointer;
    907     window->wl.pointerLock.lockedPointer = lockedPointer;
    908 
    909     wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
    910                           NULL, 0, 0);
    911 }
    912 
    913 static GLFWbool isPointerLocked(_GLFWwindow* window)
    914 {
    915     return window->wl.pointerLock.lockedPointer != NULL;
    916 }
    917 
    918 void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
    919 {
    920     struct wl_buffer* buffer;
    921     struct wl_cursor* defaultCursor;
    922     struct wl_cursor_image* image;
    923     struct wl_surface* surface = _glfw.wl.cursorSurface;
    924 
    925     if (!_glfw.wl.pointer)
    926         return;
    927 
    928     window->wl.currentCursor = cursor;
    929 
    930     // If we're not in the correct window just save the cursor
    931     // the next time the pointer enters the window the cursor will change
    932     if (window != _glfw.wl.pointerFocus)
    933         return;
    934 
    935     // Unlock possible pointer lock if no longer disabled.
    936     if (window->cursorMode != GLFW_CURSOR_DISABLED && isPointerLocked(window))
    937         unlockPointer(window);
    938 
    939     if (window->cursorMode == GLFW_CURSOR_NORMAL)
    940     {
    941         if (cursor)
    942             image = cursor->wl.image;
    943         else
    944         {
    945             defaultCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme,
    946                                                        "left_ptr");
    947             if (!defaultCursor)
    948             {
    949                 _glfwInputError(GLFW_PLATFORM_ERROR,
    950                                 "Wayland: Standard cursor not found");
    951                 return;
    952             }
    953             image = defaultCursor->images[0];
    954         }
    955 
    956         if (image)
    957         {
    958             buffer = wl_cursor_image_get_buffer(image);
    959             if (!buffer)
    960                 return;
    961             wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
    962                                   surface,
    963                                   image->hotspot_x,
    964                                   image->hotspot_y);
    965             wl_surface_attach(surface, buffer, 0, 0);
    966             wl_surface_damage(surface, 0, 0,
    967                               image->width, image->height);
    968             wl_surface_commit(surface);
    969         }
    970         else
    971         {
    972             wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
    973                                   surface,
    974                                   cursor->wl.xhot,
    975                                   cursor->wl.yhot);
    976             wl_surface_attach(surface, cursor->wl.buffer, 0, 0);
    977             wl_surface_damage(surface, 0, 0,
    978                               cursor->wl.width, cursor->wl.height);
    979             wl_surface_commit(surface);
    980         }
    981     }
    982     else if (window->cursorMode == GLFW_CURSOR_DISABLED)
    983     {
    984         if (!isPointerLocked(window))
    985             lockPointer(window);
    986     }
    987     else if (window->cursorMode == GLFW_CURSOR_HIDDEN)
    988     {
    989         wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
    990                               NULL, 0, 0);
    991     }
    992 }
    993 
    994 void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
    995 {
    996     // TODO
    997     _glfwInputError(GLFW_PLATFORM_ERROR,
    998                     "Wayland: Clipboard setting not implemented yet");
    999 }
   1000 
   1001 const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
   1002 {
   1003     // TODO
   1004     _glfwInputError(GLFW_PLATFORM_ERROR,
   1005                     "Wayland: Clipboard getting not implemented yet");
   1006     return NULL;
   1007 }
   1008 
   1009 void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
   1010 {
   1011     if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_wayland_surface)
   1012         return;
   1013 
   1014     extensions[0] = "VK_KHR_surface";
   1015     extensions[1] = "VK_KHR_wayland_surface";
   1016 }
   1017 
   1018 int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
   1019                                                       VkPhysicalDevice device,
   1020                                                       uint32_t queuefamily)
   1021 {
   1022     PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR =
   1023         (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)
   1024         vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR");
   1025     if (!vkGetPhysicalDeviceWaylandPresentationSupportKHR)
   1026     {
   1027         _glfwInputError(GLFW_API_UNAVAILABLE,
   1028                         "Wayland: Vulkan instance missing VK_KHR_wayland_surface extension");
   1029         return VK_NULL_HANDLE;
   1030     }
   1031 
   1032     return vkGetPhysicalDeviceWaylandPresentationSupportKHR(device,
   1033                                                             queuefamily,
   1034                                                             _glfw.wl.display);
   1035 }
   1036 
   1037 VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
   1038                                           _GLFWwindow* window,
   1039                                           const VkAllocationCallbacks* allocator,
   1040                                           VkSurfaceKHR* surface)
   1041 {
   1042     VkResult err;
   1043     VkWaylandSurfaceCreateInfoKHR sci;
   1044     PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR;
   1045 
   1046     vkCreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR)
   1047         vkGetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR");
   1048     if (!vkCreateWaylandSurfaceKHR)
   1049     {
   1050         _glfwInputError(GLFW_API_UNAVAILABLE,
   1051                         "Wayland: Vulkan instance missing VK_KHR_wayland_surface extension");
   1052         return VK_ERROR_EXTENSION_NOT_PRESENT;
   1053     }
   1054 
   1055     memset(&sci, 0, sizeof(sci));
   1056     sci.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
   1057     sci.display = _glfw.wl.display;
   1058     sci.surface = window->wl.surface;
   1059 
   1060     err = vkCreateWaylandSurfaceKHR(instance, &sci, allocator, surface);
   1061     if (err)
   1062     {
   1063         _glfwInputError(GLFW_PLATFORM_ERROR,
   1064                         "Wayland: Failed to create Vulkan surface: %s",
   1065                         _glfwGetVulkanResultString(err));
   1066     }
   1067 
   1068     return err;
   1069 }
   1070 
   1071 
   1072 //////////////////////////////////////////////////////////////////////////
   1073 //////                        GLFW native API                       //////
   1074 //////////////////////////////////////////////////////////////////////////
   1075 
   1076 GLFWAPI struct wl_display* glfwGetWaylandDisplay(void)
   1077 {
   1078     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
   1079     return _glfw.wl.display;
   1080 }
   1081 
   1082 GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* handle)
   1083 {
   1084     _GLFWwindow* window = (_GLFWwindow*) handle;
   1085     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
   1086     return window->wl.surface;
   1087 }
   1088