/* * Copyright © 2010 Intel Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library. If not, see . */ #include "config.h" #include #include #include #include #include "gdkscreenprivate.h" #include "gdkvisualprivate.h" #include "gdkdisplay.h" #include "gdkdisplay-wayland.h" #include "gdkwayland.h" #include "gdkprivate-wayland.h" #include "wm-button-layout-translation.h" typedef struct _GdkWaylandScreen GdkWaylandScreen; typedef struct _GdkWaylandScreenClass GdkWaylandScreenClass; #define GDK_TYPE_WAYLAND_SCREEN (_gdk_wayland_screen_get_type ()) #define GDK_WAYLAND_SCREEN(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_SCREEN, GdkWaylandScreen)) #define GDK_WAYLAND_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WAYLAND_SCREEN, GdkWaylandScreenClass)) #define GDK_IS_WAYLAND_SCREEN(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_SCREEN)) #define GDK_IS_WAYLAND_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WAYLAND_SCREEN)) #define GDK_WAYLAND_SCREEN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WAYLAND_SCREEN, GdkWaylandScreenClass)) typedef struct { gboolean antialias; gboolean hinting; gint dpi; const gchar *rgba; const gchar *hintstyle; } GsdXftSettings; typedef struct _GdkWaylandMonitor GdkWaylandMonitor; struct _GdkWaylandScreen { GdkScreen parent_instance; GdkDisplay *display; GdkWindow *root_window; int width, height; int width_mm, height_mm; /* Visual Part */ GdkVisual *visual; /* Xinerama/RandR 1.2 */ GPtrArray *monitors; gint primary_monitor; GHashTable *settings; GsdXftSettings xft_settings; guint32 shell_capabilities; }; struct _GdkWaylandScreenClass { GdkScreenClass parent_class; void (* window_manager_changed) (GdkWaylandScreen *screen_wayland); }; #define OUTPUT_VERSION_WITH_DONE 2 struct _GdkWaylandMonitor { GdkWaylandScreen *screen; guint32 id; guint32 version; struct wl_output *output; GdkRectangle geometry; int width_mm; int height_mm; char * output_name; char * manufacturer; int refresh_rate; gint scale; }; GType _gdk_wayland_screen_get_type (void); G_DEFINE_TYPE (GdkWaylandScreen, _gdk_wayland_screen, GDK_TYPE_SCREEN) static void free_monitor (gpointer data) { GdkWaylandMonitor *monitor = data; if (monitor == NULL) return; wl_output_destroy (monitor->output); g_free (monitor->output_name); g_free (monitor->manufacturer); g_free (monitor); } static void deinit_multihead (GdkScreen *screen) { GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen); g_ptr_array_free (screen_wayland->monitors, TRUE); screen_wayland->monitors = NULL; } static void init_multihead (GdkScreen *screen) { GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen); screen_wayland->monitors = g_ptr_array_new_with_free_func (free_monitor); screen_wayland->primary_monitor = 0; } static void gdk_wayland_screen_dispose (GObject *object) { GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (object); if (screen_wayland->root_window) _gdk_window_destroy (screen_wayland->root_window, FALSE); G_OBJECT_CLASS (_gdk_wayland_screen_parent_class)->dispose (object); } static void gdk_wayland_screen_finalize (GObject *object) { GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (object); if (screen_wayland->root_window) g_object_unref (screen_wayland->root_window); g_object_unref (screen_wayland->visual); deinit_multihead (GDK_SCREEN (object)); g_hash_table_destroy (screen_wayland->settings); G_OBJECT_CLASS (_gdk_wayland_screen_parent_class)->finalize (object); } static GdkDisplay * gdk_wayland_screen_get_display (GdkScreen *screen) { return GDK_WAYLAND_SCREEN (screen)->display; } static gint gdk_wayland_screen_get_width (GdkScreen *screen) { return GDK_WAYLAND_SCREEN (screen)->width; } static gint gdk_wayland_screen_get_height (GdkScreen *screen) { return GDK_WAYLAND_SCREEN (screen)->height; } static gint gdk_wayland_screen_get_width_mm (GdkScreen *screen) { return GDK_WAYLAND_SCREEN (screen)->width_mm; } static gint gdk_wayland_screen_get_height_mm (GdkScreen *screen) { return GDK_WAYLAND_SCREEN (screen)->height_mm; } static gint gdk_wayland_screen_get_number (GdkScreen *screen) { return 0; } static GdkWindow * gdk_wayland_screen_get_root_window (GdkScreen *screen) { return GDK_WAYLAND_SCREEN (screen)->root_window; } static gint gdk_wayland_screen_get_n_monitors (GdkScreen *screen) { return GDK_WAYLAND_SCREEN (screen)->monitors->len; } static gint gdk_wayland_screen_get_primary_monitor (GdkScreen *screen) { return GDK_WAYLAND_SCREEN (screen)->primary_monitor; } static gint gdk_wayland_screen_get_monitor_width_mm (GdkScreen *screen, gint monitor_num) { GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen); GdkWaylandMonitor *monitor; monitor = g_ptr_array_index (screen_wayland->monitors, monitor_num); return monitor->width_mm; } static gint gdk_wayland_screen_get_monitor_height_mm (GdkScreen *screen, gint monitor_num) { GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen); GdkWaylandMonitor *monitor; monitor = g_ptr_array_index (screen_wayland->monitors, monitor_num); return monitor->height_mm; } static gchar * gdk_wayland_screen_get_monitor_plug_name (GdkScreen *screen, gint monitor_num) { GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen); GdkWaylandMonitor *monitor; monitor = g_ptr_array_index (screen_wayland->monitors, monitor_num); return g_strdup (monitor->output_name); } static void gdk_wayland_screen_get_monitor_geometry (GdkScreen *screen, gint monitor_num, GdkRectangle *dest) { GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen); GdkWaylandMonitor *monitor; monitor = g_ptr_array_index (screen_wayland->monitors, monitor_num); if (dest) *dest = monitor->geometry; } static gint gdk_wayland_screen_get_monitor_scale_factor (GdkScreen *screen, gint monitor_num) { GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen); GdkWaylandMonitor *monitor; monitor = g_ptr_array_index (screen_wayland->monitors, monitor_num); return monitor->scale; } static GdkVisual * gdk_wayland_screen_get_system_visual (GdkScreen * screen) { return (GdkVisual *) GDK_WAYLAND_SCREEN (screen)->visual; } static GdkVisual * gdk_wayland_screen_get_rgba_visual (GdkScreen *screen) { return (GdkVisual *) GDK_WAYLAND_SCREEN (screen)->visual; } static gboolean gdk_wayland_screen_is_composited (GdkScreen *screen) { return TRUE; } static gchar * gdk_wayland_screen_make_display_name (GdkScreen *screen) { return g_strdup (gdk_display_get_name (GDK_WAYLAND_SCREEN (screen)->display)); } static GdkWindow * gdk_wayland_screen_get_active_window (GdkScreen *screen) { return NULL; } static GList * gdk_wayland_screen_get_window_stack (GdkScreen *screen) { return NULL; } static void gdk_wayland_screen_broadcast_client_message (GdkScreen *screen, GdkEvent *event) { } static void notify_setting (GdkScreen *screen, const gchar *setting) { GdkEvent event; event.type = GDK_SETTING; event.setting.window = gdk_screen_get_root_window (screen); event.setting.send_event = FALSE; event.setting.action = GDK_SETTING_ACTION_CHANGED; event.setting.name = (gchar *)setting; gdk_event_put (&event); } typedef enum { GSD_FONT_ANTIALIASING_MODE_NONE, GSD_FONT_ANTIALIASING_MODE_GRAYSCALE, GSD_FONT_ANTIALIASING_MODE_RGBA } GsdFontAntialiasingMode; typedef enum { GSD_FONT_HINTING_NONE, GSD_FONT_HINTING_SLIGHT, GSD_FONT_HINTING_MEDIUM, GSD_FONT_HINTING_FULL } GsdFontHinting; typedef enum { GSD_FONT_RGBA_ORDER_RGBA, GSD_FONT_RGBA_ORDER_RGB, GSD_FONT_RGBA_ORDER_BGR, GSD_FONT_RGBA_ORDER_VRGB, GSD_FONT_RGBA_ORDER_VBGR } GsdFontRgbaOrder; static gdouble get_dpi_from_gsettings (GdkWaylandScreen *screen_wayland) { GSettings *settings; gdouble factor; settings = g_hash_table_lookup (screen_wayland->settings, "org.gnome.desktop.interface"); if (settings != NULL) factor = g_settings_get_double (settings, "text-scaling-factor"); else factor = 1.0; return 96.0 * factor; } static void update_xft_settings (GdkScreen *screen) { GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen); GSettings *settings; GsdFontAntialiasingMode antialiasing; GsdFontHinting hinting; GsdFontRgbaOrder order; gboolean use_rgba = FALSE; GsdXftSettings xft_settings; settings = g_hash_table_lookup (screen_wayland->settings, "org.gnome.settings-daemon.plugins.xsettings"); if (settings) { antialiasing = g_settings_get_enum (settings, "antialiasing"); hinting = g_settings_get_enum (settings, "hinting"); order = g_settings_get_enum (settings, "rgba-order"); } else { antialiasing = GSD_FONT_ANTIALIASING_MODE_GRAYSCALE; hinting = GSD_FONT_HINTING_MEDIUM; order = GSD_FONT_RGBA_ORDER_RGB; } xft_settings.antialias = (antialiasing != GSD_FONT_ANTIALIASING_MODE_NONE); xft_settings.hinting = (hinting != GSD_FONT_HINTING_NONE); xft_settings.dpi = get_dpi_from_gsettings (screen_wayland) * 1024; /* Xft wants 1/1024ths of an inch */ xft_settings.rgba = "rgb"; xft_settings.hintstyle = "hintfull"; switch (hinting) { case GSD_FONT_HINTING_NONE: xft_settings.hintstyle = "hintnone"; break; case GSD_FONT_HINTING_SLIGHT: xft_settings.hintstyle = "hintslight"; break; case GSD_FONT_HINTING_MEDIUM: xft_settings.hintstyle = "hintmedium"; break; case GSD_FONT_HINTING_FULL: xft_settings.hintstyle = "hintfull"; break; } switch (order) { case GSD_FONT_RGBA_ORDER_RGBA: xft_settings.rgba = "rgba"; break; case GSD_FONT_RGBA_ORDER_RGB: xft_settings.rgba = "rgb"; break; case GSD_FONT_RGBA_ORDER_BGR: xft_settings.rgba = "bgr"; break; case GSD_FONT_RGBA_ORDER_VRGB: xft_settings.rgba = "vrgb"; break; case GSD_FONT_RGBA_ORDER_VBGR: xft_settings.rgba = "vbgr"; break; } switch (antialiasing) { case GSD_FONT_ANTIALIASING_MODE_NONE: xft_settings.antialias = FALSE; break; case GSD_FONT_ANTIALIASING_MODE_GRAYSCALE: xft_settings.antialias = TRUE; break; case GSD_FONT_ANTIALIASING_MODE_RGBA: xft_settings.antialias = TRUE; use_rgba = TRUE; } if (!use_rgba) xft_settings.rgba = "none"; if (screen_wayland->xft_settings.antialias != xft_settings.antialias) { screen_wayland->xft_settings.antialias = xft_settings.antialias; notify_setting (screen, "gtk-xft-antialias"); } if (screen_wayland->xft_settings.hinting != xft_settings.hinting) { screen_wayland->xft_settings.hinting = xft_settings.hinting; notify_setting (screen, "gtk-xft-hinting"); } if (screen_wayland->xft_settings.hintstyle != xft_settings.hintstyle) { screen_wayland->xft_settings.hintstyle = xft_settings.hintstyle; notify_setting (screen, "gtk-xft-hintstyle"); } if (screen_wayland->xft_settings.rgba != xft_settings.rgba) { screen_wayland->xft_settings.rgba = xft_settings.rgba; notify_setting (screen, "gtk-xft-rgba"); } if (screen_wayland->xft_settings.dpi != xft_settings.dpi) { double dpi = xft_settings.dpi / 1024.; const char *scale_env; double scale; screen_wayland->xft_settings.dpi = xft_settings.dpi; scale_env = g_getenv ("GDK_DPI_SCALE"); if (scale_env) { scale = g_ascii_strtod (scale_env, NULL); if (scale != 0 && dpi > 0) dpi *= scale; } _gdk_screen_set_resolution (screen, dpi); notify_setting (screen, "gtk-xft-dpi"); } } #define WM_SETTINGS_SCHEMA "org.gnome.desktop.wm.preferences" #define CLASSIC_WM_SETTINGS_SCHEMA "org.gnome.shell.extensions.classic-overrides" typedef struct _TranslationEntry TranslationEntry; struct _TranslationEntry { const gchar *schema; const gchar *key; const gchar *setting; GType type; union { const gchar *s; gint i; gboolean b; } fallback; }; static TranslationEntry translations[] = { { "org.gnome.desktop.interface", "gtk-theme", "gtk-theme-name" , G_TYPE_STRING, { .s = "Adwaita" } }, { "org.gnome.desktop.interface", "icon-theme", "gtk-icon-theme-name", G_TYPE_STRING, { .s = "gnome" } }, { "org.gnome.desktop.interface", "cursor-theme", "gtk-cursor-theme-name", G_TYPE_STRING, { .s = "Adwaita" } }, { "org.gnome.desktop.interface", "cursor-size", "gtk-cursor-theme-size", G_TYPE_INT, { .i = 32 } }, { "org.gnome.desktop.interface", "font-name", "gtk-font-name", G_TYPE_STRING, { .s = "Cantarell 11" } }, { "org.gnome.desktop.interface", "cursor-blink", "gtk-cursor-blink", G_TYPE_BOOLEAN, { .b = TRUE } }, { "org.gnome.desktop.interface", "cursor-blink-time", "gtk-cursor-blink-time", G_TYPE_INT, { .i = 1200 } }, { "org.gnome.desktop.interface", "cursor-blink-timeout", "gtk-cursor-blink-timeout", G_TYPE_INT, { .i = 3600 } }, { "org.gnome.desktop.interface", "gtk-im-module", "gtk-im-module", G_TYPE_STRING, { .s = "simple" } }, { "org.gnome.desktop.interface", "enable-animations", "gtk-enable-animations", G_TYPE_BOOLEAN, { .b = TRUE } }, { "org.gnome.settings-daemon.peripherals.mouse", "double-click", "gtk-double-click-time", G_TYPE_INT, { .i = 400 } }, { "org.gnome.settings-daemon.peripherals.mouse", "drag-threshold", "gtk-dnd-drag-threshold", G_TYPE_INT, {.i = 8 } }, { "org.gnome.desktop.sound", "theme-name", "gtk-sound-theme-name", G_TYPE_STRING, { .s = "freedesktop" } }, { "org.gnome.desktop.sound", "event-sounds", "gtk-enable-event-sounds", G_TYPE_BOOLEAN, { .b = TRUE } }, { "org.gnome.desktop.sound", "input-feedback-sounds", "gtk-enable-input-feedback-sounds", G_TYPE_BOOLEAN, { . b = FALSE } }, { "org.gnome.desktop.privacy", "recent-files-max-age", "gtk-recent-files-max-age", G_TYPE_INT, { .i = 30 } }, { "org.gnome.desktop.privacy", "remember-recent-files", "gtk-recent-files-enabled", G_TYPE_BOOLEAN, { .b = TRUE } }, { WM_SETTINGS_SCHEMA, "button-layout", "gtk-decoration-layout", G_TYPE_STRING, { .s = "menu:close" } }, { CLASSIC_WM_SETTINGS_SCHEMA, "button-layout", "gtk-decoration-layout", G_TYPE_STRING, { .s = "menu:close" } }, { "org.gnome.settings-daemon.plugins.xsettings", "antialiasing", "gtk-xft-antialias", G_TYPE_NONE, { .i = 0 } }, { "org.gnome.settings-daemon.plugins.xsettings", "hinting", "gtk-xft-hinting", G_TYPE_NONE, { .i = 0 } }, { "org.gnome.settings-daemon.plugins.xsettings", "hinting", "gtk-xft-hintstyle", G_TYPE_NONE, { .i = 0 } }, { "org.gnome.settings-daemon.plugins.xsettings", "rgba-order", "gtk-xft-rgba", G_TYPE_NONE, { .i = 0 } }, { "org.gnome.desktop.interface", "text-scaling-factor", "gtk-xft-dpi" , G_TYPE_NONE, { .i = 0 } }, { "org.gnome.desktop.wm.preferences", "action-double-click-titlebar", "gtk-titlebar-double-click", G_TYPE_STRING, { .s = "toggle-maximize" } }, { "org.gnome.desktop.wm.preferences", "action-middle-click-titlebar", "gtk-titlebar-middle-click", G_TYPE_STRING, { .s = "none" } }, { "org.gnome.desktop.wm.preferences", "action-right-click-titlebar", "gtk-titlebar-right-click", G_TYPE_STRING, { .s = "menu" } }, { "org.gnome.desktop.a11y", "always-show-text-caret", "gtk-keynav-use-caret", G_TYPE_BOOLEAN, { .b = FALSE } } }; static TranslationEntry * find_translation_entry_by_key (GSettings *settings, const gchar *key) { guint i; gchar *schema; g_object_get (settings, "schema", &schema, NULL); for (i = 0; i < G_N_ELEMENTS (translations); i++) { if (g_str_equal (schema, translations[i].schema) && g_str_equal (key, translations[i].key)) { g_free (schema); return &translations[i]; } } g_free (schema); return NULL; } static TranslationEntry * find_translation_entry_by_setting (const gchar *setting) { guint i; for (i = 0; i < G_N_ELEMENTS (translations); i++) { if (g_str_equal (setting, translations[i].setting)) return &translations[i]; } return NULL; } static void settings_changed (GSettings *settings, const gchar *key, GdkScreen *screen) { TranslationEntry *entry; entry = find_translation_entry_by_key (settings, key); if (entry != NULL) { if (entry->type != G_TYPE_NONE) notify_setting (screen, entry->setting); else update_xft_settings (screen); } } static void init_settings (GdkScreen *screen) { GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen); GSettingsSchemaSource *source; GSettingsSchema *schema; GSettings *settings; gint i; screen_wayland->settings = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); source = g_settings_schema_source_get_default (); if (source == NULL) return; for (i = 0; i < G_N_ELEMENTS (translations); i++) { if (g_hash_table_lookup (screen_wayland->settings, (gpointer)translations[i].schema) != NULL) continue; schema = g_settings_schema_source_lookup (source, translations[i].schema, TRUE); if (schema != NULL) { settings = g_settings_new_full (schema, NULL, NULL); g_signal_connect (settings, "changed", G_CALLBACK (settings_changed), screen); g_hash_table_insert (screen_wayland->settings, (gpointer)translations[i].schema, settings); g_settings_schema_unref (schema); } } update_xft_settings (screen); } static void gtk_shell_handle_capabilities (void *data, struct gtk_shell1 *shell, uint32_t capabilities) { GdkScreen *screen = data; GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (data); screen_wayland->shell_capabilities = capabilities; notify_setting (screen, "gtk-shell-shows-app-menu"); notify_setting (screen, "gtk-shell-shows-menubar"); notify_setting (screen, "gtk-shell-shows-desktop"); } struct gtk_shell1_listener gdk_screen_gtk_shell_listener = { gtk_shell_handle_capabilities }; void _gdk_wayland_screen_set_has_gtk_shell (GdkScreen *screen) { GdkWaylandDisplay *wayland_display = GDK_WAYLAND_DISPLAY (GDK_WAYLAND_SCREEN (screen)->display); gtk_shell1_add_listener (wayland_display->gtk_shell, &gdk_screen_gtk_shell_listener, screen); } static void set_value_from_entry (GdkScreen *screen, TranslationEntry *entry, GValue *value) { GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen); GSettings *settings; settings = (GSettings *)g_hash_table_lookup (screen_wayland->settings, entry->schema); switch (entry->type) { case G_TYPE_STRING: if (settings) { gchar *s; s = g_settings_get_string (settings, entry->key); g_value_set_string (value, s); g_free (s); } else { g_value_set_static_string (value, entry->fallback.s); } break; case G_TYPE_INT: g_value_set_int (value, settings != NULL ? g_settings_get_int (settings, entry->key) : entry->fallback.i); break; case G_TYPE_BOOLEAN: g_value_set_boolean (value, settings != NULL ? g_settings_get_boolean (settings, entry->key) : entry->fallback.b); break; case G_TYPE_NONE: if (g_str_equal (entry->setting, "gtk-xft-antialias")) g_value_set_int (value, screen_wayland->xft_settings.antialias); else if (g_str_equal (entry->setting, "gtk-xft-hinting")) g_value_set_int (value, screen_wayland->xft_settings.hinting); else if (g_str_equal (entry->setting, "gtk-xft-hintstyle")) g_value_set_static_string (value, screen_wayland->xft_settings.hintstyle); else if (g_str_equal (entry->setting, "gtk-xft-rgba")) g_value_set_static_string (value, screen_wayland->xft_settings.rgba); else if (g_str_equal (entry->setting, "gtk-xft-dpi")) g_value_set_int (value, screen_wayland->xft_settings.dpi); else g_assert_not_reached (); break; default: g_assert_not_reached (); } } static void set_decoration_layout_from_entry (GdkScreen *screen, TranslationEntry *entry, GValue *value) { GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen); GSettings *settings = NULL; const char *session; /* Hack: until we get session-dependent defaults in GSettings, * swap out the usual schema for the "classic" one when * running in classic mode */ session = g_getenv ("XDG_CURRENT_DESKTOP"); if (session && strstr (session, "GNOME-Classic")) settings = (GSettings *)g_hash_table_lookup (screen_wayland->settings, CLASSIC_WM_SETTINGS_SCHEMA); if (settings == NULL) settings = (GSettings *)g_hash_table_lookup (screen_wayland->settings, WM_SETTINGS_SCHEMA); if (settings) { gchar *s = g_settings_get_string (settings, entry->key); translate_wm_button_layout_to_gtk (s); g_value_set_string (value, s); g_free (s); } else { g_value_set_static_string (value, entry->fallback.s); } } static gboolean set_capability_setting (GdkScreen *screen, GValue *value, enum gtk_shell1_capability test) { GdkWaylandScreen *wayland_screen = GDK_WAYLAND_SCREEN (screen); g_value_set_boolean (value, (wayland_screen->shell_capabilities & test) == test); return TRUE; } static gboolean gdk_wayland_screen_get_setting (GdkScreen *screen, const gchar *name, GValue *value) { TranslationEntry *entry; g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE); entry = find_translation_entry_by_setting (name); if (entry != NULL) { if (strcmp (name, "gtk-decoration-layout") == 0) set_decoration_layout_from_entry (screen, entry, value); else set_value_from_entry (screen, entry, value); return TRUE; } if (strcmp (name, "gtk-shell-shows-app-menu") == 0) return set_capability_setting (screen, value, GTK_SHELL1_CAPABILITY_GLOBAL_APP_MENU); if (strcmp (name, "gtk-shell-shows-menubar") == 0) return set_capability_setting (screen, value, GTK_SHELL1_CAPABILITY_GLOBAL_MENU_BAR); if (strcmp (name, "gtk-shell-shows-desktop") == 0) return set_capability_setting (screen, value, GTK_SHELL1_CAPABILITY_DESKTOP_ICONS); if (strcmp (name, "gtk-dialogs-use-header") == 0) { g_value_set_boolean (value, TRUE); return TRUE; } return FALSE; } typedef struct _GdkWaylandVisual GdkWaylandVisual; typedef struct _GdkWaylandVisualClass GdkWaylandVisualClass; struct _GdkWaylandVisual { GdkVisual visual; }; struct _GdkWaylandVisualClass { GdkVisualClass parent_class; }; GType _gdk_wayland_visual_get_type (void); G_DEFINE_TYPE (GdkWaylandVisual, _gdk_wayland_visual, GDK_TYPE_VISUAL) static void _gdk_wayland_visual_class_init (GdkWaylandVisualClass *klass) { } static void _gdk_wayland_visual_init (GdkWaylandVisual *visual) { } static gint gdk_wayland_screen_visual_get_best_depth (GdkScreen *screen) { return 32; } static GdkVisualType gdk_wayland_screen_visual_get_best_type (GdkScreen *screen) { return GDK_VISUAL_TRUE_COLOR; } static GdkVisual* gdk_wayland_screen_visual_get_best (GdkScreen *screen) { return GDK_WAYLAND_SCREEN (screen)->visual; } static GdkVisual* gdk_wayland_screen_visual_get_best_with_depth (GdkScreen *screen, gint depth) { return GDK_WAYLAND_SCREEN (screen)->visual; } static GdkVisual* gdk_wayland_screen_visual_get_best_with_type (GdkScreen *screen, GdkVisualType visual_type) { return GDK_WAYLAND_SCREEN (screen)->visual; } static GdkVisual* gdk_wayland_screen_visual_get_best_with_both (GdkScreen *screen, gint depth, GdkVisualType visual_type) { return GDK_WAYLAND_SCREEN (screen)->visual; } static void gdk_wayland_screen_query_depths (GdkScreen *screen, gint **depths, gint *count) { static gint static_depths[] = { 32 }; *count = G_N_ELEMENTS(static_depths); *depths = static_depths; } static void gdk_wayland_screen_query_visual_types (GdkScreen *screen, GdkVisualType **visual_types, gint *count) { static GdkVisualType static_visual_types[] = { GDK_VISUAL_TRUE_COLOR }; *count = G_N_ELEMENTS(static_visual_types); *visual_types = static_visual_types; } static GList * gdk_wayland_screen_list_visuals (GdkScreen *screen) { GList *list; GdkWaylandScreen *screen_wayland; g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); screen_wayland = GDK_WAYLAND_SCREEN (screen); list = g_list_append (NULL, screen_wayland->visual); return list; } #define GDK_TYPE_WAYLAND_VISUAL (_gdk_wayland_visual_get_type ()) #define GDK_WAYLAND_VISUAL(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_VISUAL, GdkWaylandVisual)) /* Currently, the Wayland backend only ever uses ARGB8888. */ static GdkVisual * gdk_wayland_visual_new (GdkScreen *screen) { GdkVisual *visual; visual = g_object_new (GDK_TYPE_WAYLAND_VISUAL, NULL); visual->screen = GDK_SCREEN (screen); visual->type = GDK_VISUAL_TRUE_COLOR; visual->depth = 32; visual->red_mask = 0xff0000; visual->green_mask = 0x00ff00; visual->blue_mask = 0x0000ff; visual->bits_per_rgb = 8; return visual; } GdkScreen * _gdk_wayland_screen_new (GdkDisplay *display) { GdkScreen *screen; GdkWaylandScreen *screen_wayland; screen = g_object_new (GDK_TYPE_WAYLAND_SCREEN, NULL); screen_wayland = GDK_WAYLAND_SCREEN (screen); screen_wayland->display = display; screen_wayland->width = 0; screen_wayland->height = 0; screen_wayland->visual = gdk_wayland_visual_new (screen); init_multihead (screen); screen_wayland->root_window = _gdk_wayland_screen_create_root_window (screen, screen_wayland->width, screen_wayland->height); init_settings (screen); return screen; } static void _gdk_wayland_screen_class_init (GdkWaylandScreenClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GdkScreenClass *screen_class = GDK_SCREEN_CLASS (klass); object_class->dispose = gdk_wayland_screen_dispose; object_class->finalize = gdk_wayland_screen_finalize; screen_class->get_display = gdk_wayland_screen_get_display; screen_class->get_width = gdk_wayland_screen_get_width; screen_class->get_height = gdk_wayland_screen_get_height; screen_class->get_width_mm = gdk_wayland_screen_get_width_mm; screen_class->get_height_mm = gdk_wayland_screen_get_height_mm; screen_class->get_number = gdk_wayland_screen_get_number; screen_class->get_root_window = gdk_wayland_screen_get_root_window; screen_class->get_n_monitors = gdk_wayland_screen_get_n_monitors; screen_class->get_primary_monitor = gdk_wayland_screen_get_primary_monitor; screen_class->get_monitor_width_mm = gdk_wayland_screen_get_monitor_width_mm; screen_class->get_monitor_height_mm = gdk_wayland_screen_get_monitor_height_mm; screen_class->get_monitor_plug_name = gdk_wayland_screen_get_monitor_plug_name; screen_class->get_monitor_geometry = gdk_wayland_screen_get_monitor_geometry; screen_class->get_monitor_workarea = gdk_wayland_screen_get_monitor_geometry; screen_class->get_monitor_scale_factor = gdk_wayland_screen_get_monitor_scale_factor; screen_class->get_system_visual = gdk_wayland_screen_get_system_visual; screen_class->get_rgba_visual = gdk_wayland_screen_get_rgba_visual; screen_class->is_composited = gdk_wayland_screen_is_composited; screen_class->make_display_name = gdk_wayland_screen_make_display_name; screen_class->get_active_window = gdk_wayland_screen_get_active_window; screen_class->get_window_stack = gdk_wayland_screen_get_window_stack; screen_class->broadcast_client_message = gdk_wayland_screen_broadcast_client_message; screen_class->get_setting = gdk_wayland_screen_get_setting; screen_class->visual_get_best_depth = gdk_wayland_screen_visual_get_best_depth; screen_class->visual_get_best_type = gdk_wayland_screen_visual_get_best_type; screen_class->visual_get_best = gdk_wayland_screen_visual_get_best; screen_class->visual_get_best_with_depth = gdk_wayland_screen_visual_get_best_with_depth; screen_class->visual_get_best_with_type = gdk_wayland_screen_visual_get_best_with_type; screen_class->visual_get_best_with_both = gdk_wayland_screen_visual_get_best_with_both; screen_class->query_depths = gdk_wayland_screen_query_depths; screen_class->query_visual_types = gdk_wayland_screen_query_visual_types; screen_class->list_visuals = gdk_wayland_screen_list_visuals; } static void _gdk_wayland_screen_init (GdkWaylandScreen *screen_wayland) { } static void update_screen_size (GdkWaylandScreen *screen_wayland) { gboolean emit_changed = FALSE; gint width, height; gint width_mm, height_mm; gint i; width = height = 0; width_mm = height_mm = 0; for (i = 0; i < screen_wayland->monitors->len; i++) { GdkWaylandMonitor *monitor = screen_wayland->monitors->pdata[i]; /* XXX: Largely assuming here that monitor areas * are contiguous and never overlap. */ if (monitor->geometry.x > 0) width_mm += monitor->width_mm; else width_mm = MAX (width_mm, monitor->width_mm); if (monitor->geometry.y > 0) height_mm += monitor->height_mm; else height_mm = MAX (height_mm, monitor->height_mm); width = MAX (width, monitor->geometry.x + monitor->geometry.width); height = MAX (height, monitor->geometry.y + monitor->geometry.height); } if (screen_wayland->width_mm != width_mm || screen_wayland->height_mm != height_mm) { emit_changed = TRUE; screen_wayland->width_mm = width_mm; screen_wayland->height_mm = height_mm; } if (screen_wayland->width != width || screen_wayland->height != height) { emit_changed = TRUE; screen_wayland->width = width; screen_wayland->height = height; } if (emit_changed) g_signal_emit_by_name (screen_wayland, "size-changed"); } static void output_handle_geometry (void *data, struct wl_output *wl_output, int x, int y, int physical_width, int physical_height, int subpixel, const char *make, const char *model, int32_t transform) { GdkWaylandMonitor *monitor = (GdkWaylandMonitor *)data; GDK_NOTE (MISC, g_message ("handle geometry output %d, position %d %d, phys. size %d %d, manufacturer %s, model %s", monitor->id, x, y, physical_width, physical_height, make, model)); monitor->geometry.x = x; monitor->geometry.y = y; monitor->width_mm = physical_width; monitor->height_mm = physical_height; monitor->manufacturer = g_strdup (make); monitor->output_name = g_strdup (model); if (monitor->geometry.width != 0 && monitor->version < OUTPUT_VERSION_WITH_DONE) { g_signal_emit_by_name (monitor->screen, "monitors-changed"); update_screen_size (monitor->screen); } } static void output_handle_done (void *data, struct wl_output *wl_output) { GdkWaylandMonitor *monitor = (GdkWaylandMonitor *)data; GDK_NOTE (MISC, g_message ("handle done output %d", monitor->id)); g_signal_emit_by_name (monitor->screen, "monitors-changed"); update_screen_size (monitor->screen); } static void output_handle_scale (void *data, struct wl_output *wl_output, int32_t scale) { GdkWaylandMonitor *monitor = (GdkWaylandMonitor *)data; GDK_NOTE (MISC, g_message ("handle scale output %d, scale %d", monitor->id, scale)); monitor->scale = scale; if (monitor->geometry.width != 0 && monitor->version < OUTPUT_VERSION_WITH_DONE) g_signal_emit_by_name (monitor->screen, "monitors-changed"); } static void output_handle_mode (void *data, struct wl_output *wl_output, uint32_t flags, int width, int height, int refresh) { GdkWaylandMonitor *monitor = (GdkWaylandMonitor *)data; GDK_NOTE (MISC, g_message ("handle mode output %d, size %d %d, rate %d", monitor->id, width, height, refresh)); if ((flags & WL_OUTPUT_MODE_CURRENT) == 0) return; monitor->geometry.width = width; monitor->geometry.height = height; monitor->refresh_rate = refresh; if (monitor->geometry.width != 0 && monitor->version < OUTPUT_VERSION_WITH_DONE) { g_signal_emit_by_name (monitor->screen, "monitors-changed"); update_screen_size (monitor->screen); } } static const struct wl_output_listener output_listener = { output_handle_geometry, output_handle_mode, output_handle_done, output_handle_scale, }; void _gdk_wayland_screen_add_output (GdkScreen *screen, guint32 id, struct wl_output *output, guint32 version) { GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen); GdkWaylandMonitor *monitor; monitor = g_new0 (GdkWaylandMonitor, 1); monitor->id = id; monitor->output = output; monitor->version = version; monitor->screen = screen_wayland; monitor->scale = 1; g_ptr_array_add (screen_wayland->monitors, monitor); wl_output_add_listener (output, &output_listener, monitor); } struct wl_output * _gdk_wayland_screen_get_wl_output (GdkScreen *screen, gint monitor_num) { GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen); GdkWaylandMonitor *monitor = g_ptr_array_index (screen_wayland->monitors, monitor_num); return monitor->output; } void _gdk_wayland_screen_remove_output (GdkScreen *screen, guint32 id) { GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen); int i; for (i = 0; i < screen_wayland->monitors->len; i++) { GdkWaylandMonitor *monitor = screen_wayland->monitors->pdata[i]; if (monitor->id == id) { g_ptr_array_remove (screen_wayland->monitors, monitor); g_signal_emit_by_name (screen_wayland, "monitors-changed"); update_screen_size (screen_wayland); break; } } } int _gdk_wayland_screen_get_output_refresh_rate (GdkScreen *screen, struct wl_output *output) { GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen); int i; for (i = 0; i < screen_wayland->monitors->len; i++) { GdkWaylandMonitor *monitor = screen_wayland->monitors->pdata[i]; if (monitor->output == output) return monitor->refresh_rate; } return 0; } guint32 _gdk_wayland_screen_get_output_scale (GdkScreen *screen, struct wl_output *output) { GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen); int i; for (i = 0; i < screen_wayland->monitors->len; i++) { GdkWaylandMonitor *monitor = screen_wayland->monitors->pdata[i]; if (monitor->output == output) return monitor->scale; } return 0; }