1/*
2 * Copyright © 2010 Intel Corporation
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "config.h"
19
20#include <stdlib.h>
21#include <string.h>
22#include <errno.h>
23#include <unistd.h>
24#include <fcntl.h>
25#include <linux/memfd.h>
26#include <sys/mman.h>
27#include <sys/syscall.h>
28
29#include <glib.h>
30#include "gdkwayland.h"
31#include "gdkdisplay.h"
32#include "gdkdisplay-wayland.h"
33#include "gdkscreen.h"
34#include "gdkinternals.h"
35#include "gdkdeviceprivate.h"
36#include "gdkdevicemanager.h"
37#include "gdkkeysprivate.h"
38#include "gdkprivate-wayland.h"
39#include "gdkglcontext-wayland.h"
40#include "gdkwaylandmonitor.h"
41#include "pointer-gestures-unstable-v1-client-protocol.h"
42#include "tablet-unstable-v1-client-protocol.h"
43
44/**
45 * SECTION:wayland_interaction
46 * @Short_description: Wayland backend-specific functions
47 * @Title: Wayland Interaction
48 *
49 * The functions in this section are specific to the GDK Wayland backend.
50 * To use them, you need to include the `<gdk/gdkwayland.h>` header and use
51 * the Wayland-specific pkg-config files to build your application (either
52 * `gdk-wayland-3.0` or `gtk+-wayland-3.0`).
53 *
54 * To make your code compile with other GDK backends, guard backend-specific
55 * calls by an ifdef as follows. Since GDK may be built with multiple
56 * backends, you should also check for the backend that is in use (e.g. by
57 * using the GDK_IS_WAYLAND_DISPLAY() macro).
58 * |[<!-- language="C" -->
59 * #ifdef GDK_WINDOWING_WAYLAND
60 * if (GDK_IS_WAYLAND_DISPLAY (display))
61 * {
62 * // make Wayland-specific calls here
63 * }
64 * else
65 * #endif
66 * #ifdef GDK_WINDOWING_X11
67 * if (GDK_IS_X11_DISPLAY (display))
68 * {
69 * // make X11-specific calls here
70 * }
71 * else
72 * #endif
73 * g_error ("Unsupported GDK backend");
74 * ]|
75 */
76
77static void _gdk_wayland_display_load_cursor_theme (GdkWaylandDisplay *display_wayland);
78
79G_DEFINE_TYPE (GdkWaylandDisplay, gdk_wayland_display, GDK_TYPE_DISPLAY)
80
81static void
82async_roundtrip_callback (void *data,
83 struct wl_callback *callback,
84 uint32_t time)
85{
86 GdkWaylandDisplay *display_wayland = data;
87
88 display_wayland->async_roundtrips =
89 g_list_remove (display_wayland->async_roundtrips, callback);
90 wl_callback_destroy (callback);
91}
92
93static const struct wl_callback_listener async_roundtrip_listener = {
94 async_roundtrip_callback
95};
96
97static void
98_gdk_wayland_display_async_roundtrip (GdkWaylandDisplay *display_wayland)
99{
100 struct wl_callback *callback;
101
102 callback = wl_display_sync (display_wayland->wl_display);
103 wl_callback_add_listener (callback,
104 &async_roundtrip_listener,
105 display_wayland);
106 display_wayland->async_roundtrips =
107 g_list_append (display_wayland->async_roundtrips, callback);
108}
109
110static void
111xdg_shell_ping (void *data,
112 struct xdg_shell *xdg_shell,
113 uint32_t serial)
114{
115 GdkWaylandDisplay *display_wayland = data;
116
117 _gdk_wayland_display_update_serial (display_wayland, serial);
118
119 GDK_NOTE (EVENTS,
120 g_message ("ping, shell %p, serial %u\n", xdg_shell, serial));
121
122 xdg_shell_pong (xdg_shell, serial);
123}
124
125static const struct xdg_shell_listener xdg_shell_listener = {
126 xdg_shell_ping,
127};
128
129static gboolean
130is_known_global (gpointer key, gpointer value, gpointer user_data)
131{
132 const char *required_global = user_data;
133 const char *known_global = value;
134
135 return g_strcmp0 (required_global, known_global) == 0;
136}
137
138static gboolean
139has_required_globals (GdkWaylandDisplay *display_wayland,
140 const char *required_globals[])
141{
142 int i = 0;
143
144 while (required_globals[i])
145 {
146 if (g_hash_table_find (display_wayland->known_globals,
147 is_known_global,
148 (gpointer)required_globals[i]) == NULL)
149 return FALSE;
150
151 i++;
152 }
153
154 return TRUE;
155}
156
157typedef struct _OnHasGlobalsClosure OnHasGlobalsClosure;
158
159typedef void (*HasGlobalsCallback) (GdkWaylandDisplay *display_wayland,
160 OnHasGlobalsClosure *closure);
161
162struct _OnHasGlobalsClosure
163{
164 HasGlobalsCallback handler;
165 const char **required_globals;
166};
167
168static void
169process_on_globals_closures (GdkWaylandDisplay *display_wayland)
170{
171 GList *iter;
172
173 iter = display_wayland->on_has_globals_closures;
174 while (iter != NULL)
175 {
176 GList *next = iter->next;
177 OnHasGlobalsClosure *closure = iter->data;
178
179 if (has_required_globals (display_wayland,
180 closure->required_globals))
181 {
182 closure->handler (display_wayland, closure);
183 g_free (closure);
184 display_wayland->on_has_globals_closures =
185 g_list_delete_link (display_wayland->on_has_globals_closures, iter);
186 }
187
188 iter = next;
189 }
190}
191
192typedef struct
193{
194 OnHasGlobalsClosure base;
195 uint32_t id;
196 uint32_t version;
197} SeatAddedClosure;
198
199static void
200_gdk_wayland_display_add_seat (GdkWaylandDisplay *display_wayland,
201 uint32_t id,
202 uint32_t version)
203{
204 GdkDisplay *gdk_display = GDK_DISPLAY_OBJECT (display_wayland);
205 struct wl_seat *seat;
206
207 display_wayland->seat_version = MIN (version, 5);
208 seat = wl_registry_bind (display_wayland->wl_registry,
209 id, &wl_seat_interface,
210 display_wayland->seat_version);
211 _gdk_wayland_device_manager_add_seat (gdk_display->device_manager,
212 id, seat);
213 _gdk_wayland_display_async_roundtrip (display_wayland);
214}
215
216static void
217seat_added_closure_run (GdkWaylandDisplay *display_wayland,
218 OnHasGlobalsClosure *closure)
219{
220 SeatAddedClosure *seat_added_closure = (SeatAddedClosure*)closure;
221
222 _gdk_wayland_display_add_seat (display_wayland,
223 seat_added_closure->id,
224 seat_added_closure->version);
225}
226
227static void
228postpone_on_globals_closure (GdkWaylandDisplay *display_wayland,
229 OnHasGlobalsClosure *closure)
230{
231 display_wayland->on_has_globals_closures =
232 g_list_append (display_wayland->on_has_globals_closures, closure);
233}
234
235#ifdef G_ENABLE_DEBUG
236
237static const char *
238get_format_name (enum wl_shm_format format)
239{
240 int i;
241#define FORMAT(s) { WL_SHM_FORMAT_ ## s, #s }
242 struct { int format; const char *name; } formats[] = {
243 FORMAT(ARGB8888),
244 FORMAT(XRGB8888),
245 FORMAT(C8),
246 FORMAT(RGB332),
247 FORMAT(BGR233),
248 FORMAT(XRGB4444),
249 FORMAT(XBGR4444),
250 FORMAT(RGBX4444),
251 FORMAT(BGRX4444),
252 FORMAT(ARGB4444),
253 FORMAT(ABGR4444),
254 FORMAT(RGBA4444),
255 FORMAT(BGRA4444),
256 FORMAT(XRGB1555),
257 FORMAT(XBGR1555),
258 FORMAT(RGBX5551),
259 FORMAT(BGRX5551),
260 FORMAT(ARGB1555),
261 FORMAT(ABGR1555),
262 FORMAT(RGBA5551),
263 FORMAT(BGRA5551),
264 FORMAT(RGB565),
265 FORMAT(BGR565),
266 FORMAT(RGB888),
267 FORMAT(BGR888),
268 FORMAT(XBGR8888),
269 FORMAT(RGBX8888),
270 FORMAT(BGRX8888),
271 FORMAT(ABGR8888),
272 FORMAT(RGBA8888),
273 FORMAT(BGRA8888),
274 FORMAT(XRGB2101010),
275 FORMAT(XBGR2101010),
276 FORMAT(RGBX1010102),
277 FORMAT(BGRX1010102),
278 FORMAT(ARGB2101010),
279 FORMAT(ABGR2101010),
280 FORMAT(RGBA1010102),
281 FORMAT(BGRA1010102),
282 FORMAT(YUYV),
283 FORMAT(YVYU),
284 FORMAT(UYVY),
285 FORMAT(VYUY),
286 FORMAT(AYUV),
287 FORMAT(NV12),
288 FORMAT(NV21),
289 FORMAT(NV16),
290 FORMAT(NV61),
291 FORMAT(YUV410),
292 FORMAT(YVU410),
293 FORMAT(YUV411),
294 FORMAT(YVU411),
295 FORMAT(YUV420),
296 FORMAT(YVU420),
297 FORMAT(YUV422),
298 FORMAT(YVU422),
299 FORMAT(YUV444),
300 FORMAT(YVU444),
301 { 0xffffffff, NULL }
302 };
303#undef FORMAT
304
305 for (i = 0; formats[i].name; i++)
306 {
307 if (formats[i].format == format)
308 return formats[i].name;
309 }
310 return NULL;
311}
312#endif
313
314static void
315wl_shm_format (void *data,
316 struct wl_shm *wl_shm,
317 uint32_t format)
318{
319 GDK_NOTE (MISC, g_message ("supported pixel format %s", get_format_name (format)));
320}
321
322static const struct wl_shm_listener wl_shm_listener = {
323 wl_shm_format
324};
325
326static void
327gdk_registry_handle_global (void *data,
328 struct wl_registry *registry,
329 uint32_t id,
330 const char *interface,
331 uint32_t version)
332{
333 GdkWaylandDisplay *display_wayland = data;
334 struct wl_output *output;
335 gboolean handled = TRUE;
336
337 GDK_NOTE (MISC,
338 g_message ("add global %u, interface %s, version %u", id, interface, version));
339
340 if (strcmp (interface, "wl_compositor") == 0)
341 {
342 display_wayland->compositor =
343 wl_registry_bind (display_wayland->wl_registry, id, &wl_compositor_interface, MIN (version, 3));
344 display_wayland->compositor_version = MIN (version, 3);
345 }
346 else if (strcmp (interface, "wl_shm") == 0)
347 {
348 display_wayland->shm =
349 wl_registry_bind (display_wayland->wl_registry, id, &wl_shm_interface, 1);
350 wl_shm_add_listener (display_wayland->shm, &wl_shm_listener, display_wayland);
351 }
352 else if (strcmp (interface, "xdg_shell") == 0)
353 {
354 display_wayland->xdg_shell =
355 wl_registry_bind (display_wayland->wl_registry, id, &xdg_shell_interface, 1);
356 xdg_shell_use_unstable_version (display_wayland->xdg_shell, XDG_SHELL_VERSION_CURRENT);
357 xdg_shell_add_listener (display_wayland->xdg_shell, &xdg_shell_listener, display_wayland);
358 }
359 else if (strcmp (interface, "gtk_shell1") == 0)
360 {
361 display_wayland->gtk_shell =
362 wl_registry_bind(display_wayland->wl_registry, id,
363 &gtk_shell1_interface,
364 1);
365 _gdk_wayland_screen_set_has_gtk_shell (display_wayland->screen);
366 display_wayland->gtk_shell_version = version;
367 }
368 else if (strcmp (interface, "wl_output") == 0)
369 {
370 output =
371 wl_registry_bind (display_wayland->wl_registry, id, &wl_output_interface, MIN (version, 2));
372 _gdk_wayland_screen_add_output (display_wayland->screen, id, output, MIN (version, 2));
373 _gdk_wayland_display_async_roundtrip (display_wayland);
374 }
375 else if (strcmp (interface, "wl_seat") == 0)
376 {
377 static const char *required_device_manager_globals[] = {
378 "wl_compositor",
379 "wl_data_device_manager",
380 NULL
381 };
382
383 if (has_required_globals (display_wayland,
384 required_device_manager_globals))
385 _gdk_wayland_display_add_seat (display_wayland, id, version);
386 else
387 {
388 SeatAddedClosure *closure;
389
390 closure = g_new0 (SeatAddedClosure, 1);
391 closure->base.handler = seat_added_closure_run;
392 closure->base.required_globals = required_device_manager_globals;
393 closure->id = id;
394 closure->version = version;
395 postpone_on_globals_closure (display_wayland, &closure->base);
396 }
397 }
398 else if (strcmp (interface, "wl_data_device_manager") == 0)
399 {
400 display_wayland->data_device_manager_version = MIN (version, 3);
401 display_wayland->data_device_manager =
402 wl_registry_bind (display_wayland->wl_registry, id, &wl_data_device_manager_interface,
403 display_wayland->data_device_manager_version);
404 }
405 else if (strcmp (interface, "wl_subcompositor") == 0)
406 {
407 display_wayland->subcompositor =
408 wl_registry_bind (display_wayland->wl_registry, id, &wl_subcompositor_interface, 1);
409 }
410 else if (strcmp (interface, "zwp_pointer_gestures_v1") == 0 &&
411 version == GDK_ZWP_POINTER_GESTURES_V1_VERSION)
412 {
413 display_wayland->pointer_gestures =
414 wl_registry_bind (display_wayland->wl_registry,
415 id, &zwp_pointer_gestures_v1_interface, version);
416 }
417 else if (strcmp (interface, "gtk_primary_selection_device_manager") == 0)
418 {
419 display_wayland->primary_selection_manager =
420 wl_registry_bind(display_wayland->wl_registry, id,
421 &gtk_primary_selection_device_manager_interface, 1);
422 }
423 else if (strcmp (interface, "zwp_tablet_manager_v1") == 0)
424 {
425 display_wayland->tablet_manager =
426 wl_registry_bind(display_wayland->wl_registry, id,
427 &zwp_tablet_manager_v1_interface, 1);
428 }
429 else
430 handled = FALSE;
431
432 if (handled)
433 g_hash_table_insert (display_wayland->known_globals,
434 GUINT_TO_POINTER (id), g_strdup (interface));
435
436 process_on_globals_closures (display_wayland);
437}
438
439static void
440gdk_registry_handle_global_remove (void *data,
441 struct wl_registry *registry,
442 uint32_t id)
443{
444 GdkWaylandDisplay *display_wayland = data;
445 GdkDisplay *display = GDK_DISPLAY (display_wayland);
446
447 GDK_NOTE (MISC, g_message ("remove global %u", id));
448 _gdk_wayland_device_manager_remove_seat (display->device_manager, id);
449 _gdk_wayland_screen_remove_output (display_wayland->screen, id);
450
451 g_hash_table_remove (display_wayland->known_globals, GUINT_TO_POINTER (id));
452
453 /* FIXME: the object needs to be destroyed here, we're leaking */
454}
455
456static const struct wl_registry_listener registry_listener = {
457 gdk_registry_handle_global,
458 gdk_registry_handle_global_remove
459};
460
461static void
462log_handler (const char *format, va_list args)
463{
464 g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format, args);
465}
466
467static void
468load_cursor_theme_closure_run (GdkWaylandDisplay *display_wayland,
469 OnHasGlobalsClosure *closure)
470{
471 _gdk_wayland_display_load_cursor_theme (display_wayland);
472}
473
474static void
475_gdk_wayland_display_prepare_cursor_themes (GdkWaylandDisplay *display_wayland)
476{
477 OnHasGlobalsClosure *closure;
478 static const char *required_cursor_theme_globals[] = {
479 "wl_shm",
480 NULL
481 };
482
483 closure = g_new0 (OnHasGlobalsClosure, 1);
484 closure->handler = load_cursor_theme_closure_run;
485 closure->required_globals = required_cursor_theme_globals;
486 postpone_on_globals_closure (display_wayland, closure);
487}
488
489GdkDisplay *
490_gdk_wayland_display_open (const gchar *display_name)
491{
492 struct wl_display *wl_display;
493 GdkDisplay *display;
494 GdkWaylandDisplay *display_wayland;
495
496 GDK_NOTE (MISC, g_message ("opening display %s", display_name ? display_name : ""));
497
498 /* If this variable is unset then wayland initialisation will surely
499 * fail, logging a fatal error in the process. Save ourselves from
500 * that.
501 */
502 if (g_getenv ("XDG_RUNTIME_DIR") == NULL)
503 return NULL;
504
505 wl_log_set_handler_client (log_handler);
506
507 wl_display = wl_display_connect (display_name);
508 if (!wl_display)
509 return NULL;
510
511 display = g_object_new (GDK_TYPE_WAYLAND_DISPLAY, NULL);
512 display->device_manager = _gdk_wayland_device_manager_new (display);
513
514 display_wayland = GDK_WAYLAND_DISPLAY (display);
515 display_wayland->wl_display = wl_display;
516 display_wayland->screen = _gdk_wayland_screen_new (display);
517 display_wayland->event_source = _gdk_wayland_display_event_source_new (display);
518
519 display_wayland->known_globals =
520 g_hash_table_new_full (NULL, NULL, NULL, g_free);
521
522 _gdk_wayland_display_init_cursors (display_wayland);
523 _gdk_wayland_display_prepare_cursor_themes (display_wayland);
524
525 display_wayland->wl_registry = wl_display_get_registry (display_wayland->wl_display);
526 wl_registry_add_listener (display_wayland->wl_registry, &registry_listener, display_wayland);
527
528 _gdk_wayland_display_async_roundtrip (display_wayland);
529
530 /* Wait for initializing to complete. This means waiting for all
531 * asynchrounous roundtrips that were triggered during initial roundtrip. */
532 while (g_list_length (display_wayland->async_roundtrips) > 0)
533 {
534 if (wl_display_dispatch (display_wayland->wl_display) < 0)
535 {
536 g_object_unref (display);
537 return NULL;
538 }
539 }
540
541 /* Make sure we have xdg_shell at least */
542 if (display_wayland->xdg_shell == NULL)
543 {
544 g_warning ("Wayland compositor does not support xdg_shell interface,"
545 " not using Wayland display");
546 g_object_unref (display);
547
548 return NULL;
549 }
550
551 display_wayland->selection = gdk_wayland_selection_new ();
552
553 g_signal_emit_by_name (display, "opened");
554
555 return display;
556}
557
558static void
559gdk_wayland_display_dispose (GObject *object)
560{
561 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (object);
562
563 _gdk_screen_close (display_wayland->screen);
564
565 if (display_wayland->event_source)
566 {
567 g_source_destroy (display_wayland->event_source);
568 g_source_unref (display_wayland->event_source);
569 display_wayland->event_source = NULL;
570 }
571
572 if (display_wayland->selection)
573 {
574 gdk_wayland_selection_free (display_wayland->selection);
575 display_wayland->selection = NULL;
576 }
577
578 g_list_free_full (display_wayland->async_roundtrips, (GDestroyNotify) wl_callback_destroy);
579
580 if (display_wayland->known_globals)
581 {
582 g_hash_table_destroy (display_wayland->known_globals);
583 display_wayland->known_globals = NULL;
584 }
585
586 g_list_free_full (display_wayland->on_has_globals_closures, g_free);
587
588 G_OBJECT_CLASS (gdk_wayland_display_parent_class)->dispose (object);
589}
590
591static void
592gdk_wayland_display_finalize (GObject *object)
593{
594 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (object);
595
596 _gdk_wayland_display_finalize_cursors (display_wayland);
597
598 g_object_unref (display_wayland->screen);
599
600 g_free (display_wayland->startup_notification_id);
601
602 g_ptr_array_free (display_wayland->monitors, TRUE);
603
604 G_OBJECT_CLASS (gdk_wayland_display_parent_class)->finalize (object);
605}
606
607static const gchar *
608gdk_wayland_display_get_name (GdkDisplay *display)
609{
610 const gchar *name;
611
612 name = g_getenv ("WAYLAND_DISPLAY");
613 if (name == NULL)
614 name = "wayland-0";
615
616 return name;
617}
618
619static GdkScreen *
620gdk_wayland_display_get_default_screen (GdkDisplay *display)
621{
622 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
623
624 return GDK_WAYLAND_DISPLAY (display)->screen;
625}
626
627static void
628gdk_wayland_display_beep (GdkDisplay *display)
629{
630 GdkWaylandDisplay *display_wayland;
631
632 g_return_if_fail (GDK_IS_DISPLAY (display));
633
634 display_wayland = GDK_WAYLAND_DISPLAY (display);
635
636 if (!display_wayland->gtk_shell)
637 return;
638
639 gtk_shell1_system_bell (display_wayland->gtk_shell, NULL);
640}
641
642static void
643gdk_wayland_display_sync (GdkDisplay *display)
644{
645 GdkWaylandDisplay *display_wayland;
646
647 g_return_if_fail (GDK_IS_DISPLAY (display));
648
649 display_wayland = GDK_WAYLAND_DISPLAY (display);
650
651 wl_display_roundtrip (display_wayland->wl_display);
652}
653
654static void
655gdk_wayland_display_flush (GdkDisplay *display)
656{
657 g_return_if_fail (GDK_IS_DISPLAY (display));
658
659 if (!display->closed)
660 wl_display_flush (GDK_WAYLAND_DISPLAY (display)->wl_display);
661}
662
663static void
664gdk_wayland_display_make_default (GdkDisplay *display)
665{
666 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
667 const gchar *startup_id;
668
669 g_free (display_wayland->startup_notification_id);
670 display_wayland->startup_notification_id = NULL;
671
672 startup_id = g_getenv ("DESKTOP_STARTUP_ID");
673 if (startup_id && *startup_id != '\0')
674 {
675 if (!g_utf8_validate (startup_id, -1, NULL))
676 g_warning ("DESKTOP_STARTUP_ID contains invalid UTF-8");
677 else
678 display_wayland->startup_notification_id = g_strdup (startup_id);
679
680 /* Clear the environment variable so it won't be inherited by
681 * child processes and confuse things.
682 */
683 g_unsetenv ("DESKTOP_STARTUP_ID");
684 }
685}
686
687static gboolean
688gdk_wayland_display_has_pending (GdkDisplay *display)
689{
690 return FALSE;
691}
692
693static GdkWindow *
694gdk_wayland_display_get_default_group (GdkDisplay *display)
695{
696 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
697
698 return NULL;
699}
700
701
702static gboolean
703gdk_wayland_display_supports_selection_notification (GdkDisplay *display)
704{
705 return FALSE;
706}
707
708static gboolean
709gdk_wayland_display_request_selection_notification (GdkDisplay *display,
710 GdkAtom selection)
711
712{
713 return FALSE;
714}
715
716static gboolean
717gdk_wayland_display_supports_clipboard_persistence (GdkDisplay *display)
718{
719 return FALSE;
720}
721
722static void
723gdk_wayland_display_store_clipboard (GdkDisplay *display,
724 GdkWindow *clipboard_window,
725 guint32 time_,
726 const GdkAtom *targets,
727 gint n_targets)
728{
729}
730
731static gboolean
732gdk_wayland_display_supports_shapes (GdkDisplay *display)
733{
734 return FALSE;
735}
736
737static gboolean
738gdk_wayland_display_supports_input_shapes (GdkDisplay *display)
739{
740 return TRUE;
741}
742
743static gboolean
744gdk_wayland_display_supports_composite (GdkDisplay *display)
745{
746 return FALSE;
747}
748
749static void
750gdk_wayland_display_before_process_all_updates (GdkDisplay *display)
751{
752}
753
754static void
755gdk_wayland_display_after_process_all_updates (GdkDisplay *display)
756{
757 /* Post the damage here instead? */
758}
759
760static gulong
761gdk_wayland_display_get_next_serial (GdkDisplay *display)
762{
763 static gulong serial = 0;
764 return ++serial;
765}
766
767static void
768gdk_wayland_display_notify_startup_complete (GdkDisplay *display,
769 const gchar *startup_id)
770{
771 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
772 gchar *free_this = NULL;
773
774 if (startup_id == NULL)
775 {
776 startup_id = free_this = display_wayland->startup_notification_id;
777 display_wayland->startup_notification_id = NULL;
778
779 if (startup_id == NULL)
780 return;
781 }
782
783 if (display_wayland->gtk_shell)
784 gtk_shell1_set_startup_id (display_wayland->gtk_shell, startup_id);
785
786 g_free (free_this);
787}
788
789static GdkKeymap *
790_gdk_wayland_display_get_keymap (GdkDisplay *display)
791{
792 GdkDevice *core_keyboard = NULL;
793 static GdkKeymap *tmp_keymap = NULL;
794
795 core_keyboard = gdk_seat_get_keyboard (gdk_display_get_default_seat (display));
796
797 if (core_keyboard && tmp_keymap)
798 {
799 g_object_unref (tmp_keymap);
800 tmp_keymap = NULL;
801 }
802
803 if (core_keyboard)
804 return _gdk_wayland_device_get_keymap (core_keyboard);
805
806 if (!tmp_keymap)
807 tmp_keymap = _gdk_wayland_keymap_new ();
808
809 return tmp_keymap;
810}
811
812static void
813gdk_wayland_display_push_error_trap (GdkDisplay *display)
814{
815}
816
817static gint
818gdk_wayland_display_pop_error_trap (GdkDisplay *display,
819 gboolean ignored)
820{
821 return 0;
822}
823
824static int
825gdk_wayland_display_get_n_monitors (GdkDisplay *display)
826{
827 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
828
829 return display_wayland->monitors->len;
830}
831
832static GdkMonitor *
833gdk_wayland_display_get_monitor (GdkDisplay *display,
834 int monitor_num)
835{
836 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
837
838 if (monitor_num < 0 || monitor_num >= display_wayland->monitors->len)
839 return NULL;
840
841 return (GdkMonitor *)display_wayland->monitors->pdata[monitor_num];
842}
843
844static GdkMonitor *
845gdk_wayland_display_get_monitor_at_window (GdkDisplay *display,
846 GdkWindow *window)
847{
848 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
849 struct wl_output *output;
850 int i;
851
852 g_return_val_if_fail (GDK_IS_WAYLAND_WINDOW (window), NULL);
853
854 output = gdk_wayland_window_get_wl_output (window);
855 if (output == NULL)
856 return NULL;
857
858 for (i = 0; i < display_wayland->monitors->len; i++)
859 {
860 GdkMonitor *monitor = display_wayland->monitors->pdata[i];
861
862 if (gdk_wayland_monitor_get_wl_output (monitor) == output)
863 return monitor;
864 }
865
866 return NULL;
867}
868
869static void
870gdk_wayland_display_class_init (GdkWaylandDisplayClass *class)
871{
872 GObjectClass *object_class = G_OBJECT_CLASS (class);
873 GdkDisplayClass *display_class = GDK_DISPLAY_CLASS (class);
874
875 object_class->dispose = gdk_wayland_display_dispose;
876 object_class->finalize = gdk_wayland_display_finalize;
877
878 display_class->window_type = gdk_wayland_window_get_type ();
879 display_class->get_name = gdk_wayland_display_get_name;
880 display_class->get_default_screen = gdk_wayland_display_get_default_screen;
881 display_class->beep = gdk_wayland_display_beep;
882 display_class->sync = gdk_wayland_display_sync;
883 display_class->flush = gdk_wayland_display_flush;
884 display_class->make_default = gdk_wayland_display_make_default;
885 display_class->has_pending = gdk_wayland_display_has_pending;
886 display_class->queue_events = _gdk_wayland_display_queue_events;
887 display_class->get_default_group = gdk_wayland_display_get_default_group;
888 display_class->supports_selection_notification = gdk_wayland_display_supports_selection_notification;
889 display_class->request_selection_notification = gdk_wayland_display_request_selection_notification;
890 display_class->supports_clipboard_persistence = gdk_wayland_display_supports_clipboard_persistence;
891 display_class->store_clipboard = gdk_wayland_display_store_clipboard;
892 display_class->supports_shapes = gdk_wayland_display_supports_shapes;
893 display_class->supports_input_shapes = gdk_wayland_display_supports_input_shapes;
894 display_class->supports_composite = gdk_wayland_display_supports_composite;
895 display_class->get_app_launch_context = _gdk_wayland_display_get_app_launch_context;
896 display_class->get_default_cursor_size = _gdk_wayland_display_get_default_cursor_size;
897 display_class->get_maximal_cursor_size = _gdk_wayland_display_get_maximal_cursor_size;
898 display_class->get_cursor_for_type = _gdk_wayland_display_get_cursor_for_type;
899 display_class->get_cursor_for_name = _gdk_wayland_display_get_cursor_for_name;
900 display_class->get_cursor_for_surface = _gdk_wayland_display_get_cursor_for_surface;
901 display_class->supports_cursor_alpha = _gdk_wayland_display_supports_cursor_alpha;
902 display_class->supports_cursor_color = _gdk_wayland_display_supports_cursor_color;
903 display_class->before_process_all_updates = gdk_wayland_display_before_process_all_updates;
904 display_class->after_process_all_updates = gdk_wayland_display_after_process_all_updates;
905 display_class->get_next_serial = gdk_wayland_display_get_next_serial;
906 display_class->notify_startup_complete = gdk_wayland_display_notify_startup_complete;
907 display_class->create_window_impl = _gdk_wayland_display_create_window_impl;
908 display_class->get_keymap = _gdk_wayland_display_get_keymap;
909 display_class->push_error_trap = gdk_wayland_display_push_error_trap;
910 display_class->pop_error_trap = gdk_wayland_display_pop_error_trap;
911 display_class->get_selection_owner = _gdk_wayland_display_get_selection_owner;
912 display_class->set_selection_owner = _gdk_wayland_display_set_selection_owner;
913 display_class->send_selection_notify = _gdk_wayland_display_send_selection_notify;
914 display_class->get_selection_property = _gdk_wayland_display_get_selection_property;
915 display_class->convert_selection = _gdk_wayland_display_convert_selection;
916 display_class->text_property_to_utf8_list = _gdk_wayland_display_text_property_to_utf8_list;
917 display_class->utf8_to_string_target = _gdk_wayland_display_utf8_to_string_target;
918
919 display_class->make_gl_context_current = gdk_wayland_display_make_gl_context_current;
920
921 display_class->get_n_monitors = gdk_wayland_display_get_n_monitors;
922 display_class->get_monitor = gdk_wayland_display_get_monitor;
923 display_class->get_monitor_at_window = gdk_wayland_display_get_monitor_at_window;
924}
925
926static void
927gdk_wayland_display_init (GdkWaylandDisplay *display)
928{
929 display->xkb_context = xkb_context_new (0);
930
931 display->monitors = g_ptr_array_new_with_free_func (g_object_unref);
932}
933
934void
935gdk_wayland_display_set_cursor_theme (GdkDisplay *display,
936 const gchar *name,
937 gint size)
938{
939 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY(display);
940 struct wl_cursor_theme *theme;
941 int i;
942
943 g_assert (display_wayland);
944 g_assert (display_wayland->shm);
945
946 if (g_strcmp0 (name, display_wayland->cursor_theme_name) == 0 &&
947 display_wayland->cursor_theme_size == size)
948 return;
949
950 theme = wl_cursor_theme_load (name, size, display_wayland->shm);
951 if (theme == NULL)
952 {
953 g_warning ("Failed to load cursor theme %s", name);
954 return;
955 }
956
957 for (i = 0; i < GDK_WAYLAND_THEME_SCALES_COUNT; i++)
958 {
959 if (display_wayland->scaled_cursor_themes[i])
960 {
961 wl_cursor_theme_destroy (display_wayland->scaled_cursor_themes[i]);
962 display_wayland->scaled_cursor_themes[i] = NULL;
963 }
964 }
965 display_wayland->scaled_cursor_themes[0] = theme;
966 if (display_wayland->cursor_theme_name != NULL)
967 g_free (display_wayland->cursor_theme_name);
968 display_wayland->cursor_theme_name = g_strdup (name);
969 display_wayland->cursor_theme_size = size;
970
971 _gdk_wayland_display_update_cursors (display_wayland);
972}
973
974struct wl_cursor_theme *
975_gdk_wayland_display_get_scaled_cursor_theme (GdkWaylandDisplay *display_wayland,
976 guint scale)
977{
978 struct wl_cursor_theme *theme;
979
980 g_assert (display_wayland->cursor_theme_name);
981 g_assert (scale <= GDK_WAYLAND_MAX_THEME_SCALE);
982 g_assert (scale >= 1);
983
984 theme = display_wayland->scaled_cursor_themes[scale - 1];
985 if (!theme)
986 {
987 theme = wl_cursor_theme_load (display_wayland->cursor_theme_name,
988 display_wayland->cursor_theme_size * scale,
989 display_wayland->shm);
990 if (theme == NULL)
991 {
992 g_warning ("Failed to load cursor theme %s with scale %u",
993 display_wayland->cursor_theme_name, scale);
994 return NULL;
995 }
996 display_wayland->scaled_cursor_themes[scale - 1] = theme;
997 }
998
999 return theme;
1000}
1001
1002static void
1003_gdk_wayland_display_load_cursor_theme (GdkWaylandDisplay *display_wayland)
1004{
1005 guint size;
1006 const gchar *name;
1007 GValue v = G_VALUE_INIT;
1008
1009 g_assert (display_wayland);
1010 g_assert (display_wayland->shm);
1011
1012 g_value_init (&v, G_TYPE_INT);
1013 if (gdk_screen_get_setting (display_wayland->screen, "gtk-cursor-theme-size", &v))
1014 size = g_value_get_int (&v);
1015 else
1016 size = 32;
1017 g_value_unset (&v);
1018
1019 g_value_init (&v, G_TYPE_STRING);
1020 if (gdk_screen_get_setting (display_wayland->screen, "gtk-cursor-theme-name", &v))
1021 name = g_value_get_string (&v);
1022 else
1023 name = "default";
1024
1025 gdk_wayland_display_set_cursor_theme (GDK_DISPLAY (display_wayland), name, size);
1026 g_value_unset (&v);
1027}
1028
1029guint32
1030_gdk_wayland_display_get_serial (GdkWaylandDisplay *display_wayland)
1031{
1032 return display_wayland->serial;
1033}
1034
1035void
1036_gdk_wayland_display_update_serial (GdkWaylandDisplay *display_wayland,
1037 guint32 serial)
1038{
1039 display_wayland->serial = serial;
1040}
1041
1042/**
1043 * gdk_wayland_display_get_wl_display:
1044 * @display: (type GdkWaylandDisplay): a #GdkDisplay
1045 *
1046 * Returns the Wayland wl_display of a #GdkDisplay.
1047 *
1048 * Returns: (transfer none): a Wayland wl_display
1049 *
1050 * Since: 3.8
1051 */
1052struct wl_display *
1053gdk_wayland_display_get_wl_display (GdkDisplay *display)
1054{
1055 g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), NULL);
1056
1057 return GDK_WAYLAND_DISPLAY (display)->wl_display;
1058}
1059
1060/**
1061 * gdk_wayland_display_get_wl_compositor:
1062 * @display: (type GdkWaylandDisplay): a #GdkDisplay
1063 *
1064 * Returns the Wayland global singleton compositor of a #GdkDisplay.
1065 *
1066 * Returns: (transfer none): a Wayland wl_compositor
1067 *
1068 * Since: 3.8
1069 */
1070struct wl_compositor *
1071gdk_wayland_display_get_wl_compositor (GdkDisplay *display)
1072{
1073 g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), NULL);
1074
1075 return GDK_WAYLAND_DISPLAY (display)->compositor;
1076}
1077
1078/**
1079 * gdk_wayland_display_get_xdg_shell:
1080 * @display: (type GdkWaylandDisplay): a #GdkDisplay
1081 *
1082 * Returns the Wayland global singleton shell of a #GdkDisplay.
1083 *
1084 * Returns: (transfer none): a Wayland xdg_shell
1085 *
1086 * Since: 3.8
1087 */
1088struct xdg_shell *
1089gdk_wayland_display_get_xdg_shell (GdkDisplay *display)
1090{
1091 g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), NULL);
1092
1093 return GDK_WAYLAND_DISPLAY (display)->xdg_shell;
1094}
1095
1096static const cairo_user_data_key_t gdk_wayland_shm_surface_cairo_key;
1097
1098typedef struct _GdkWaylandCairoSurfaceData {
1099 gpointer buf;
1100 size_t buf_length;
1101 struct wl_shm_pool *pool;
1102 struct wl_buffer *buffer;
1103 GdkWaylandDisplay *display;
1104 uint32_t scale;
1105} GdkWaylandCairoSurfaceData;
1106
1107static struct wl_shm_pool *
1108create_shm_pool (struct wl_shm *shm,
1109 int size,
1110 size_t *buf_length,
1111 void **data_out)
1112{
1113 struct wl_shm_pool *pool;
1114 int ret, fd;
1115 void *data;
1116
1117 ret = syscall (__NR_memfd_create, "gdk-wayland", MFD_CLOEXEC);
1118
1119 if (ret < 0)
1120 {
1121 g_critical (G_STRLOC ": creating shared memory file failed: %s",
1122 g_strerror (-ret));
1123 return NULL;
1124 }
1125
1126 fd = ret;
1127
1128 if (ftruncate (fd, size) < 0)
1129 {
1130 g_critical (G_STRLOC ": Truncating shared memory file failed: %m");
1131 close (fd);
1132 return NULL;
1133 }
1134
1135 data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1136
1137 if (data == MAP_FAILED)
1138 {
1139 g_critical (G_STRLOC ": mmap'ping shared memory file failed: %m");
1140 close (fd);
1141 return NULL;
1142 }
1143
1144 pool = wl_shm_create_pool (shm, fd, size);
1145
1146 close (fd);
1147
1148 *data_out = data;
1149 *buf_length = size;
1150
1151 return pool;
1152}
1153
1154static void
1155gdk_wayland_cairo_surface_destroy (void *p)
1156{
1157 GdkWaylandCairoSurfaceData *data = p;
1158
1159 if (data->buffer)
1160 wl_buffer_destroy (data->buffer);
1161
1162 if (data->pool)
1163 wl_shm_pool_destroy (data->pool);
1164
1165 munmap (data->buf, data->buf_length);
1166 g_free (data);
1167}
1168
1169cairo_surface_t *
1170_gdk_wayland_display_create_shm_surface (GdkWaylandDisplay *display,
1171 int width,
1172 int height,
1173 guint scale)
1174{
1175 GdkWaylandCairoSurfaceData *data;
1176 cairo_surface_t *surface = NULL;
1177 cairo_status_t status;
1178 int stride;
1179
1180 data = g_new (GdkWaylandCairoSurfaceData, 1);
1181 data->display = display;
1182 data->buffer = NULL;
1183 data->scale = scale;
1184
1185 stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, width*scale);
1186
1187 data->pool = create_shm_pool (display->shm,
1188 height*scale*stride,
1189 &data->buf_length,
1190 &data->buf);
1191
1192 surface = cairo_image_surface_create_for_data (data->buf,
1193 CAIRO_FORMAT_ARGB32,
1194 width*scale,
1195 height*scale,
1196 stride);
1197
1198 data->buffer = wl_shm_pool_create_buffer (data->pool, 0,
1199 width*scale, height*scale,
1200 stride, WL_SHM_FORMAT_ARGB8888);
1201
1202 cairo_surface_set_user_data (surface, &gdk_wayland_shm_surface_cairo_key,
1203 data, gdk_wayland_cairo_surface_destroy);
1204
1205 cairo_surface_set_device_scale (surface, scale, scale);
1206
1207 status = cairo_surface_status (surface);
1208 if (status != CAIRO_STATUS_SUCCESS)
1209 {
1210 g_critical (G_STRLOC ": Unable to create Cairo image surface: %s",
1211 cairo_status_to_string (status));
1212 }
1213
1214 return surface;
1215}
1216
1217struct wl_buffer *
1218_gdk_wayland_shm_surface_get_wl_buffer (cairo_surface_t *surface)
1219{
1220 GdkWaylandCairoSurfaceData *data = cairo_surface_get_user_data (surface, &gdk_wayland_shm_surface_cairo_key);
1221 return data->buffer;
1222}
1223
1224gboolean
1225_gdk_wayland_is_shm_surface (cairo_surface_t *surface)
1226{
1227 return cairo_surface_get_user_data (surface, &gdk_wayland_shm_surface_cairo_key) != NULL;
1228}
1229
1230GdkWaylandSelection *
1231gdk_wayland_display_get_selection (GdkDisplay *display)
1232{
1233 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
1234
1235 return display_wayland->selection;
1236}
1237