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
23#include <glib.h>
24#include <gio/gio.h>
25#include "gdkscreenprivate.h"
26#include "gdkvisualprivate.h"
27#include "gdkdisplay.h"
28#include "gdkdisplay-wayland.h"
29#include "gdkmonitor-wayland.h"
30#include "gdkwayland.h"
31#include "gdkprivate-wayland.h"
32
33#include "wm-button-layout-translation.h"
34
35typedef struct _GdkWaylandScreen GdkWaylandScreen;
36typedef struct _GdkWaylandScreenClass GdkWaylandScreenClass;
37
38#define GDK_TYPE_WAYLAND_SCREEN (_gdk_wayland_screen_get_type ())
39#define GDK_WAYLAND_SCREEN(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_SCREEN, GdkWaylandScreen))
40#define GDK_WAYLAND_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WAYLAND_SCREEN, GdkWaylandScreenClass))
41#define GDK_IS_WAYLAND_SCREEN(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_SCREEN))
42#define GDK_IS_WAYLAND_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WAYLAND_SCREEN))
43#define GDK_WAYLAND_SCREEN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WAYLAND_SCREEN, GdkWaylandScreenClass))
44
45typedef struct {
46 gboolean antialias;
47 gboolean hinting;
48 gint dpi;
49 const gchar *rgba;
50 const gchar *hintstyle;
51} GsdXftSettings;
52
53
54struct _GdkWaylandScreen
55{
56 GdkScreen parent_instance;
57
58 GdkDisplay *display;
59 GdkWindow *root_window;
60
61 int width, height;
62 int width_mm, height_mm;
63
64 /* Visual Part */
65 GdkVisual *visual;
66
67 GHashTable *settings;
68 GsdXftSettings xft_settings;
69
70 guint32 shell_capabilities;
71};
72
73struct _GdkWaylandScreenClass
74{
75 GdkScreenClass parent_class;
76};
77
78#define OUTPUT_VERSION_WITH_DONE 2
79
80
81GType _gdk_wayland_screen_get_type (void);
82
83G_DEFINE_TYPE (GdkWaylandScreen, _gdk_wayland_screen, GDK_TYPE_SCREEN)
84
85static void
86gdk_wayland_screen_dispose (GObject *object)
87{
88 GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (object);
89
90 if (screen_wayland->root_window)
91 _gdk_window_destroy (screen_wayland->root_window, FALSE);
92
93 G_OBJECT_CLASS (_gdk_wayland_screen_parent_class)->dispose (object);
94}
95
96static void
97gdk_wayland_screen_finalize (GObject *object)
98{
99 GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (object);
100
101 if (screen_wayland->root_window)
102 g_object_unref (screen_wayland->root_window);
103
104 g_object_unref (screen_wayland->visual);
105
106 g_hash_table_destroy (screen_wayland->settings);
107
108 G_OBJECT_CLASS (_gdk_wayland_screen_parent_class)->finalize (object);
109}
110
111static GdkDisplay *
112gdk_wayland_screen_get_display (GdkScreen *screen)
113{
114 return GDK_WAYLAND_SCREEN (screen)->display;
115}
116
117static gint
118gdk_wayland_screen_get_width (GdkScreen *screen)
119{
120 return GDK_WAYLAND_SCREEN (screen)->width;
121}
122
123static gint
124gdk_wayland_screen_get_height (GdkScreen *screen)
125{
126 return GDK_WAYLAND_SCREEN (screen)->height;
127}
128
129static gint
130gdk_wayland_screen_get_width_mm (GdkScreen *screen)
131{
132 return GDK_WAYLAND_SCREEN (screen)->width_mm;
133}
134
135static gint
136gdk_wayland_screen_get_height_mm (GdkScreen *screen)
137{
138 return GDK_WAYLAND_SCREEN (screen)->height_mm;
139}
140
141static gint
142gdk_wayland_screen_get_number (GdkScreen *screen)
143{
144 return 0;
145}
146
147static GdkWindow *
148gdk_wayland_screen_get_root_window (GdkScreen *screen)
149{
150 return GDK_WAYLAND_SCREEN (screen)->root_window;
151}
152
153static GdkVisual *
154gdk_wayland_screen_get_system_visual (GdkScreen * screen)
155{
156 return (GdkVisual *) GDK_WAYLAND_SCREEN (screen)->visual;
157}
158
159static GdkVisual *
160gdk_wayland_screen_get_rgba_visual (GdkScreen *screen)
161{
162 return (GdkVisual *) GDK_WAYLAND_SCREEN (screen)->visual;
163}
164
165static gboolean
166gdk_wayland_screen_is_composited (GdkScreen *screen)
167{
168 return TRUE;
169}
170
171static gchar *
172gdk_wayland_screen_make_display_name (GdkScreen *screen)
173{
174 return g_strdup (gdk_display_get_name (GDK_WAYLAND_SCREEN (screen)->display));
175}
176
177static GdkWindow *
178gdk_wayland_screen_get_active_window (GdkScreen *screen)
179{
180 return NULL;
181}
182
183static GList *
184gdk_wayland_screen_get_window_stack (GdkScreen *screen)
185{
186 return NULL;
187}
188
189static void
190gdk_wayland_screen_broadcast_client_message (GdkScreen *screen,
191 GdkEvent *event)
192{
193}
194
195static void
196notify_setting (GdkScreen *screen,
197 const gchar *setting)
198{
199 GdkEvent event;
200
201 event.type = GDK_SETTING;
202 event.setting.window = gdk_screen_get_root_window (screen);
203 event.setting.send_event = FALSE;
204 event.setting.action = GDK_SETTING_ACTION_CHANGED;
205 event.setting.name = (gchar *)setting;
206 gdk_event_put (&event);
207}
208
209typedef enum
210{
211 GSD_FONT_ANTIALIASING_MODE_NONE,
212 GSD_FONT_ANTIALIASING_MODE_GRAYSCALE,
213 GSD_FONT_ANTIALIASING_MODE_RGBA
214} GsdFontAntialiasingMode;
215
216typedef enum
217{
218 GSD_FONT_HINTING_NONE,
219 GSD_FONT_HINTING_SLIGHT,
220 GSD_FONT_HINTING_MEDIUM,
221 GSD_FONT_HINTING_FULL
222} GsdFontHinting;
223
224typedef enum
225{
226 GSD_FONT_RGBA_ORDER_RGBA,
227 GSD_FONT_RGBA_ORDER_RGB,
228 GSD_FONT_RGBA_ORDER_BGR,
229 GSD_FONT_RGBA_ORDER_VRGB,
230 GSD_FONT_RGBA_ORDER_VBGR
231} GsdFontRgbaOrder;
232
233static gdouble
234get_dpi_from_gsettings (GdkWaylandScreen *screen_wayland)
235{
236 GSettings *settings;
237 gdouble factor;
238
239 settings = g_hash_table_lookup (screen_wayland->settings,
240 "org.gnome.desktop.interface");
241 if (settings != NULL)
242 factor = g_settings_get_double (settings, "text-scaling-factor");
243 else
244 factor = 1.0;
245
246 return 96.0 * factor;
247}
248
249static void
250update_xft_settings (GdkScreen *screen)
251{
252 GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen);
253 GSettings *settings;
254 GsdFontAntialiasingMode antialiasing;
255 GsdFontHinting hinting;
256 GsdFontRgbaOrder order;
257 gboolean use_rgba = FALSE;
258 GsdXftSettings xft_settings;
259
260 settings = g_hash_table_lookup (screen_wayland->settings, "org.gnome.settings-daemon.plugins.xsettings");
261
262 if (settings)
263 {
264 antialiasing = g_settings_get_enum (settings, "antialiasing");
265 hinting = g_settings_get_enum (settings, "hinting");
266 order = g_settings_get_enum (settings, "rgba-order");
267 }
268 else
269 {
270 antialiasing = GSD_FONT_ANTIALIASING_MODE_GRAYSCALE;
271 hinting = GSD_FONT_HINTING_MEDIUM;
272 order = GSD_FONT_RGBA_ORDER_RGB;
273 }
274
275 xft_settings.antialias = (antialiasing != GSD_FONT_ANTIALIASING_MODE_NONE);
276 xft_settings.hinting = (hinting != GSD_FONT_HINTING_NONE);
277 xft_settings.dpi = get_dpi_from_gsettings (screen_wayland) * 1024; /* Xft wants 1/1024ths of an inch */
278 xft_settings.rgba = "rgb";
279 xft_settings.hintstyle = "hintfull";
280
281 switch (hinting)
282 {
283 case GSD_FONT_HINTING_NONE:
284 xft_settings.hintstyle = "hintnone";
285 break;
286 case GSD_FONT_HINTING_SLIGHT:
287 xft_settings.hintstyle = "hintslight";
288 break;
289 case GSD_FONT_HINTING_MEDIUM:
290 xft_settings.hintstyle = "hintmedium";
291 break;
292 case GSD_FONT_HINTING_FULL:
293 xft_settings.hintstyle = "hintfull";
294 break;
295 }
296
297 switch (order)
298 {
299 case GSD_FONT_RGBA_ORDER_RGBA:
300 xft_settings.rgba = "rgba";
301 break;
302 case GSD_FONT_RGBA_ORDER_RGB:
303 xft_settings.rgba = "rgb";
304 break;
305 case GSD_FONT_RGBA_ORDER_BGR:
306 xft_settings.rgba = "bgr";
307 break;
308 case GSD_FONT_RGBA_ORDER_VRGB:
309 xft_settings.rgba = "vrgb";
310 break;
311 case GSD_FONT_RGBA_ORDER_VBGR:
312 xft_settings.rgba = "vbgr";
313 break;
314 }
315
316 switch (antialiasing)
317 {
318 case GSD_FONT_ANTIALIASING_MODE_NONE:
319 xft_settings.antialias = FALSE;
320 break;
321 case GSD_FONT_ANTIALIASING_MODE_GRAYSCALE:
322 xft_settings.antialias = TRUE;
323 break;
324 case GSD_FONT_ANTIALIASING_MODE_RGBA:
325 xft_settings.antialias = TRUE;
326 use_rgba = TRUE;
327 }
328
329 if (!use_rgba)
330 xft_settings.rgba = "none";
331
332 if (screen_wayland->xft_settings.antialias != xft_settings.antialias)
333 {
334 screen_wayland->xft_settings.antialias = xft_settings.antialias;
335 notify_setting (screen, "gtk-xft-antialias");
336 }
337
338 if (screen_wayland->xft_settings.hinting != xft_settings.hinting)
339 {
340 screen_wayland->xft_settings.hinting = xft_settings.hinting;
341 notify_setting (screen, "gtk-xft-hinting");
342 }
343
344 if (screen_wayland->xft_settings.hintstyle != xft_settings.hintstyle)
345 {
346 screen_wayland->xft_settings.hintstyle = xft_settings.hintstyle;
347 notify_setting (screen, "gtk-xft-hintstyle");
348 }
349
350 if (screen_wayland->xft_settings.rgba != xft_settings.rgba)
351 {
352 screen_wayland->xft_settings.rgba = xft_settings.rgba;
353 notify_setting (screen, "gtk-xft-rgba");
354 }
355
356 if (screen_wayland->xft_settings.dpi != xft_settings.dpi)
357 {
358 double dpi = xft_settings.dpi / 1024.;
359 const char *scale_env;
360 double scale;
361
362 screen_wayland->xft_settings.dpi = xft_settings.dpi;
363
364 scale_env = g_getenv ("GDK_DPI_SCALE");
365 if (scale_env)
366 {
367 scale = g_ascii_strtod (scale_env, NULL);
368 if (scale != 0 && dpi > 0)
369 dpi *= scale;
370 }
371
372 _gdk_screen_set_resolution (screen, dpi);
373
374 notify_setting (screen, "gtk-xft-dpi");
375 }
376}
377
378#define WM_SETTINGS_SCHEMA "org.gnome.desktop.wm.preferences"
379#define CLASSIC_WM_SETTINGS_SCHEMA "org.gnome.shell.extensions.classic-overrides"
380
381typedef struct _TranslationEntry TranslationEntry;
382struct _TranslationEntry {
383 const gchar *schema;
384 const gchar *key;
385 const gchar *setting;
386 GType type;
387 union {
388 const gchar *s;
389 gint i;
390 gboolean b;
391 } fallback;
392};
393
394static TranslationEntry translations[] = {
395 { "org.gnome.desktop.interface", "gtk-theme", "gtk-theme-name" , G_TYPE_STRING, { .s = "Adwaita" } },
396 { "org.gnome.desktop.interface", "icon-theme", "gtk-icon-theme-name", G_TYPE_STRING, { .s = "gnome" } },
397 { "org.gnome.desktop.interface", "cursor-theme", "gtk-cursor-theme-name", G_TYPE_STRING, { .s = "Adwaita" } },
398 { "org.gnome.desktop.interface", "cursor-size", "gtk-cursor-theme-size", G_TYPE_INT, { .i = 32 } },
399 { "org.gnome.desktop.interface", "font-name", "gtk-font-name", G_TYPE_STRING, { .s = "Cantarell 11" } },
400 { "org.gnome.desktop.interface", "cursor-blink", "gtk-cursor-blink", G_TYPE_BOOLEAN, { .b = TRUE } },
401 { "org.gnome.desktop.interface", "cursor-blink-time", "gtk-cursor-blink-time", G_TYPE_INT, { .i = 1200 } },
402 { "org.gnome.desktop.interface", "cursor-blink-timeout", "gtk-cursor-blink-timeout", G_TYPE_INT, { .i = 3600 } },
403 { "org.gnome.desktop.interface", "gtk-im-module", "gtk-im-module", G_TYPE_STRING, { .s = "simple" } },
404 { "org.gnome.desktop.interface", "enable-animations", "gtk-enable-animations", G_TYPE_BOOLEAN, { .b = TRUE } },
405 { "org.gnome.settings-daemon.peripherals.mouse", "double-click", "gtk-double-click-time", G_TYPE_INT, { .i = 400 } },
406 { "org.gnome.settings-daemon.peripherals.mouse", "drag-threshold", "gtk-dnd-drag-threshold", G_TYPE_INT, {.i = 8 } },
407 { "org.gnome.desktop.sound", "theme-name", "gtk-sound-theme-name", G_TYPE_STRING, { .s = "freedesktop" } },
408 { "org.gnome.desktop.sound", "event-sounds", "gtk-enable-event-sounds", G_TYPE_BOOLEAN, { .b = TRUE } },
409 { "org.gnome.desktop.sound", "input-feedback-sounds", "gtk-enable-input-feedback-sounds", G_TYPE_BOOLEAN, { . b = FALSE } },
410 { "org.gnome.desktop.privacy", "recent-files-max-age", "gtk-recent-files-max-age", G_TYPE_INT, { .i = 30 } },
411 { "org.gnome.desktop.privacy", "remember-recent-files", "gtk-recent-files-enabled", G_TYPE_BOOLEAN, { .b = TRUE } },
412 { WM_SETTINGS_SCHEMA, "button-layout", "gtk-decoration-layout", G_TYPE_STRING, { .s = "menu:close" } },
413 { CLASSIC_WM_SETTINGS_SCHEMA, "button-layout", "gtk-decoration-layout", G_TYPE_STRING, { .s = "menu:close" } },
414 { "org.gnome.settings-daemon.plugins.xsettings", "antialiasing", "gtk-xft-antialias", G_TYPE_NONE, { .i = 0 } },
415 { "org.gnome.settings-daemon.plugins.xsettings", "hinting", "gtk-xft-hinting", G_TYPE_NONE, { .i = 0 } },
416 { "org.gnome.settings-daemon.plugins.xsettings", "hinting", "gtk-xft-hintstyle", G_TYPE_NONE, { .i = 0 } },
417 { "org.gnome.settings-daemon.plugins.xsettings", "rgba-order", "gtk-xft-rgba", G_TYPE_NONE, { .i = 0 } },
418 { "org.gnome.desktop.interface", "text-scaling-factor", "gtk-xft-dpi" , G_TYPE_NONE, { .i = 0 } },
419 { "org.gnome.desktop.wm.preferences", "action-double-click-titlebar", "gtk-titlebar-double-click", G_TYPE_STRING, { .s = "toggle-maximize" } },
420 { "org.gnome.desktop.wm.preferences", "action-middle-click-titlebar", "gtk-titlebar-middle-click", G_TYPE_STRING, { .s = "none" } },
421 { "org.gnome.desktop.wm.preferences", "action-right-click-titlebar", "gtk-titlebar-right-click", G_TYPE_STRING, { .s = "menu" } },
422 { "org.gnome.desktop.a11y", "always-show-text-caret", "gtk-keynav-use-caret", G_TYPE_BOOLEAN, { .b = FALSE } }
423};
424
425static TranslationEntry *
426find_translation_entry_by_key (GSettings *settings,
427 const gchar *key)
428{
429 guint i;
430 gchar *schema;
431
432 g_object_get (settings, "schema", &schema, NULL);
433
434 for (i = 0; i < G_N_ELEMENTS (translations); i++)
435 {
436 if (g_str_equal (schema, translations[i].schema) &&
437 g_str_equal (key, translations[i].key))
438 {
439 g_free (schema);
440 return &translations[i];
441 }
442 }
443
444 g_free (schema);
445
446 return NULL;
447}
448
449static TranslationEntry *
450find_translation_entry_by_setting (const gchar *setting)
451{
452 guint i;
453
454 for (i = 0; i < G_N_ELEMENTS (translations); i++)
455 {
456 if (g_str_equal (setting, translations[i].setting))
457 return &translations[i];
458 }
459
460 return NULL;
461}
462
463static void
464settings_changed (GSettings *settings,
465 const gchar *key,
466 GdkScreen *screen)
467{
468 TranslationEntry *entry;
469
470 entry = find_translation_entry_by_key (settings, key);
471
472 if (entry != NULL)
473 {
474 if (entry->type != G_TYPE_NONE)
475 notify_setting (screen, entry->setting);
476 else
477 update_xft_settings (screen);
478 }
479}
480
481static void
482init_settings (GdkScreen *screen)
483{
484 GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen);
485 GSettingsSchemaSource *source;
486 GSettingsSchema *schema;
487 GSettings *settings;
488 gint i;
489
490 screen_wayland->settings = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
491
492 source = g_settings_schema_source_get_default ();
493 if (source == NULL)
494 return;
495
496 for (i = 0; i < G_N_ELEMENTS (translations); i++)
497 {
498 if (g_hash_table_lookup (screen_wayland->settings, (gpointer)translations[i].schema) != NULL)
499 continue;
500
501 schema = g_settings_schema_source_lookup (source, translations[i].schema, TRUE);
502 if (schema != NULL)
503 {
504 settings = g_settings_new_full (schema, NULL, NULL);
505 g_signal_connect (settings, "changed",
506 G_CALLBACK (settings_changed), screen);
507 g_hash_table_insert (screen_wayland->settings, (gpointer)translations[i].schema, settings);
508 g_settings_schema_unref (schema);
509 }
510 }
511
512 update_xft_settings (screen);
513}
514
515static void
516gtk_shell_handle_capabilities (void *data,
517 struct gtk_shell1 *shell,
518 uint32_t capabilities)
519{
520 GdkScreen *screen = data;
521 GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (data);
522
523 screen_wayland->shell_capabilities = capabilities;
524
525 notify_setting (screen, "gtk-shell-shows-app-menu");
526 notify_setting (screen, "gtk-shell-shows-menubar");
527 notify_setting (screen, "gtk-shell-shows-desktop");
528}
529
530struct gtk_shell1_listener gdk_screen_gtk_shell_listener = {
531 gtk_shell_handle_capabilities
532};
533
534void
535_gdk_wayland_screen_set_has_gtk_shell (GdkScreen *screen)
536{
537 GdkWaylandDisplay *display_wayland =
538 GDK_WAYLAND_DISPLAY (GDK_WAYLAND_SCREEN (screen)->display);
539
540 gtk_shell1_add_listener (display_wayland->gtk_shell,
541 &gdk_screen_gtk_shell_listener,
542 screen);
543}
544
545static void
546set_value_from_entry (GdkScreen *screen,
547 TranslationEntry *entry,
548 GValue *value)
549{
550 GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen);
551 GSettings *settings;
552
553 settings = (GSettings *)g_hash_table_lookup (screen_wayland->settings, entry->schema);
554 switch (entry->type)
555 {
556 case G_TYPE_STRING:
557 if (settings)
558 {
559 gchar *s;
560 s = g_settings_get_string (settings, entry->key);
561 g_value_set_string (value, s);
562 g_free (s);
563 }
564 else
565 {
566 g_value_set_static_string (value, entry->fallback.s);
567 }
568 break;
569 case G_TYPE_INT:
570 g_value_set_int (value, settings != NULL
571 ? g_settings_get_int (settings, entry->key)
572 : entry->fallback.i);
573 break;
574 case G_TYPE_BOOLEAN:
575 g_value_set_boolean (value, settings != NULL
576 ? g_settings_get_boolean (settings, entry->key)
577 : entry->fallback.b);
578 break;
579 case G_TYPE_NONE:
580 if (g_str_equal (entry->setting, "gtk-xft-antialias"))
581 g_value_set_int (value, screen_wayland->xft_settings.antialias);
582 else if (g_str_equal (entry->setting, "gtk-xft-hinting"))
583 g_value_set_int (value, screen_wayland->xft_settings.hinting);
584 else if (g_str_equal (entry->setting, "gtk-xft-hintstyle"))
585 g_value_set_static_string (value, screen_wayland->xft_settings.hintstyle);
586 else if (g_str_equal (entry->setting, "gtk-xft-rgba"))
587 g_value_set_static_string (value, screen_wayland->xft_settings.rgba);
588 else if (g_str_equal (entry->setting, "gtk-xft-dpi"))
589 g_value_set_int (value, screen_wayland->xft_settings.dpi);
590 else
591 g_assert_not_reached ();
592 break;
593 default:
594 g_assert_not_reached ();
595 }
596}
597
598static void
599set_decoration_layout_from_entry (GdkScreen *screen,
600 TranslationEntry *entry,
601 GValue *value)
602{
603 GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen);
604 GSettings *settings = NULL;
605 const char *session;
606
607 /* Hack: until we get session-dependent defaults in GSettings,
608 * swap out the usual schema for the "classic" one when
609 * running in classic mode
610 */
611 session = g_getenv ("XDG_CURRENT_DESKTOP");
612 if (session && strstr (session, "GNOME-Classic"))
613 settings = (GSettings *)g_hash_table_lookup (screen_wayland->settings, CLASSIC_WM_SETTINGS_SCHEMA);
614
615 if (settings == NULL)
616 settings = (GSettings *)g_hash_table_lookup (screen_wayland->settings, WM_SETTINGS_SCHEMA);
617
618 if (settings)
619 {
620 gchar *s = g_settings_get_string (settings, entry->key);
621
622 translate_wm_button_layout_to_gtk (s);
623 g_value_set_string (value, s);
624
625 g_free (s);
626 }
627 else
628 {
629 g_value_set_static_string (value, entry->fallback.s);
630 }
631}
632
633static gboolean
634set_capability_setting (GdkScreen *screen,
635 GValue *value,
636 enum gtk_shell1_capability test)
637{
638 GdkWaylandScreen *wayland_screen = GDK_WAYLAND_SCREEN (screen);
639
640 g_value_set_boolean (value, (wayland_screen->shell_capabilities & test) == test);
641
642 return TRUE;
643}
644
645static gboolean
646gdk_wayland_screen_get_setting (GdkScreen *screen,
647 const gchar *name,
648 GValue *value)
649{
650 TranslationEntry *entry;
651
652 g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
653
654 entry = find_translation_entry_by_setting (name);
655 if (entry != NULL)
656 {
657 if (strcmp (name, "gtk-decoration-layout") == 0)
658 set_decoration_layout_from_entry (screen, entry, value);
659 else
660 set_value_from_entry (screen, entry, value);
661 return TRUE;
662 }
663
664 if (strcmp (name, "gtk-shell-shows-app-menu") == 0)
665 return set_capability_setting (screen, value,
666 GTK_SHELL1_CAPABILITY_GLOBAL_APP_MENU);
667
668 if (strcmp (name, "gtk-shell-shows-menubar") == 0)
669 return set_capability_setting (screen, value,
670 GTK_SHELL1_CAPABILITY_GLOBAL_MENU_BAR);
671
672 if (strcmp (name, "gtk-shell-shows-desktop") == 0)
673 return set_capability_setting (screen, value,
674 GTK_SHELL1_CAPABILITY_DESKTOP_ICONS);
675
676 if (strcmp (name, "gtk-dialogs-use-header") == 0)
677 {
678 g_value_set_boolean (value, TRUE);
679 return TRUE;
680 }
681
682 return FALSE;
683}
684
685typedef struct _GdkWaylandVisual GdkWaylandVisual;
686typedef struct _GdkWaylandVisualClass GdkWaylandVisualClass;
687
688struct _GdkWaylandVisual
689{
690 GdkVisual visual;
691};
692
693struct _GdkWaylandVisualClass
694{
695 GdkVisualClass parent_class;
696};
697
698GType _gdk_wayland_visual_get_type (void);
699
700G_DEFINE_TYPE (GdkWaylandVisual, _gdk_wayland_visual, GDK_TYPE_VISUAL)
701
702static void
703_gdk_wayland_visual_class_init (GdkWaylandVisualClass *klass)
704{
705}
706
707static void
708_gdk_wayland_visual_init (GdkWaylandVisual *visual)
709{
710}
711
712static gint
713gdk_wayland_screen_visual_get_best_depth (GdkScreen *screen)
714{
715 return 32;
716}
717
718static GdkVisualType
719gdk_wayland_screen_visual_get_best_type (GdkScreen *screen)
720{
721 return GDK_VISUAL_TRUE_COLOR;
722}
723
724static GdkVisual*
725gdk_wayland_screen_visual_get_best (GdkScreen *screen)
726{
727 return GDK_WAYLAND_SCREEN (screen)->visual;
728}
729
730static GdkVisual*
731gdk_wayland_screen_visual_get_best_with_depth (GdkScreen *screen,
732 gint depth)
733{
734 if (depth == 32)
735 return GDK_WAYLAND_SCREEN (screen)->visual;
736 else
737 return NULL;
738}
739
740static GdkVisual*
741gdk_wayland_screen_visual_get_best_with_type (GdkScreen *screen,
742 GdkVisualType visual_type)
743{
744 if (visual_type == GDK_VISUAL_TRUE_COLOR)
745 return GDK_WAYLAND_SCREEN (screen)->visual;
746 else
747 return NULL;
748}
749
750static GdkVisual*
751gdk_wayland_screen_visual_get_best_with_both (GdkScreen *screen,
752 gint depth,
753 GdkVisualType visual_type)
754{
755 if (depth == 32 && visual_type == GDK_VISUAL_TRUE_COLOR)
756 return GDK_WAYLAND_SCREEN (screen)->visual;
757 else
758 return NULL;
759}
760
761static void
762gdk_wayland_screen_query_depths (GdkScreen *screen,
763 gint **depths,
764 gint *count)
765{
766 static gint static_depths[] = { 32 };
767
768 *count = G_N_ELEMENTS(static_depths);
769 *depths = static_depths;
770}
771
772static void
773gdk_wayland_screen_query_visual_types (GdkScreen *screen,
774 GdkVisualType **visual_types,
775 gint *count)
776{
777 static GdkVisualType static_visual_types[] = { GDK_VISUAL_TRUE_COLOR };
778
779 *count = G_N_ELEMENTS(static_visual_types);
780 *visual_types = static_visual_types;
781}
782
783static GList *
784gdk_wayland_screen_list_visuals (GdkScreen *screen)
785{
786 GList *list;
787 GdkWaylandScreen *screen_wayland;
788
789 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
790 screen_wayland = GDK_WAYLAND_SCREEN (screen);
791
792 list = g_list_append (NULL, screen_wayland->visual);
793
794 return list;
795}
796
797#define GDK_TYPE_WAYLAND_VISUAL (_gdk_wayland_visual_get_type ())
798#define GDK_WAYLAND_VISUAL(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_VISUAL, GdkWaylandVisual))
799
800/* Currently, the Wayland backend only ever uses ARGB8888.
801 */
802static GdkVisual *
803gdk_wayland_visual_new (GdkScreen *screen)
804{
805 GdkVisual *visual;
806
807 visual = g_object_new (GDK_TYPE_WAYLAND_VISUAL, NULL);
808 visual->screen = GDK_SCREEN (screen);
809 visual->type = GDK_VISUAL_TRUE_COLOR;
810 visual->depth = 32;
811 visual->red_mask = 0xff0000;
812 visual->green_mask = 0x00ff00;
813 visual->blue_mask = 0x0000ff;
814 visual->bits_per_rgb = 8;
815
816 return visual;
817}
818
819GdkScreen *
820_gdk_wayland_screen_new (GdkDisplay *display)
821{
822 GdkScreen *screen;
823 GdkWaylandScreen *screen_wayland;
824
825 screen = g_object_new (GDK_TYPE_WAYLAND_SCREEN, NULL);
826
827 screen_wayland = GDK_WAYLAND_SCREEN (screen);
828 screen_wayland->display = display;
829 screen_wayland->width = 0;
830 screen_wayland->height = 0;
831
832 screen_wayland->visual = gdk_wayland_visual_new (screen);
833
834 screen_wayland->root_window =
835 _gdk_wayland_screen_create_root_window (screen,
836 screen_wayland->width,
837 screen_wayland->height);
838
839 init_settings (screen);
840
841 return screen;
842}
843
844static void
845_gdk_wayland_screen_class_init (GdkWaylandScreenClass *klass)
846{
847 GObjectClass *object_class = G_OBJECT_CLASS (klass);
848 GdkScreenClass *screen_class = GDK_SCREEN_CLASS (klass);
849
850 object_class->dispose = gdk_wayland_screen_dispose;
851 object_class->finalize = gdk_wayland_screen_finalize;
852
853 screen_class->get_display = gdk_wayland_screen_get_display;
854 screen_class->get_width = gdk_wayland_screen_get_width;
855 screen_class->get_height = gdk_wayland_screen_get_height;
856 screen_class->get_width_mm = gdk_wayland_screen_get_width_mm;
857 screen_class->get_height_mm = gdk_wayland_screen_get_height_mm;
858 screen_class->get_number = gdk_wayland_screen_get_number;
859 screen_class->get_root_window = gdk_wayland_screen_get_root_window;
860 screen_class->get_system_visual = gdk_wayland_screen_get_system_visual;
861 screen_class->get_rgba_visual = gdk_wayland_screen_get_rgba_visual;
862 screen_class->is_composited = gdk_wayland_screen_is_composited;
863 screen_class->make_display_name = gdk_wayland_screen_make_display_name;
864 screen_class->get_active_window = gdk_wayland_screen_get_active_window;
865 screen_class->get_window_stack = gdk_wayland_screen_get_window_stack;
866 screen_class->broadcast_client_message = gdk_wayland_screen_broadcast_client_message;
867 screen_class->get_setting = gdk_wayland_screen_get_setting;
868 screen_class->visual_get_best_depth = gdk_wayland_screen_visual_get_best_depth;
869 screen_class->visual_get_best_type = gdk_wayland_screen_visual_get_best_type;
870 screen_class->visual_get_best = gdk_wayland_screen_visual_get_best;
871 screen_class->visual_get_best_with_depth = gdk_wayland_screen_visual_get_best_with_depth;
872 screen_class->visual_get_best_with_type = gdk_wayland_screen_visual_get_best_with_type;
873 screen_class->visual_get_best_with_both = gdk_wayland_screen_visual_get_best_with_both;
874 screen_class->query_depths = gdk_wayland_screen_query_depths;
875 screen_class->query_visual_types = gdk_wayland_screen_query_visual_types;
876 screen_class->list_visuals = gdk_wayland_screen_list_visuals;
877}
878
879static void
880_gdk_wayland_screen_init (GdkWaylandScreen *screen_wayland)
881{
882}
883
884static void
885update_screen_size (GdkWaylandScreen *screen_wayland)
886{
887 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (screen_wayland->display);
888 gboolean emit_changed = FALSE;
889 gint width, height;
890 gint width_mm, height_mm;
891 int i;
892
893 width = height = 0;
894 width_mm = height_mm = 0;
895 for (i = 0; i < display_wayland->monitors->len; i++)
896 {
897 GdkMonitor *monitor = display_wayland->monitors->pdata[i];
898
899 /* XXX: Largely assuming here that monitor areas
900 * are contiguous and never overlap.
901 */
902 if (monitor->geometry.x > 0)
903 width_mm += monitor->width_mm;
904 else
905 width_mm = MAX (width_mm, monitor->width_mm);
906
907 if (monitor->geometry.y > 0)
908 height_mm += monitor->height_mm;
909 else
910 height_mm = MAX (height_mm, monitor->height_mm);
911
912 width = MAX (width, monitor->geometry.x + monitor->geometry.width);
913 height = MAX (height, monitor->geometry.y + monitor->geometry.height);
914 }
915
916 if (screen_wayland->width_mm != width_mm ||
917 screen_wayland->height_mm != height_mm)
918 {
919 emit_changed = TRUE;
920 screen_wayland->width_mm = width_mm;
921 screen_wayland->height_mm = height_mm;
922 }
923
924 if (screen_wayland->width != width ||
925 screen_wayland->height != height)
926 {
927 emit_changed = TRUE;
928 screen_wayland->width = width;
929 screen_wayland->height = height;
930 }
931
932 if (emit_changed)
933 g_signal_emit_by_name (screen_wayland, "size-changed");
934}
935
936#ifdef G_ENABLE_DEBUG
937
938static const char *
939subpixel_to_string (int layout)
940{
941 int i;
942 struct { int layout; const char *name; } layouts[] = {
943 { WL_OUTPUT_SUBPIXEL_UNKNOWN, "unknown" },
944 { WL_OUTPUT_SUBPIXEL_NONE, "none" },
945 { WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB, "rgb" },
946 { WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR, "bgr" },
947 { WL_OUTPUT_SUBPIXEL_VERTICAL_RGB, "vrgb" },
948 { WL_OUTPUT_SUBPIXEL_VERTICAL_BGR, "vbgr" },
949 { 0xffffffff, NULL }
950 };
951
952 for (i = 0; layouts[i].name; i++)
953 {
954 if (layouts[i].layout == layout)
955 return layouts[i].name;
956 }
957 return NULL;
958}
959
960static const char *
961transform_to_string (int transform)
962{
963 int i;
964 struct { int transform; const char *name; } transforms[] = {
965 { WL_OUTPUT_TRANSFORM_NORMAL, "normal" },
966 { WL_OUTPUT_TRANSFORM_90, "90" },
967 { WL_OUTPUT_TRANSFORM_180, "180" },
968 { WL_OUTPUT_TRANSFORM_270, "270" },
969 { WL_OUTPUT_TRANSFORM_FLIPPED, "flipped" },
970 { WL_OUTPUT_TRANSFORM_FLIPPED_90, "flipped 90" },
971 { WL_OUTPUT_TRANSFORM_FLIPPED_180, "flipped 180" },
972 { WL_OUTPUT_TRANSFORM_FLIPPED_270, "flipped 270" },
973 { 0xffffffff, NULL }
974 };
975
976 for (i = 0; transforms[i].name; i++)
977 {
978 if (transforms[i].transform == transform)
979 return transforms[i].name;
980 }
981 return NULL;
982}
983
984#endif
985
986static void
987output_handle_geometry (void *data,
988 struct wl_output *wl_output,
989 int x,
990 int y,
991 int physical_width,
992 int physical_height,
993 int subpixel,
994 const char *make,
995 const char *model,
996 int32_t transform)
997{
998 GdkWaylandMonitor *monitor = (GdkWaylandMonitor *)data;
999
1000 GDK_NOTE (MISC,
1001 g_message ("handle geometry output %d, position %d %d, phys. size %d %d, subpixel layout %s, manufacturer %s, model %s, transform %s",
1002 monitor->id, x, y, physical_width, physical_height, subpixel_to_string (subpixel), make, model, transform_to_string (transform)));
1003
1004 gdk_monitor_set_position (GDK_MONITOR (monitor), x, y);
1005 gdk_monitor_set_physical_size (GDK_MONITOR (monitor), physical_width, physical_height);
1006 gdk_monitor_set_subpixel_layout (GDK_MONITOR (monitor), subpixel);
1007 gdk_monitor_set_manufacturer (GDK_MONITOR (monitor), make);
1008 gdk_monitor_set_model (GDK_MONITOR (monitor), model);
1009
1010 if (GDK_MONITOR (monitor)->geometry.width != 0 && monitor->version < OUTPUT_VERSION_WITH_DONE)
1011 {
1012 GdkDisplay *display = GDK_MONITOR (monitor)->display;
1013 GdkWaylandScreen *screen = GDK_WAYLAND_SCREEN (gdk_display_get_default_screen (display));
1014 g_signal_emit_by_name (screen, "monitors-changed");
1015 update_screen_size (screen);
1016 }
1017}
1018
1019static void
1020output_handle_done (void *data,
1021 struct wl_output *wl_output)
1022{
1023 GdkWaylandMonitor *monitor = (GdkWaylandMonitor *)data;
1024 GdkDisplay *display = gdk_monitor_get_display (GDK_MONITOR (monitor));
1025 GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (gdk_display_get_default_screen (display));
1026
1027 GDK_NOTE (MISC,
1028 g_message ("handle done output %d", monitor->id));
1029
1030 if (!monitor->added)
1031 {
1032 monitor->added = TRUE;
1033 g_ptr_array_add (GDK_WAYLAND_DISPLAY (display)->monitors, monitor);
1034 gdk_display_monitor_added (display, GDK_MONITOR (monitor));
1035 }
1036
1037 g_signal_emit_by_name (screen_wayland, "monitors-changed");
1038 update_screen_size (screen_wayland);
1039}
1040
1041static void
1042output_handle_scale (void *data,
1043 struct wl_output *wl_output,
1044 int32_t scale)
1045{
1046 GdkWaylandMonitor *monitor = (GdkWaylandMonitor *)data;
1047
1048 GDK_NOTE (MISC,
1049 g_message ("handle scale output %d, scale %d", monitor->id, scale));
1050
1051 gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), scale);
1052
1053 if (GDK_MONITOR (monitor)->geometry.width != 0 && monitor->version < OUTPUT_VERSION_WITH_DONE)
1054 {
1055 GdkScreen *screen = gdk_display_get_default_screen (GDK_MONITOR (monitor)->display);
1056 g_signal_emit_by_name (screen, "monitors-changed");
1057 }
1058}
1059
1060static void
1061output_handle_mode (void *data,
1062 struct wl_output *wl_output,
1063 uint32_t flags,
1064 int width,
1065 int height,
1066 int refresh)
1067{
1068 GdkWaylandMonitor *monitor = (GdkWaylandMonitor *)data;
1069
1070 GDK_NOTE (MISC,
1071 g_message ("handle mode output %d, size %d %d, rate %d",
1072 monitor->id, width, height, refresh));
1073
1074 if ((flags & WL_OUTPUT_MODE_CURRENT) == 0)
1075 return;
1076
1077 gdk_monitor_set_size (GDK_MONITOR (monitor), width, height);
1078 gdk_monitor_set_refresh_rate (GDK_MONITOR (monitor), refresh);
1079
1080 if (width != 0 && monitor->version < OUTPUT_VERSION_WITH_DONE)
1081 {
1082 GdkScreen *screen = gdk_display_get_default_screen (GDK_MONITOR (monitor)->display);
1083 g_signal_emit_by_name (screen, "monitors-changed");
1084 update_screen_size (GDK_WAYLAND_SCREEN (screen));
1085 }
1086}
1087
1088static const struct wl_output_listener output_listener =
1089{
1090 output_handle_geometry,
1091 output_handle_mode,
1092 output_handle_done,
1093 output_handle_scale,
1094};
1095
1096void
1097_gdk_wayland_screen_add_output (GdkScreen *screen,
1098 guint32 id,
1099 struct wl_output *output,
1100 guint32 version)
1101{
1102 GdkDisplay *display = gdk_screen_get_display (screen);
1103 GdkWaylandMonitor *monitor;
1104
1105 monitor = g_object_new (GDK_TYPE_WAYLAND_MONITOR,
1106 "display", display,
1107 NULL);
1108
1109 monitor->id = id;
1110 monitor->output = output;
1111 monitor->version = version;
1112
1113 if (monitor->version < OUTPUT_VERSION_WITH_DONE)
1114 {
1115 g_ptr_array_add (GDK_WAYLAND_DISPLAY (display)->monitors, monitor);
1116 gdk_display_monitor_added (display, GDK_MONITOR (monitor));
1117 }
1118
1119 wl_output_add_listener (output, &output_listener, monitor);
1120}
1121
1122struct wl_output *
1123_gdk_wayland_screen_get_wl_output (GdkScreen *screen,
1124 gint monitor_num)
1125{
1126 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (GDK_WAYLAND_SCREEN (screen)->display);
1127 GdkWaylandMonitor *monitor;
1128
1129 monitor = display_wayland->monitors->pdata[monitor_num];
1130
1131 return monitor->output;
1132}
1133
1134static GdkWaylandMonitor *
1135get_monitor_for_id (GdkWaylandScreen *screen_wayland,
1136 guint32 id)
1137{
1138 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (screen_wayland->display);
1139 int i;
1140
1141 for (i = 0; i < display_wayland->monitors->len; i++)
1142 {
1143 GdkWaylandMonitor *monitor = display_wayland->monitors->pdata[i];
1144
1145 if (monitor->id == id)
1146 return monitor;
1147 }
1148
1149 return NULL;
1150}
1151
1152static GdkWaylandMonitor *
1153get_monitor_for_output (GdkWaylandScreen *screen_wayland,
1154 struct wl_output *output)
1155{
1156 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (screen_wayland->display);
1157 int i;
1158
1159 for (i = 0; i < display_wayland->monitors->len; i++)
1160 {
1161 GdkWaylandMonitor *monitor = display_wayland->monitors->pdata[i];
1162
1163 if (monitor->output == output)
1164 return monitor;
1165 }
1166
1167 return NULL;
1168}
1169
1170void
1171_gdk_wayland_screen_remove_output (GdkScreen *screen,
1172 guint32 id)
1173{
1174 GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen);
1175 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (screen_wayland->display);
1176 GdkWaylandMonitor *monitor;
1177
1178 monitor = get_monitor_for_id (screen_wayland, id);
1179 if (monitor != NULL)
1180 {
1181 g_object_ref (monitor);
1182 g_ptr_array_remove (display_wayland->monitors, monitor);
1183 gdk_display_monitor_removed (GDK_DISPLAY (display_wayland), GDK_MONITOR (monitor));
1184 g_object_unref (monitor);
1185 g_signal_emit_by_name (screen_wayland, "monitors-changed");
1186 update_screen_size (screen_wayland);
1187 }
1188}
1189
1190int
1191_gdk_wayland_screen_get_output_refresh_rate (GdkScreen *screen,
1192 struct wl_output *output)
1193{
1194 GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen);
1195 GdkWaylandMonitor *monitor;
1196
1197 monitor = get_monitor_for_output (screen_wayland, output);
1198 if (monitor != NULL)
1199 return gdk_monitor_get_refresh_rate (GDK_MONITOR (monitor));
1200
1201 return 0;
1202}
1203
1204guint32
1205_gdk_wayland_screen_get_output_scale (GdkScreen *screen,
1206 struct wl_output *output)
1207{
1208 GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen);
1209 GdkWaylandMonitor *monitor;
1210
1211 monitor = get_monitor_for_output (screen_wayland, output);
1212 if (monitor != NULL)
1213 return gdk_monitor_get_scale_factor (GDK_MONITOR (monitor));
1214
1215 return 0;
1216}
1217