github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/tests/raylib/external/glfw/src/wl_window.c (about)

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