Wise&mystical  1.0
Project about Europe
Loading...
Searching...
No Matches
wl_window.c
Go to the documentation of this file.
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 <unistd.h>
37#include <string.h>
38#include <fcntl.h>
39#include <sys/mman.h>
40#include <sys/timerfd.h>
41#include <poll.h>
42
43
44static int createTmpfileCloexec(char* tmpname)
45{
46 int fd;
47
48 fd = mkostemp(tmpname, O_CLOEXEC);
49 if (fd >= 0)
50 unlink(tmpname);
51
52 return fd;
53}
54
55/*
56 * Create a new, unique, anonymous file of the given size, and
57 * return the file descriptor for it. The file descriptor is set
58 * CLOEXEC. The file is immediately suitable for mmap()'ing
59 * the given size at offset zero.
60 *
61 * The file should not have a permanent backing store like a disk,
62 * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
63 *
64 * The file name is deleted from the file system.
65 *
66 * The file is suitable for buffer sharing between processes by
67 * transmitting the file descriptor over Unix sockets using the
68 * SCM_RIGHTS methods.
69 *
70 * posix_fallocate() is used to guarantee that disk space is available
71 * for the file at the given size. If disk space is insufficient, errno
72 * is set to ENOSPC. If posix_fallocate() is not supported, program may
73 * receive SIGBUS on accessing mmap()'ed file contents instead.
74 */
75static int createAnonymousFile(off_t size)
76{
77 static const char template[] = "/glfw-shared-XXXXXX";
78 const char* path;
79 char* name;
80 int fd;
81 int ret;
82
83#ifdef HAVE_MEMFD_CREATE
84 fd = memfd_create("glfw-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING);
85 if (fd >= 0)
86 {
87 // We can add this seal before calling posix_fallocate(), as the file
88 // is currently zero-sized anyway.
89 //
90 // There is also no need to check for the return value, we couldn’t do
91 // anything with it anyway.
92 fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
93 }
94 else
95#elif defined(SHM_ANON)
96 fd = shm_open(SHM_ANON, O_RDWR | O_CLOEXEC, 0600);
97 if (fd < 0)
98#endif
99 {
100 path = getenv("XDG_RUNTIME_DIR");
101 if (!path)
102 {
103 errno = ENOENT;
104 return -1;
105 }
106
107 name = calloc(strlen(path) + sizeof(template), 1);
108 strcpy(name, path);
109 strcat(name, template);
110
111 fd = createTmpfileCloexec(name);
112 free(name);
113 if (fd < 0)
114 return -1;
115 }
116
117#if defined(SHM_ANON)
118 // posix_fallocate does not work on SHM descriptors
119 ret = ftruncate(fd, size);
120#else
121 ret = posix_fallocate(fd, 0, size);
122#endif
123 if (ret != 0)
124 {
125 close(fd);
126 errno = ret;
127 return -1;
128 }
129 return fd;
130}
131
132static struct wl_buffer* createShmBuffer(const GLFWimage* image)
133{
134 struct wl_shm_pool* pool;
135 struct wl_buffer* buffer;
136 int stride = image->width * 4;
137 int length = image->width * image->height * 4;
138 void* data;
139 int fd, i;
140
141 fd = createAnonymousFile(length);
142 if (fd < 0)
143 {
145 "Wayland: Creating a buffer file for %d B failed: %s",
146 length, strerror(errno));
147 return NULL;
148 }
149
150 data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
151 if (data == MAP_FAILED)
152 {
154 "Wayland: mmap failed: %s", strerror(errno));
155 close(fd);
156 return NULL;
157 }
158
159 pool = wl_shm_create_pool(_glfw.wl.shm, fd, length);
160
161 close(fd);
162 unsigned char* source = (unsigned char*) image->pixels;
163 unsigned char* target = data;
164 for (i = 0; i < image->width * image->height; i++, source += 4)
165 {
166 unsigned int alpha = source[3];
167
168 *target++ = (unsigned char) ((source[2] * alpha) / 255);
169 *target++ = (unsigned char) ((source[1] * alpha) / 255);
170 *target++ = (unsigned char) ((source[0] * alpha) / 255);
171 *target++ = (unsigned char) alpha;
172 }
173
174 buffer =
175 wl_shm_pool_create_buffer(pool, 0,
176 image->width,
177 image->height,
178 stride, WL_SHM_FORMAT_ARGB8888);
179 munmap(data, length);
180 wl_shm_pool_destroy(pool);
181
182 return buffer;
183}
184
185static void createDecoration(_GLFWdecorationWayland* decoration,
186 struct wl_surface* parent,
187 struct wl_buffer* buffer, GLFWbool opaque,
188 int x, int y,
189 int width, int height)
190{
191 struct wl_region* region;
192
193 decoration->surface = wl_compositor_create_surface(_glfw.wl.compositor);
194 decoration->subsurface =
195 wl_subcompositor_get_subsurface(_glfw.wl.subcompositor,
196 decoration->surface, parent);
197 wl_subsurface_set_position(decoration->subsurface, x, y);
198 decoration->viewport = wp_viewporter_get_viewport(_glfw.wl.viewporter,
199 decoration->surface);
200 wp_viewport_set_destination(decoration->viewport, width, height);
201 wl_surface_attach(decoration->surface, buffer, 0, 0);
202
203 if (opaque)
204 {
205 region = wl_compositor_create_region(_glfw.wl.compositor);
206 wl_region_add(region, 0, 0, width, height);
207 wl_surface_set_opaque_region(decoration->surface, region);
208 wl_surface_commit(decoration->surface);
209 wl_region_destroy(region);
210 }
211 else
212 wl_surface_commit(decoration->surface);
213}
214
215static void createDecorations(_GLFWwindow* window)
216{
217 unsigned char data[] = { 224, 224, 224, 255 };
218 const GLFWimage image = { 1, 1, data };
219 GLFWbool opaque = (data[3] == 255);
220
221 if (!_glfw.wl.viewporter || !window->decorated || window->wl.decorations.serverSide)
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 createDecoration(&window->wl.decorations.top, window->wl.surface,
230 window->wl.decorations.buffer, opaque,
232 window->wl.width, _GLFW_DECORATION_TOP);
233 createDecoration(&window->wl.decorations.left, window->wl.surface,
234 window->wl.decorations.buffer, opaque,
236 _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);
237 createDecoration(&window->wl.decorations.right, window->wl.surface,
238 window->wl.decorations.buffer, opaque,
239 window->wl.width, -_GLFW_DECORATION_TOP,
240 _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);
241 createDecoration(&window->wl.decorations.bottom, window->wl.surface,
242 window->wl.decorations.buffer, opaque,
243 -_GLFW_DECORATION_WIDTH, window->wl.height,
245}
246
247static void destroyDecoration(_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
260static void destroyDecorations(_GLFWwindow* window)
261{
262 destroyDecoration(&window->wl.decorations.top);
263 destroyDecoration(&window->wl.decorations.left);
264 destroyDecoration(&window->wl.decorations.right);
265 destroyDecoration(&window->wl.decorations.bottom);
266}
267
268static void xdgDecorationHandleConfigure(void* data,
269 struct zxdg_toplevel_decoration_v1* decoration,
270 uint32_t mode)
271{
272 _GLFWwindow* window = data;
273
274 window->wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
275
276 if (!window->wl.decorations.serverSide)
277 createDecorations(window);
278}
279
280static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener = {
281 xdgDecorationHandleConfigure,
282};
283
284// Makes the surface considered as XRGB instead of ARGB.
285static void setOpaqueRegion(_GLFWwindow* window)
286{
287 struct wl_region* region;
288
289 region = wl_compositor_create_region(_glfw.wl.compositor);
290 if (!region)
291 return;
292
293 wl_region_add(region, 0, 0, window->wl.width, window->wl.height);
294 wl_surface_set_opaque_region(window->wl.surface, region);
295 wl_surface_commit(window->wl.surface);
296 wl_region_destroy(region);
297}
298
299
300static void resizeWindow(_GLFWwindow* window)
301{
302 int scale = window->wl.scale;
303 int scaledWidth = window->wl.width * scale;
304 int scaledHeight = window->wl.height * scale;
305 wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0);
306 if (!window->wl.transparent)
307 setOpaqueRegion(window);
308 _glfwInputFramebufferSize(window, scaledWidth, scaledHeight);
309 _glfwInputWindowContentScale(window, scale, scale);
310
311 if (!window->wl.decorations.top.surface)
312 return;
313
314 // Top decoration.
315 wp_viewport_set_destination(window->wl.decorations.top.viewport,
316 window->wl.width, _GLFW_DECORATION_TOP);
317 wl_surface_commit(window->wl.decorations.top.surface);
318
319 // Left decoration.
320 wp_viewport_set_destination(window->wl.decorations.left.viewport,
321 _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);
322 wl_surface_commit(window->wl.decorations.left.surface);
323
324 // Right decoration.
325 wl_subsurface_set_position(window->wl.decorations.right.subsurface,
326 window->wl.width, -_GLFW_DECORATION_TOP);
327 wp_viewport_set_destination(window->wl.decorations.right.viewport,
328 _GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);
329 wl_surface_commit(window->wl.decorations.right.surface);
330
331 // Bottom decoration.
332 wl_subsurface_set_position(window->wl.decorations.bottom.subsurface,
333 -_GLFW_DECORATION_WIDTH, window->wl.height);
334 wp_viewport_set_destination(window->wl.decorations.bottom.viewport,
336 wl_surface_commit(window->wl.decorations.bottom.surface);
337}
338
339static void checkScaleChange(_GLFWwindow* window)
340{
341 int scale = 1;
342 int i;
343 int monitorScale;
344
345 // Check if we will be able to set the buffer scale or not.
346 if (_glfw.wl.compositorVersion < 3)
347 return;
348
349 // Get the scale factor from the highest scale monitor.
350 for (i = 0; i < window->wl.monitorsCount; ++i)
351 {
352 monitorScale = window->wl.monitors[i]->wl.scale;
353 if (scale < monitorScale)
354 scale = monitorScale;
355 }
356
357 // Only change the framebuffer size if the scale changed.
358 if (scale != window->wl.scale)
359 {
360 window->wl.scale = scale;
361 wl_surface_set_buffer_scale(window->wl.surface, scale);
362 resizeWindow(window);
363 }
364}
365
366static void surfaceHandleEnter(void *data,
367 struct wl_surface *surface,
368 struct wl_output *output)
369{
370 _GLFWwindow* window = data;
371 _GLFWmonitor* monitor = wl_output_get_user_data(output);
372
373 if (window->wl.monitorsCount + 1 > window->wl.monitorsSize)
374 {
375 ++window->wl.monitorsSize;
376 window->wl.monitors =
377 realloc(window->wl.monitors,
378 window->wl.monitorsSize * sizeof(_GLFWmonitor*));
379 }
380
381 window->wl.monitors[window->wl.monitorsCount++] = monitor;
382
383 checkScaleChange(window);
384}
385
386static void surfaceHandleLeave(void *data,
387 struct wl_surface *surface,
388 struct wl_output *output)
389{
390 _GLFWwindow* window = data;
391 _GLFWmonitor* monitor = wl_output_get_user_data(output);
392 GLFWbool found;
393 int i;
394
395 for (i = 0, found = GLFW_FALSE; i < window->wl.monitorsCount - 1; ++i)
396 {
397 if (monitor == window->wl.monitors[i])
398 found = GLFW_TRUE;
399 if (found)
400 window->wl.monitors[i] = window->wl.monitors[i + 1];
401 }
402 window->wl.monitors[--window->wl.monitorsCount] = NULL;
403
404 checkScaleChange(window);
405}
406
407static const struct wl_surface_listener surfaceListener = {
408 surfaceHandleEnter,
409 surfaceHandleLeave
410};
411
412static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable)
413{
414 if (enable && !window->wl.idleInhibitor && _glfw.wl.idleInhibitManager)
415 {
416 window->wl.idleInhibitor =
417 zwp_idle_inhibit_manager_v1_create_inhibitor(
418 _glfw.wl.idleInhibitManager, window->wl.surface);
419 if (!window->wl.idleInhibitor)
421 "Wayland: Idle inhibitor creation failed");
422 }
423 else if (!enable && window->wl.idleInhibitor)
424 {
425 zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor);
426 window->wl.idleInhibitor = NULL;
427 }
428}
429
430static GLFWbool createSurface(_GLFWwindow* window,
431 const _GLFWwndconfig* wndconfig)
432{
433 window->wl.surface = wl_compositor_create_surface(_glfw.wl.compositor);
434 if (!window->wl.surface)
435 return GLFW_FALSE;
436
437 wl_surface_add_listener(window->wl.surface,
438 &surfaceListener,
439 window);
440
441 wl_surface_set_user_data(window->wl.surface, window);
442
443 window->wl.native = wl_egl_window_create(window->wl.surface,
444 wndconfig->width,
445 wndconfig->height);
446 if (!window->wl.native)
447 return GLFW_FALSE;
448
449 window->wl.width = wndconfig->width;
450 window->wl.height = wndconfig->height;
451 window->wl.scale = 1;
452
453 if (!window->wl.transparent)
454 setOpaqueRegion(window);
455
456 return GLFW_TRUE;
457}
458
459static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor,
460 int refreshRate)
461{
462 if (window->wl.xdg.toplevel)
463 {
464 xdg_toplevel_set_fullscreen(
465 window->wl.xdg.toplevel,
466 monitor->wl.output);
467 }
468 setIdleInhibitor(window, GLFW_TRUE);
469 if (!window->wl.decorations.serverSide)
470 destroyDecorations(window);
471}
472
473static void xdgToplevelHandleConfigure(void* data,
474 struct xdg_toplevel* toplevel,
475 int32_t width,
476 int32_t height,
477 struct wl_array* states)
478{
479 _GLFWwindow* window = data;
480 float aspectRatio;
481 float targetRatio;
482 uint32_t* state;
483 GLFWbool maximized = GLFW_FALSE;
484 GLFWbool fullscreen = GLFW_FALSE;
485 GLFWbool activated = GLFW_FALSE;
486
487 wl_array_for_each(state, states)
488 {
489 switch (*state)
490 {
491 case XDG_TOPLEVEL_STATE_MAXIMIZED:
492 maximized = GLFW_TRUE;
493 break;
494 case XDG_TOPLEVEL_STATE_FULLSCREEN:
495 fullscreen = GLFW_TRUE;
496 break;
497 case XDG_TOPLEVEL_STATE_RESIZING:
498 break;
499 case XDG_TOPLEVEL_STATE_ACTIVATED:
500 activated = GLFW_TRUE;
501 break;
502 }
503 }
504
505 if (width != 0 && height != 0)
506 {
507 if (!maximized && !fullscreen)
508 {
509 if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)
510 {
511 aspectRatio = (float)width / (float)height;
512 targetRatio = (float)window->numer / (float)window->denom;
513 if (aspectRatio < targetRatio)
514 height = width / targetRatio;
515 else if (aspectRatio > targetRatio)
516 width = height * targetRatio;
517 }
518 }
519
520 _glfwInputWindowSize(window, width, height);
521 _glfwPlatformSetWindowSize(window, width, height);
523 }
524
525 if (window->wl.wasFullscreen && window->autoIconify)
526 {
527 if (!activated || !fullscreen)
528 {
530 window->wl.wasFullscreen = GLFW_FALSE;
531 }
532 }
533 if (fullscreen && activated)
534 window->wl.wasFullscreen = GLFW_TRUE;
535 _glfwInputWindowFocus(window, activated);
536}
537
538static void xdgToplevelHandleClose(void* data,
539 struct xdg_toplevel* toplevel)
540{
541 _GLFWwindow* window = data;
543}
544
545static const struct xdg_toplevel_listener xdgToplevelListener = {
546 xdgToplevelHandleConfigure,
547 xdgToplevelHandleClose
548};
549
550static void xdgSurfaceHandleConfigure(void* data,
551 struct xdg_surface* surface,
552 uint32_t serial)
553{
554 xdg_surface_ack_configure(surface, serial);
555}
556
557static const struct xdg_surface_listener xdgSurfaceListener = {
558 xdgSurfaceHandleConfigure
559};
560
561static void setXdgDecorations(_GLFWwindow* window)
562{
563 if (_glfw.wl.decorationManager)
564 {
565 window->wl.xdg.decoration =
566 zxdg_decoration_manager_v1_get_toplevel_decoration(
567 _glfw.wl.decorationManager, window->wl.xdg.toplevel);
568 zxdg_toplevel_decoration_v1_add_listener(window->wl.xdg.decoration,
569 &xdgDecorationListener,
570 window);
571 zxdg_toplevel_decoration_v1_set_mode(
572 window->wl.xdg.decoration,
573 ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
574 }
575 else
576 {
577 window->wl.decorations.serverSide = GLFW_FALSE;
578 createDecorations(window);
579 }
580}
581
582static GLFWbool createXdgSurface(_GLFWwindow* window)
583{
584 window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase,
585 window->wl.surface);
586 if (!window->wl.xdg.surface)
587 {
589 "Wayland: xdg-surface creation failed");
590 return GLFW_FALSE;
591 }
592
593 xdg_surface_add_listener(window->wl.xdg.surface,
594 &xdgSurfaceListener,
595 window);
596
597 window->wl.xdg.toplevel = xdg_surface_get_toplevel(window->wl.xdg.surface);
598 if (!window->wl.xdg.toplevel)
599 {
601 "Wayland: xdg-toplevel creation failed");
602 return GLFW_FALSE;
603 }
604
605 xdg_toplevel_add_listener(window->wl.xdg.toplevel,
606 &xdgToplevelListener,
607 window);
608
609 if (window->wl.title)
610 xdg_toplevel_set_title(window->wl.xdg.toplevel, window->wl.title);
611
612 if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE)
613 xdg_toplevel_set_min_size(window->wl.xdg.toplevel,
614 window->minwidth, window->minheight);
615 if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE)
616 xdg_toplevel_set_max_size(window->wl.xdg.toplevel,
617 window->maxwidth, window->maxheight);
618
619 if (window->monitor)
620 {
621 xdg_toplevel_set_fullscreen(window->wl.xdg.toplevel,
622 window->monitor->wl.output);
623 setIdleInhibitor(window, GLFW_TRUE);
624 }
625 else if (window->wl.maximized)
626 {
627 xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
628 setIdleInhibitor(window, GLFW_FALSE);
629 setXdgDecorations(window);
630 }
631 else
632 {
633 setIdleInhibitor(window, GLFW_FALSE);
634 setXdgDecorations(window);
635 }
636
637 wl_surface_commit(window->wl.surface);
638 wl_display_roundtrip(_glfw.wl.display);
639
640 return GLFW_TRUE;
641}
642
643static void setCursorImage(_GLFWwindow* window,
644 _GLFWcursorWayland* cursorWayland)
645{
646 struct itimerspec timer = {};
647 struct wl_cursor* wlCursor = cursorWayland->cursor;
648 struct wl_cursor_image* image;
649 struct wl_buffer* buffer;
650 struct wl_surface* surface = _glfw.wl.cursorSurface;
651 int scale = 1;
652
653 if (!wlCursor)
654 buffer = cursorWayland->buffer;
655 else
656 {
657 if (window->wl.scale > 1 && cursorWayland->cursorHiDPI)
658 {
659 wlCursor = cursorWayland->cursorHiDPI;
660 scale = 2;
661 }
662
663 image = wlCursor->images[cursorWayland->currentImage];
664 buffer = wl_cursor_image_get_buffer(image);
665 if (!buffer)
666 return;
667
668 timer.it_value.tv_sec = image->delay / 1000;
669 timer.it_value.tv_nsec = (image->delay % 1000) * 1000000;
670 timerfd_settime(_glfw.wl.cursorTimerfd, 0, &timer, NULL);
671
672 cursorWayland->width = image->width;
673 cursorWayland->height = image->height;
674 cursorWayland->xhot = image->hotspot_x;
675 cursorWayland->yhot = image->hotspot_y;
676 }
677
678 wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,
679 surface,
680 cursorWayland->xhot / scale,
681 cursorWayland->yhot / scale);
682 wl_surface_set_buffer_scale(surface, scale);
683 wl_surface_attach(surface, buffer, 0, 0);
684 wl_surface_damage(surface, 0, 0,
685 cursorWayland->width, cursorWayland->height);
686 wl_surface_commit(surface);
687}
688
689static void incrementCursorImage(_GLFWwindow* window)
690{
691 _GLFWcursor* cursor;
692
693 if (!window || window->wl.decorations.focus != mainWindow)
694 return;
695
696 cursor = window->wl.currentCursor;
697 if (cursor && cursor->wl.cursor)
698 {
699 cursor->wl.currentImage += 1;
700 cursor->wl.currentImage %= cursor->wl.cursor->image_count;
701 setCursorImage(window, &cursor->wl);
702 }
703}
704
705static void handleEvents(int timeout)
706{
707 struct wl_display* display = _glfw.wl.display;
708 struct pollfd fds[] = {
709 { wl_display_get_fd(display), POLLIN },
710 { _glfw.wl.timerfd, POLLIN },
711 { _glfw.wl.cursorTimerfd, POLLIN },
712 };
713 ssize_t read_ret;
714 uint64_t repeats, i;
715
716 while (wl_display_prepare_read(display) != 0)
717 wl_display_dispatch_pending(display);
718
719 // If an error different from EAGAIN happens, we have likely been
720 // disconnected from the Wayland session, try to handle that the best we
721 // can.
722 if (wl_display_flush(display) < 0 && errno != EAGAIN)
723 {
725 while (window)
726 {
728 window = window->next;
729 }
730 wl_display_cancel_read(display);
731 return;
732 }
733
734 if (poll(fds, 3, timeout) > 0)
735 {
736 if (fds[0].revents & POLLIN)
737 {
738 wl_display_read_events(display);
739 wl_display_dispatch_pending(display);
740 }
741 else
742 {
743 wl_display_cancel_read(display);
744 }
745
746 if (fds[1].revents & POLLIN)
747 {
748 read_ret = read(_glfw.wl.timerfd, &repeats, sizeof(repeats));
749 if (read_ret != 8)
750 return;
751
752 if (_glfw.wl.keyboardFocus)
753 {
754 for (i = 0; i < repeats; ++i)
755 {
756 _glfwInputKey(_glfw.wl.keyboardFocus,
757 _glfw.wl.keyboardLastKey,
758 _glfw.wl.keyboardLastScancode,
760 _glfw.wl.xkb.modifiers);
761 }
762 }
763 }
764
765 if (fds[2].revents & POLLIN)
766 {
767 read_ret = read(_glfw.wl.cursorTimerfd, &repeats, sizeof(repeats));
768 if (read_ret != 8)
769 return;
770
771 incrementCursorImage(_glfw.wl.pointerFocus);
772 }
773 }
774 else
775 {
776 wl_display_cancel_read(display);
777 }
778}
779
783
785 const _GLFWwndconfig* wndconfig,
786 const _GLFWctxconfig* ctxconfig,
787 const _GLFWfbconfig* fbconfig)
788{
789 window->wl.transparent = fbconfig->transparent;
790
791 if (!createSurface(window, wndconfig))
792 return GLFW_FALSE;
793
794 if (ctxconfig->client != GLFW_NO_API)
795 {
796 if (ctxconfig->source == GLFW_EGL_CONTEXT_API ||
797 ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
798 {
799 if (!_glfwInitEGL())
800 return GLFW_FALSE;
801 if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
802 return GLFW_FALSE;
803 }
804 else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
805 {
806 if (!_glfwInitOSMesa())
807 return GLFW_FALSE;
808 if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
809 return GLFW_FALSE;
810 }
811 }
812
813 if (wndconfig->title)
814 window->wl.title = _glfw_strdup(wndconfig->title);
815
816 if (wndconfig->visible)
817 {
818 if (!createXdgSurface(window))
819 return GLFW_FALSE;
820
821 window->wl.visible = GLFW_TRUE;
822 }
823 else
824 {
825 window->wl.xdg.surface = NULL;
826 window->wl.xdg.toplevel = NULL;
827 window->wl.visible = GLFW_FALSE;
828 }
829
830 window->wl.currentCursor = NULL;
831
832 window->wl.monitors = calloc(1, sizeof(_GLFWmonitor*));
833 window->wl.monitorsCount = 0;
834 window->wl.monitorsSize = 1;
835
836 return GLFW_TRUE;
837}
838
840{
841 if (window == _glfw.wl.pointerFocus)
842 {
843 _glfw.wl.pointerFocus = NULL;
845 }
846 if (window == _glfw.wl.keyboardFocus)
847 {
848 _glfw.wl.keyboardFocus = NULL;
850 }
851
852 if (window->wl.idleInhibitor)
853 zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor);
854
855 if (window->context.destroy)
856 window->context.destroy(window);
857
858 destroyDecorations(window);
859 if (window->wl.xdg.decoration)
860 zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration);
861
862 if (window->wl.decorations.buffer)
863 wl_buffer_destroy(window->wl.decorations.buffer);
864
865 if (window->wl.native)
866 wl_egl_window_destroy(window->wl.native);
867
868 if (window->wl.xdg.toplevel)
869 xdg_toplevel_destroy(window->wl.xdg.toplevel);
870
871 if (window->wl.xdg.surface)
872 xdg_surface_destroy(window->wl.xdg.surface);
873
874 if (window->wl.surface)
875 wl_surface_destroy(window->wl.surface);
876
877 free(window->wl.title);
878 free(window->wl.monitors);
879}
880
881void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
882{
883 if (window->wl.title)
884 free(window->wl.title);
885 window->wl.title = _glfw_strdup(title);
886 if (window->wl.xdg.toplevel)
887 xdg_toplevel_set_title(window->wl.xdg.toplevel, title);
888}
889
891 int count, const GLFWimage* images)
892{
894 "Wayland: The platform does not support setting the window icon");
895}
896
897void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
898{
899 // A Wayland client is not aware of its position, so just warn and leave it
900 // as (0, 0)
901
903 "Wayland: The platform does not provide the window position");
904}
905
906void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
907{
908 // A Wayland client can not set its position, so just warn
909
911 "Wayland: The platform does not support setting the window position");
912}
913
914void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
915{
916 if (width)
917 *width = window->wl.width;
918 if (height)
919 *height = window->wl.height;
920}
921
922void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
923{
924 window->wl.width = width;
925 window->wl.height = height;
926 resizeWindow(window);
927}
928
930 int minwidth, int minheight,
931 int maxwidth, int maxheight)
932{
933 if (window->wl.xdg.toplevel)
934 {
935 if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE)
936 minwidth = minheight = 0;
937 if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)
938 maxwidth = maxheight = 0;
939 xdg_toplevel_set_min_size(window->wl.xdg.toplevel, minwidth, minheight);
940 xdg_toplevel_set_max_size(window->wl.xdg.toplevel, maxwidth, maxheight);
941 wl_surface_commit(window->wl.surface);
942 }
943}
944
946 int numer, int denom)
947{
948 // TODO: find out how to trigger a resize.
949 // The actual limits are checked in the xdg_toplevel::configure handler.
951 "Wayland: Window aspect ratio not yet implemented");
952}
953
955 int* width, int* height)
956{
957 _glfwPlatformGetWindowSize(window, width, height);
958 if (width)
959 *width *= window->wl.scale;
960 if (height)
961 *height *= window->wl.scale;
962}
963
965 int* left, int* top,
966 int* right, int* bottom)
967{
968 if (window->decorated && !window->monitor && !window->wl.decorations.serverSide)
969 {
970 if (top)
972 if (left)
974 if (right)
975 *right = _GLFW_DECORATION_WIDTH;
976 if (bottom)
977 *bottom = _GLFW_DECORATION_WIDTH;
978 }
979}
980
982 float* xscale, float* yscale)
983{
984 if (xscale)
985 *xscale = (float) window->wl.scale;
986 if (yscale)
987 *yscale = (float) window->wl.scale;
988}
989
991{
992 if (window->wl.xdg.toplevel)
993 xdg_toplevel_set_minimized(window->wl.xdg.toplevel);
994}
995
997{
998 if (window->wl.xdg.toplevel)
999 {
1000 if (window->monitor)
1001 xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);
1002 if (window->wl.maximized)
1003 xdg_toplevel_unset_maximized(window->wl.xdg.toplevel);
1004 // There is no way to unset minimized, or even to know if we are
1005 // minimized, so there is nothing to do in this case.
1006 }
1008 window->wl.maximized = GLFW_FALSE;
1009}
1010
1012{
1013 if (window->wl.xdg.toplevel)
1014 {
1015 xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
1016 }
1017 window->wl.maximized = GLFW_TRUE;
1018}
1019
1021{
1022 if (!window->wl.visible)
1023 {
1024 createXdgSurface(window);
1025 window->wl.visible = GLFW_TRUE;
1026 }
1027}
1028
1030{
1031 if (window->wl.xdg.toplevel)
1032 {
1033 xdg_toplevel_destroy(window->wl.xdg.toplevel);
1034 xdg_surface_destroy(window->wl.xdg.surface);
1035 window->wl.xdg.toplevel = NULL;
1036 window->wl.xdg.surface = NULL;
1037 }
1038 window->wl.visible = GLFW_FALSE;
1039}
1040
1042{
1043 // TODO
1045 "Wayland: Window attention request not implemented yet");
1046}
1047
1049{
1051 "Wayland: The platform does not support setting the input focus");
1052}
1053
1055 _GLFWmonitor* monitor,
1056 int xpos, int ypos,
1057 int width, int height,
1058 int refreshRate)
1059{
1060 if (monitor)
1061 {
1062 setFullscreen(window, monitor, refreshRate);
1063 }
1064 else
1065 {
1066 if (window->wl.xdg.toplevel)
1067 xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);
1068 setIdleInhibitor(window, GLFW_FALSE);
1069 if (!_glfw.wl.decorationManager)
1070 createDecorations(window);
1071 }
1072 _glfwInputWindowMonitor(window, monitor);
1073}
1074
1076{
1077 return _glfw.wl.keyboardFocus == window;
1078}
1079
1081{
1082 // xdg-shell doesn’t give any way to request whether a surface is
1083 // iconified.
1084 return GLFW_FALSE;
1085}
1086
1088{
1089 return window->wl.visible;
1090}
1091
1093{
1094 return window->wl.maximized;
1095}
1096
1098{
1099 return window->wl.hovered;
1100}
1101
1103{
1104 return window->wl.transparent;
1105}
1106
1108{
1109 // TODO
1111 "Wayland: Window attribute setting not implemented yet");
1112}
1113
1115{
1116 if (!window->monitor)
1117 {
1118 if (enabled)
1119 createDecorations(window);
1120 else
1121 destroyDecorations(window);
1122 }
1123}
1124
1126{
1127 // TODO
1129 "Wayland: Window attribute setting not implemented yet");
1130}
1131
1133{
1134 if (enabled)
1135 {
1136 struct wl_region* region = wl_compositor_create_region(_glfw.wl.compositor);
1137 wl_surface_set_input_region(window->wl.surface, region);
1138 wl_region_destroy(region);
1139 }
1140 else
1141 wl_surface_set_input_region(window->wl.surface, 0);
1142 wl_surface_commit(window->wl.surface);
1143}
1144
1146{
1147 return 1.f;
1148}
1149
1150void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
1151{
1153 "Wayland: The platform does not support setting the window opacity");
1154}
1155
1157{
1158 // This is handled in relativePointerHandleRelativeMotion
1159}
1160
1162{
1163 return GLFW_TRUE;
1164}
1165
1167{
1168 handleEvents(0);
1169}
1170
1172{
1173 handleEvents(-1);
1174}
1175
1177{
1178 handleEvents((int) (timeout * 1e3));
1179}
1180
1182{
1183 wl_display_sync(_glfw.wl.display);
1184}
1185
1186void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
1187{
1188 if (xpos)
1189 *xpos = window->wl.cursorPosX;
1190 if (ypos)
1191 *ypos = window->wl.cursorPosY;
1192}
1193
1194static GLFWbool isPointerLocked(_GLFWwindow* window);
1195
1196void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
1197{
1198 if (isPointerLocked(window))
1199 {
1200 zwp_locked_pointer_v1_set_cursor_position_hint(
1201 window->wl.pointerLock.lockedPointer,
1202 wl_fixed_from_double(x), wl_fixed_from_double(y));
1203 wl_surface_commit(window->wl.surface);
1204 }
1205}
1206
1208{
1209 _glfwPlatformSetCursor(window, window->wl.currentCursor);
1210}
1211
1212const char* _glfwPlatformGetScancodeName(int scancode)
1213{
1214 // TODO
1216 "Wayland: Key names not yet implemented");
1217 return NULL;
1218}
1219
1221{
1222 return _glfw.wl.scancodes[key];
1223}
1224
1226 const GLFWimage* image,
1227 int xhot, int yhot)
1228{
1229 cursor->wl.buffer = createShmBuffer(image);
1230 if (!cursor->wl.buffer)
1231 return GLFW_FALSE;
1232
1233 cursor->wl.width = image->width;
1234 cursor->wl.height = image->height;
1235 cursor->wl.xhot = xhot;
1236 cursor->wl.yhot = yhot;
1237 return GLFW_TRUE;
1238}
1239
1241{
1242 const char* name = NULL;
1243
1244 // Try the XDG names first
1245 switch (shape)
1246 {
1247 case GLFW_ARROW_CURSOR:
1248 name = "default";
1249 break;
1250 case GLFW_IBEAM_CURSOR:
1251 name = "text";
1252 break;
1254 name = "crosshair";
1255 break;
1257 name = "pointer";
1258 break;
1260 name = "ew-resize";
1261 break;
1263 name = "ns-resize";
1264 break;
1266 name = "nwse-resize";
1267 break;
1269 name = "nesw-resize";
1270 break;
1272 name = "all-scroll";
1273 break;
1275 name = "not-allowed";
1276 break;
1277 }
1278
1279 cursor->wl.cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, name);
1280
1281 if (_glfw.wl.cursorThemeHiDPI)
1282 {
1283 cursor->wl.cursorHiDPI =
1284 wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, name);
1285 }
1286
1287 if (!cursor->wl.cursor)
1288 {
1289 // Fall back to the core X11 names
1290 switch (shape)
1291 {
1292 case GLFW_ARROW_CURSOR:
1293 name = "left_ptr";
1294 case GLFW_IBEAM_CURSOR:
1295 name = "xterm";
1297 name = "crosshair";
1299 name = "hand2";
1301 name = "sb_h_double_arrow";
1303 name = "sb_v_double_arrow";
1305 name = "fleur";
1306 default:
1308 "Wayland: Standard cursor shape unavailable");
1309 return GLFW_FALSE;
1310 }
1311
1312 cursor->wl.cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, name);
1313 if (!cursor->wl.cursor)
1314 {
1316 "Wayland: Failed to create standard cursor \"%s\"",
1317 name);
1318 return GLFW_FALSE;
1319 }
1320
1321 if (_glfw.wl.cursorThemeHiDPI)
1322 {
1323 if (!cursor->wl.cursorHiDPI)
1324 {
1325 cursor->wl.cursorHiDPI =
1326 wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, name);
1327 }
1328 }
1329 }
1330
1331 return GLFW_TRUE;
1332}
1333
1335{
1336 // If it's a standard cursor we don't need to do anything here
1337 if (cursor->wl.cursor)
1338 return;
1339
1340 if (cursor->wl.buffer)
1341 wl_buffer_destroy(cursor->wl.buffer);
1342}
1343
1344static void relativePointerHandleRelativeMotion(void* data,
1345 struct zwp_relative_pointer_v1* pointer,
1346 uint32_t timeHi,
1347 uint32_t timeLo,
1348 wl_fixed_t dx,
1349 wl_fixed_t dy,
1350 wl_fixed_t dxUnaccel,
1351 wl_fixed_t dyUnaccel)
1352{
1353 _GLFWwindow* window = data;
1354 double xpos = window->virtualCursorPosX;
1355 double ypos = window->virtualCursorPosY;
1356
1357 if (window->cursorMode != GLFW_CURSOR_DISABLED)
1358 return;
1359
1360 if (window->rawMouseMotion)
1361 {
1362 xpos += wl_fixed_to_double(dxUnaccel);
1363 ypos += wl_fixed_to_double(dyUnaccel);
1364 }
1365 else
1366 {
1367 xpos += wl_fixed_to_double(dx);
1368 ypos += wl_fixed_to_double(dy);
1369 }
1370
1371 _glfwInputCursorPos(window, xpos, ypos);
1372}
1373
1374static const struct zwp_relative_pointer_v1_listener relativePointerListener = {
1375 relativePointerHandleRelativeMotion
1376};
1377
1378static void lockedPointerHandleLocked(void* data,
1379 struct zwp_locked_pointer_v1* lockedPointer)
1380{
1381}
1382
1383static void unlockPointer(_GLFWwindow* window)
1384{
1385 struct zwp_relative_pointer_v1* relativePointer =
1386 window->wl.pointerLock.relativePointer;
1387 struct zwp_locked_pointer_v1* lockedPointer =
1388 window->wl.pointerLock.lockedPointer;
1389
1390 zwp_relative_pointer_v1_destroy(relativePointer);
1391 zwp_locked_pointer_v1_destroy(lockedPointer);
1392
1393 window->wl.pointerLock.relativePointer = NULL;
1394 window->wl.pointerLock.lockedPointer = NULL;
1395}
1396
1397static void lockPointer(_GLFWwindow* window);
1398
1399static void lockedPointerHandleUnlocked(void* data,
1400 struct zwp_locked_pointer_v1* lockedPointer)
1401{
1402}
1403
1404static const struct zwp_locked_pointer_v1_listener lockedPointerListener = {
1405 lockedPointerHandleLocked,
1406 lockedPointerHandleUnlocked
1407};
1408
1409static void lockPointer(_GLFWwindow* window)
1410{
1411 struct zwp_relative_pointer_v1* relativePointer;
1412 struct zwp_locked_pointer_v1* lockedPointer;
1413
1414 if (!_glfw.wl.relativePointerManager)
1415 {
1417 "Wayland: no relative pointer manager");
1418 return;
1419 }
1420
1421 relativePointer =
1422 zwp_relative_pointer_manager_v1_get_relative_pointer(
1423 _glfw.wl.relativePointerManager,
1424 _glfw.wl.pointer);
1425 zwp_relative_pointer_v1_add_listener(relativePointer,
1426 &relativePointerListener,
1427 window);
1428
1429 lockedPointer =
1430 zwp_pointer_constraints_v1_lock_pointer(
1431 _glfw.wl.pointerConstraints,
1432 window->wl.surface,
1433 _glfw.wl.pointer,
1434 NULL,
1435 ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
1436 zwp_locked_pointer_v1_add_listener(lockedPointer,
1437 &lockedPointerListener,
1438 window);
1439
1440 window->wl.pointerLock.relativePointer = relativePointer;
1441 window->wl.pointerLock.lockedPointer = lockedPointer;
1442
1443 wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,
1444 NULL, 0, 0);
1445}
1446
1447static GLFWbool isPointerLocked(_GLFWwindow* window)
1448{
1449 return window->wl.pointerLock.lockedPointer != NULL;
1450}
1451
1453{
1454 struct wl_cursor* defaultCursor;
1455 struct wl_cursor* defaultCursorHiDPI = NULL;
1456
1457 if (!_glfw.wl.pointer)
1458 return;
1459
1460 window->wl.currentCursor = cursor;
1461
1462 // If we're not in the correct window just save the cursor
1463 // the next time the pointer enters the window the cursor will change
1464 if (window != _glfw.wl.pointerFocus || window->wl.decorations.focus != mainWindow)
1465 return;
1466
1467 // Unlock possible pointer lock if no longer disabled.
1468 if (window->cursorMode != GLFW_CURSOR_DISABLED && isPointerLocked(window))
1469 unlockPointer(window);
1470
1471 if (window->cursorMode == GLFW_CURSOR_NORMAL)
1472 {
1473 if (cursor)
1474 setCursorImage(window, &cursor->wl);
1475 else
1476 {
1477 defaultCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme,
1478 "left_ptr");
1479 if (!defaultCursor)
1480 {
1482 "Wayland: Standard cursor not found");
1483 return;
1484 }
1485 if (_glfw.wl.cursorThemeHiDPI)
1486 defaultCursorHiDPI =
1487 wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI,
1488 "left_ptr");
1489 _GLFWcursorWayland cursorWayland = {
1490 defaultCursor,
1491 defaultCursorHiDPI,
1492 NULL,
1493 0, 0,
1494 0, 0,
1495 0
1496 };
1497 setCursorImage(window, &cursorWayland);
1498 }
1499 }
1500 else if (window->cursorMode == GLFW_CURSOR_DISABLED)
1501 {
1502 if (!isPointerLocked(window))
1503 lockPointer(window);
1504 }
1505 else if (window->cursorMode == GLFW_CURSOR_HIDDEN)
1506 {
1507 wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, NULL, 0, 0);
1508 }
1509}
1510
1511static void dataSourceHandleTarget(void* data,
1512 struct wl_data_source* dataSource,
1513 const char* mimeType)
1514{
1515 if (_glfw.wl.dataSource != dataSource)
1516 {
1518 "Wayland: Unknown clipboard data source");
1519 return;
1520 }
1521}
1522
1523static void dataSourceHandleSend(void* data,
1524 struct wl_data_source* dataSource,
1525 const char* mimeType,
1526 int fd)
1527{
1528 const char* string = _glfw.wl.clipboardSendString;
1529 size_t len = _glfw.wl.clipboardSendSize;
1530 int ret;
1531
1532 if (_glfw.wl.dataSource != dataSource)
1533 {
1535 "Wayland: Unknown clipboard data source");
1536 return;
1537 }
1538
1539 if (!string)
1540 {
1542 "Wayland: Copy requested from an invalid string");
1543 return;
1544 }
1545
1546 if (strcmp(mimeType, "text/plain;charset=utf-8") != 0)
1547 {
1549 "Wayland: Wrong MIME type asked from clipboard");
1550 close(fd);
1551 return;
1552 }
1553
1554 while (len > 0)
1555 {
1556 ret = write(fd, string, len);
1557 if (ret == -1 && errno == EINTR)
1558 continue;
1559 if (ret == -1)
1560 {
1561 // TODO: also report errno maybe.
1563 "Wayland: Error while writing the clipboard");
1564 close(fd);
1565 return;
1566 }
1567 len -= ret;
1568 }
1569 close(fd);
1570}
1571
1572static void dataSourceHandleCancelled(void* data,
1573 struct wl_data_source* dataSource)
1574{
1575 wl_data_source_destroy(dataSource);
1576
1577 if (_glfw.wl.dataSource != dataSource)
1578 {
1580 "Wayland: Unknown clipboard data source");
1581 return;
1582 }
1583
1584 _glfw.wl.dataSource = NULL;
1585}
1586
1587static const struct wl_data_source_listener dataSourceListener = {
1588 dataSourceHandleTarget,
1589 dataSourceHandleSend,
1590 dataSourceHandleCancelled,
1591};
1592
1593void _glfwPlatformSetClipboardString(const char* string)
1594{
1595 if (_glfw.wl.dataSource)
1596 {
1597 wl_data_source_destroy(_glfw.wl.dataSource);
1598 _glfw.wl.dataSource = NULL;
1599 }
1600
1601 if (_glfw.wl.clipboardSendString)
1602 {
1603 free(_glfw.wl.clipboardSendString);
1604 _glfw.wl.clipboardSendString = NULL;
1605 }
1606
1607 _glfw.wl.clipboardSendString = strdup(string);
1608 if (!_glfw.wl.clipboardSendString)
1609 {
1611 "Wayland: Impossible to allocate clipboard string");
1612 return;
1613 }
1614 _glfw.wl.clipboardSendSize = strlen(string);
1615 _glfw.wl.dataSource =
1616 wl_data_device_manager_create_data_source(_glfw.wl.dataDeviceManager);
1617 if (!_glfw.wl.dataSource)
1618 {
1620 "Wayland: Impossible to create clipboard source");
1621 free(_glfw.wl.clipboardSendString);
1622 return;
1623 }
1624 wl_data_source_add_listener(_glfw.wl.dataSource,
1625 &dataSourceListener,
1626 NULL);
1627 wl_data_source_offer(_glfw.wl.dataSource, "text/plain;charset=utf-8");
1628 wl_data_device_set_selection(_glfw.wl.dataDevice,
1629 _glfw.wl.dataSource,
1630 _glfw.wl.serial);
1631}
1632
1633static GLFWbool growClipboardString(void)
1634{
1635 char* clipboard = _glfw.wl.clipboardString;
1636
1637 clipboard = realloc(clipboard, _glfw.wl.clipboardSize * 2);
1638 if (!clipboard)
1639 {
1641 "Wayland: Impossible to grow clipboard string");
1642 return GLFW_FALSE;
1643 }
1644 _glfw.wl.clipboardString = clipboard;
1645 _glfw.wl.clipboardSize = _glfw.wl.clipboardSize * 2;
1646 return GLFW_TRUE;
1647}
1648
1650{
1651 int fds[2];
1652 int ret;
1653 size_t len = 0;
1654
1655 if (!_glfw.wl.dataOffer)
1656 {
1658 "No clipboard data has been sent yet");
1659 return NULL;
1660 }
1661
1662 ret = pipe2(fds, O_CLOEXEC);
1663 if (ret < 0)
1664 {
1665 // TODO: also report errno maybe?
1667 "Wayland: Impossible to create clipboard pipe fds");
1668 return NULL;
1669 }
1670
1671 wl_data_offer_receive(_glfw.wl.dataOffer, "text/plain;charset=utf-8", fds[1]);
1672 close(fds[1]);
1673
1674 // XXX: this is a huge hack, this function shouldn’t be synchronous!
1675 handleEvents(-1);
1676
1677 while (1)
1678 {
1679 // Grow the clipboard if we need to paste something bigger, there is no
1680 // shrink operation yet.
1681 if (len + 4096 > _glfw.wl.clipboardSize)
1682 {
1683 if (!growClipboardString())
1684 {
1685 close(fds[0]);
1686 return NULL;
1687 }
1688 }
1689
1690 // Then read from the fd to the clipboard, handling all known errors.
1691 ret = read(fds[0], _glfw.wl.clipboardString + len, 4096);
1692 if (ret == 0)
1693 break;
1694 if (ret == -1 && errno == EINTR)
1695 continue;
1696 if (ret == -1)
1697 {
1698 // TODO: also report errno maybe.
1700 "Wayland: Impossible to read from clipboard fd");
1701 close(fds[0]);
1702 return NULL;
1703 }
1704 len += ret;
1705 }
1706 close(fds[0]);
1707 if (len + 1 > _glfw.wl.clipboardSize)
1708 {
1709 if (!growClipboardString())
1710 return NULL;
1711 }
1712 _glfw.wl.clipboardString[len] = '\0';
1713 return _glfw.wl.clipboardString;
1714}
1715
1717{
1720 else
1721 return 0;
1722}
1723
1725{
1726 return _glfw.wl.display;
1727}
1728
1730{
1731 return window->wl.native;
1732}
1733
1735{
1736 if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_wayland_surface)
1737 return;
1738
1739 extensions[0] = "VK_KHR_surface";
1740 extensions[1] = "VK_KHR_wayland_surface";
1741}
1742
1744 VkPhysicalDevice device,
1745 uint32_t queuefamily)
1746{
1748 vkGetPhysicalDeviceWaylandPresentationSupportKHR =
1750 vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR");
1751 if (!vkGetPhysicalDeviceWaylandPresentationSupportKHR)
1752 {
1754 "Wayland: Vulkan instance missing VK_KHR_wayland_surface extension");
1755 return VK_NULL_HANDLE;
1756 }
1757
1758 return vkGetPhysicalDeviceWaylandPresentationSupportKHR(device,
1759 queuefamily,
1760 _glfw.wl.display);
1761}
1762
1764 _GLFWwindow* window,
1765 const VkAllocationCallbacks* allocator,
1766 VkSurfaceKHR* surface)
1767{
1768 VkResult err;
1770 PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR;
1771
1772 vkCreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR)
1773 vkGetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR");
1774 if (!vkCreateWaylandSurfaceKHR)
1775 {
1777 "Wayland: Vulkan instance missing VK_KHR_wayland_surface extension");
1779 }
1780
1781 memset(&sci, 0, sizeof(sci));
1783 sci.display = _glfw.wl.display;
1784 sci.surface = window->wl.surface;
1785
1786 err = vkCreateWaylandSurfaceKHR(instance, &sci, allocator, surface);
1787 if (err)
1788 {
1790 "Wayland: Failed to create Vulkan surface: %s",
1792 }
1793
1794 return err;
1795}
1796
1797
1801
1802GLFWAPI struct wl_display* glfwGetWaylandDisplay(void)
1803{
1805 return _glfw.wl.display;
1806}
1807
1808GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* handle)
1809{
1810 _GLFWwindow* window = (_GLFWwindow*) handle;
1812 return window->wl.surface;
1813}
1814
GLFWbool _glfwInitEGL(void)
Definition: egl_context.c:303
GLFWbool _glfwCreateContextEGL(_GLFWwindow *window, const _GLFWctxconfig *ctxconfig, const _GLFWfbconfig *fbconfig)
Definition: egl_context.c:505
unsigned int EGLenum
Definition: egl_context.h:109
void * EGLNativeDisplayType
Definition: egl_context.h:115
void * EGLNativeWindowType
Definition: egl_context.h:116
#define EGL_PLATFORM_WAYLAND_EXT
Definition: egl_context.h:96
int EGLint
Definition: egl_context.h:107
#define GLFW_EGL_CONTEXT_API
Definition: glfw3.h:1113
#define GLFW_NATIVE_CONTEXT_API
Definition: glfw3.h:1112
#define GLFW_CURSOR_DISABLED
Definition: glfw3.h:1106
#define GLFWAPI
Definition: glfw3.h:269
#define GLFW_DONT_CARE
Definition: glfw3.h:1262
#define GLFW_NO_API
Definition: glfw3.h:1086
#define GLFW_CURSOR_HIDDEN
Definition: glfw3.h:1105
#define GLFW_CURSOR_NORMAL
Definition: glfw3.h:1104
#define GLFW_OSMESA_CONTEXT_API
Definition: glfw3.h:1114
#define GLFW_CURSOR_UNAVAILABLE
The specified cursor shape is not available.
Definition: glfw3.h:796
#define GLFW_FORMAT_UNAVAILABLE
The requested format is not supported or available.
Definition: glfw3.h:777
#define GLFW_FEATURE_UNAVAILABLE
The requested feature is not provided by the platform.
Definition: glfw3.h:810
#define GLFW_API_UNAVAILABLE
GLFW could not find support for the requested API on the system.
Definition: glfw3.h:730
#define GLFW_FEATURE_UNIMPLEMENTED
The requested feature is not implemented for the platform.
Definition: glfw3.h:823
#define GLFW_PLATFORM_ERROR
A platform-specific error occurred that does not match any of the more specific categories.
Definition: glfw3.h:758
#define GLFW_TRUE
One.
Definition: glfw3.h:310
#define GLFW_FALSE
Zero.
Definition: glfw3.h:319
#define GLFW_REPEAT
The key was held down until it repeated.
Definition: glfw3.h:343
#define GLFW_RESIZE_EW_CURSOR
The horizontal resize/move arrow shape.
Definition: glfw3.h:1158
#define GLFW_NOT_ALLOWED_CURSOR
The operation-not-allowed shape.
Definition: glfw3.h:1212
#define GLFW_IBEAM_CURSOR
The text input I-beam cursor shape.
Definition: glfw3.h:1142
#define GLFW_RESIZE_ALL_CURSOR
The omni-directional resize/move cursor shape.
Definition: glfw3.h:1200
#define GLFW_ARROW_CURSOR
The regular arrow cursor shape.
Definition: glfw3.h:1137
#define GLFW_CROSSHAIR_CURSOR
The crosshair cursor shape.
Definition: glfw3.h:1147
#define GLFW_RESIZE_NS_CURSOR
The vertical resize/move arrow shape.
Definition: glfw3.h:1164
#define GLFW_POINTING_HAND_CURSOR
The pointing hand cursor shape.
Definition: glfw3.h:1152
#define GLFW_RESIZE_NESW_CURSOR
The top-right to bottom-left diagonal resize/move arrow shape.
Definition: glfw3.h:1194
#define GLFW_RESIZE_NWSE_CURSOR
The top-left to bottom-right diagonal resize/move arrow shape.
Definition: glfw3.h:1179
struct GLFWwindow GLFWwindow
Opaque window object.
Definition: glfw3.h:1319
_GLFWlibrary _glfw
Definition: init.c:46
void _glfwInputError(int code, const char *format,...)
Definition: init.c:160
char * _glfw_strdup(const char *source)
Definition: init.c:121
void _glfwInputCursorEnter(_GLFWwindow *window, GLFWbool entered)
Definition: input.c:370
void _glfwInputCursorPos(_GLFWwindow *window, double xpos, double ypos)
Definition: input.c:356
void _glfwInputKey(_GLFWwindow *window, int key, int scancode, int action, int mods)
Definition: input.c:277
uint64_t VkSurfaceKHR
Definition: internal.h:120
void _glfwInputFramebufferSize(_GLFWwindow *window, int width, int height)
Definition: window.c:108
void * VkInstance
Definition: internal.h:118
void _glfwInputWindowSize(_GLFWwindow *window, int width, int height)
Definition: window.c:83
void _glfwInputWindowMonitor(_GLFWwindow *window, _GLFWmonitor *monitor)
Definition: window.c:143
#define _GLFW_REQUIRE_INIT_OR_RETURN(x)
Definition: internal.h:214
void * VkPhysicalDevice
Definition: internal.h:119
const char * _glfwGetVulkanResultString(VkResult result)
Definition: vulkan.c:165
void _glfwInputWindowContentScale(_GLFWwindow *window, float xscale, float yscale)
Definition: window.c:117
int GLFWbool
Definition: internal.h:61
void _glfwInputWindowDamage(_GLFWwindow *window)
Definition: window.c:125
void _glfwInputWindowCloseRequest(_GLFWwindow *window)
Definition: window.c:133
void _glfwInputWindowFocus(_GLFWwindow *window, GLFWbool focused)
Definition: window.c:45
@ VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR
Definition: internal.h:128
#define NULL
Definition: miniaudio.h:3718
GLFWbool _glfwCreateContextOSMesa(_GLFWwindow *window, const _GLFWctxconfig *ctxconfig, const _GLFWfbconfig *fbconfig)
GLFWbool _glfwInitOSMesa(void)
unsigned int uint32_t
Definition: stdint.h:80
signed int int32_t
Definition: stdint.h:77
unsigned __int64 uint64_t
Definition: stdint.h:90
_GLFWdestroycontextfun destroy
Definition: internal.h:365
struct wl_buffer * buffer
Definition: wl_platform.h:344
struct wl_cursor * cursor
Definition: wl_platform.h:342
struct wl_cursor * cursorHiDPI
Definition: wl_platform.h:343
struct wl_subsurface * subsurface
Definition: wl_platform.h:162
struct wp_viewport * viewport
Definition: wl_platform.h:163
struct wl_surface * surface
Definition: wl_platform.h:161
GLFWbool transparent
Definition: internal.h:340
GLFWbool EXT_platform_wayland
Definition: egl_context.h:186
GLFWbool EXT_platform_base
Definition: egl_context.h:184
_GLFWlibraryEGL egl
Definition: internal.h:595
struct _GLFWlibrary::@25 vk
GLFWbool KHR_surface
Definition: internal.h:569
_GLFWwindow * windowListHead
Definition: internal.h:541
int minwidth
Definition: internal.h:395
int minheight
Definition: internal.h:395
int cursorMode
Definition: internal.h:402
double virtualCursorPosY
Definition: internal.h:406
_GLFWmonitor * monitor
Definition: internal.h:392
double virtualCursorPosX
Definition: internal.h:406
struct _GLFWwindow * next
Definition: internal.h:379
int maxheight
Definition: internal.h:396
GLFWbool decorated
Definition: internal.h:383
int maxwidth
Definition: internal.h:396
GLFWbool rawMouseMotion
Definition: internal.h:407
GLFWbool autoIconify
Definition: internal.h:384
GLFWwindowcontentscalefun scale
Definition: internal.h:420
GLFWwindowfocusfun focus
Definition: internal.h:416
_GLFWcontext context
Definition: internal.h:409
const char * title
Definition: internal.h:266
GLFWbool visible
Definition: internal.h:268
Image data.
Definition: glfw3.h:1855
int height
Definition: glfw3.h:1861
unsigned char * pixels
Definition: glfw3.h:1864
int width
Definition: glfw3.h:1858
struct wl_display * display
Definition: wl_platform.h:41
struct wl_surface * surface
Definition: wl_platform.h:42
uint32_t hotspot_y
Definition: wl_platform.h:80
uint32_t hotspot_x
Definition: wl_platform.h:79
uint32_t height
Definition: wl_platform.h:78
uint32_t width
Definition: wl_platform.h:77
uint32_t delay
Definition: wl_platform.h:81
struct wl_cursor_image ** images
Definition: wl_platform.h:85
VkResult
Definition: vulkan.h:842
@ VK_ERROR_EXTENSION_NOT_PRESENT
Definition: vulkan.h:855
#define VK_NULL_HANDLE
Definition: vulkan.h:208
#define vkGetInstanceProcAddr
Definition: vulkan.h:3378
#define _GLFW_DECORATION_HORIZONTAL
Definition: wl_platform.h:147
#define wl_cursor_image_get_buffer
Definition: wl_platform.h:95
VkResult(APIENTRY * PFN_vkCreateWaylandSurfaceKHR)(VkInstance, const VkWaylandSurfaceCreateInfoKHR *, const VkAllocationCallbacks *, VkSurfaceKHR *)
Definition: wl_platform.h:45
#define wl_cursor_theme_get_cursor
Definition: wl_platform.h:94
#define wl_egl_window_resize
Definition: wl_platform.h:102
#define _GLFW_DECORATION_WIDTH
Definition: wl_platform.h:144
VkBool32(APIENTRY * PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice, uint32_t, struct wl_display *)
Definition: wl_platform.h:46
#define wl_egl_window_create
Definition: wl_platform.h:100
#define _GLFW_DECORATION_TOP
Definition: wl_platform.h:145
@ mainWindow
Definition: wl_platform.h:151
#define wl_egl_window_destroy
Definition: wl_platform.h:101
void _glfwPlatformSetWindowMonitor(_GLFWwindow *window, _GLFWmonitor *monitor, int xpos, int ypos, int width, int height, int refreshRate)
Definition: wl_window.c:1054
void _glfwPlatformSetWindowPos(_GLFWwindow *window, int xpos, int ypos)
Definition: wl_window.c:906
void _glfwPlatformGetWindowContentScale(_GLFWwindow *window, float *xscale, float *yscale)
Definition: wl_window.c:981
void _glfwPlatformSetCursorPos(_GLFWwindow *window, double x, double y)
Definition: wl_window.c:1196
void _glfwPlatformSetWindowResizable(_GLFWwindow *window, GLFWbool enabled)
Definition: wl_window.c:1107
int _glfwPlatformWindowIconified(_GLFWwindow *window)
Definition: wl_window.c:1080
void _glfwPlatformMaximizeWindow(_GLFWwindow *window)
Definition: wl_window.c:1011
EGLenum _glfwPlatformGetEGLPlatform(EGLint **attribs)
Definition: wl_window.c:1716
void _glfwPlatformIconifyWindow(_GLFWwindow *window)
Definition: wl_window.c:990
void _glfwPlatformSetWindowSize(_GLFWwindow *window, int width, int height)
Definition: wl_window.c:922
void _glfwPlatformWaitEvents(void)
Definition: wl_window.c:1171
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow *window, int minwidth, int minheight, int maxwidth, int maxheight)
Definition: wl_window.c:929
void _glfwPlatformGetRequiredInstanceExtensions(char **extensions)
Definition: wl_window.c:1734
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow *window, const VkAllocationCallbacks *allocator, VkSurfaceKHR *surface)
Definition: wl_window.c:1763
int _glfwPlatformFramebufferTransparent(_GLFWwindow *window)
Definition: wl_window.c:1102
int _glfwPlatformCreateCursor(_GLFWcursor *cursor, const GLFWimage *image, int xhot, int yhot)
Definition: wl_window.c:1225
void _glfwPlatformPollEvents(void)
Definition: wl_window.c:1166
void _glfwPlatformGetFramebufferSize(_GLFWwindow *window, int *width, int *height)
Definition: wl_window.c:954
int _glfwPlatformWindowVisible(_GLFWwindow *window)
Definition: wl_window.c:1087
void _glfwPlatformSetCursor(_GLFWwindow *window, _GLFWcursor *cursor)
Definition: wl_window.c:1452
void _glfwPlatformGetWindowSize(_GLFWwindow *window, int *width, int *height)
Definition: wl_window.c:914
GLFWAPI struct wl_surface * glfwGetWaylandWindow(GLFWwindow *handle)
Definition: wl_window.c:1808
void _glfwPlatformGetWindowFrameSize(_GLFWwindow *window, int *left, int *top, int *right, int *bottom)
Definition: wl_window.c:964
void _glfwPlatformSetWindowIcon(_GLFWwindow *window, int count, const GLFWimage *images)
Definition: wl_window.c:890
EGLNativeWindowType _glfwPlatformGetEGLNativeWindow(_GLFWwindow *window)
Definition: wl_window.c:1729
const char * _glfwPlatformGetScancodeName(int scancode)
Definition: wl_window.c:1212
void _glfwPlatformSetWindowDecorated(_GLFWwindow *window, GLFWbool enabled)
Definition: wl_window.c:1114
void _glfwPlatformGetWindowPos(_GLFWwindow *window, int *xpos, int *ypos)
Definition: wl_window.c:897
void _glfwPlatformSetWindowOpacity(_GLFWwindow *window, float opacity)
Definition: wl_window.c:1150
float _glfwPlatformGetWindowOpacity(_GLFWwindow *window)
Definition: wl_window.c:1145
void _glfwPlatformDestroyCursor(_GLFWcursor *cursor)
Definition: wl_window.c:1334
void _glfwPlatformRestoreWindow(_GLFWwindow *window)
Definition: wl_window.c:996
GLFWbool _glfwPlatformRawMouseMotionSupported(void)
Definition: wl_window.c:1161
void _glfwPlatformSetCursorMode(_GLFWwindow *window, int mode)
Definition: wl_window.c:1207
int _glfwPlatformWindowHovered(_GLFWwindow *window)
Definition: wl_window.c:1097
void _glfwPlatformDestroyWindow(_GLFWwindow *window)
Definition: wl_window.c:839
void _glfwPlatformWaitEventsTimeout(double timeout)
Definition: wl_window.c:1176
void _glfwPlatformHideWindow(_GLFWwindow *window)
Definition: wl_window.c:1029
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily)
Definition: wl_window.c:1743
int _glfwPlatformWindowMaximized(_GLFWwindow *window)
Definition: wl_window.c:1092
void _glfwPlatformSetClipboardString(const char *string)
Definition: wl_window.c:1593
void _glfwPlatformShowWindow(_GLFWwindow *window)
Definition: wl_window.c:1020
void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, GLFWbool enabled)
Definition: wl_window.c:1156
int _glfwPlatformWindowFocused(_GLFWwindow *window)
Definition: wl_window.c:1075
void _glfwPlatformPostEmptyEvent(void)
Definition: wl_window.c:1181
int _glfwPlatformGetKeyScancode(int key)
Definition: wl_window.c:1220
int _glfwPlatformCreateStandardCursor(_GLFWcursor *cursor, int shape)
Definition: wl_window.c:1240
int _glfwPlatformCreateWindow(_GLFWwindow *window, const _GLFWwndconfig *wndconfig, const _GLFWctxconfig *ctxconfig, const _GLFWfbconfig *fbconfig)
Definition: wl_window.c:784
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow *window, int numer, int denom)
Definition: wl_window.c:945
const char * _glfwPlatformGetClipboardString(void)
Definition: wl_window.c:1649
void _glfwPlatformGetCursorPos(_GLFWwindow *window, double *xpos, double *ypos)
Definition: wl_window.c:1186
void _glfwPlatformRequestWindowAttention(_GLFWwindow *window)
Definition: wl_window.c:1041
EGLNativeDisplayType _glfwPlatformGetEGLNativeDisplay(void)
Definition: wl_window.c:1724
void _glfwPlatformSetWindowTitle(_GLFWwindow *window, const char *title)
Definition: wl_window.c:881
void _glfwPlatformFocusWindow(_GLFWwindow *window)
Definition: wl_window.c:1048
GLFWAPI struct wl_display * glfwGetWaylandDisplay(void)
Definition: wl_window.c:1802
void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow *window, GLFWbool enabled)
Definition: wl_window.c:1132
void _glfwPlatformSetWindowFloating(_GLFWwindow *window, GLFWbool enabled)
Definition: wl_window.c:1125