gtk2/gdk/wayland/gdkscreen-wayland.c
Giovanni Campagna 7f8bf41633 gtk-shell: extend the protocol with shell capabilities
Add the concept of shell capabilities, which allow the compositor
to advertise support for the app menu and the global menubar,
which are then propagated as GdkSettings.

https://bugzilla.gnome.org/show_bug.cgi?id=707129
2013-09-03 17:03:43 +02:00

1090 lines
31 KiB
C

/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <gio/gio.h>
#include "gdkscreenprivate.h"
#include "gdkvisualprivate.h"
#include "gdkdisplay.h"
#include "gdkdisplay-wayland.h"
#include "gdkwayland.h"
#include "gdkprivate-wayland.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;
};
G_DEFINE_TYPE (GdkWaylandScreen, _gdk_wayland_screen, GDK_TYPE_SCREEN)
static void
free_monitor (gpointer data)
{
GdkWaylandMonitor *monitor = data;
if (monitor == NULL)
return;
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 = 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 = 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 = 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 = 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;
if (monitor_num >= screen_wayland->monitors->len)
return 1;
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 NULL;
}
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 *interface_settings;
gdouble factor;
interface_settings = g_hash_table_lookup (screen_wayland->settings,
"org.gnome.desktop.interface");
if (interface_settings != NULL)
factor = g_settings_get_double (interface_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)
{
screen_wayland->xft_settings.dpi = xft_settings.dpi;
notify_setting (screen, "gtk-xft-dpi");
}
}
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 = 250 } },
{ "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 } },
{ "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 } },
};
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 ();
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, FALSE);
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_shell *shell,
uint32_t capabilities)
{
GdkWaylandScreen *screen_wayland = data;
screen_wayland->shell_capabilities = capabilities;
}
struct gtk_shell_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_shell_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 gboolean
set_capability_setting (GdkScreen *screen,
GValue *value,
enum gtk_shell_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)
{
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_SHELL_CAPABILITY_GLOBAL_APP_MENU);
if (strcmp (name, "gtk-shell-shows-menubar") == 0)
return set_capability_setting (screen, value, GTK_SHELL_CAPABILITY_GLOBAL_MENU_BAR);
return FALSE;
}
typedef struct _GdkWaylandVisual GdkWaylandVisual;
typedef struct _GdkWaylandVisualClass GdkWaylandVisualClass;
struct _GdkWaylandVisual
{
GdkVisual visual;
};
struct _GdkWaylandVisualClass
{
GdkVisualClass parent_class;
};
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))
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;
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)
{
gint width, height;
gint i;
width = height = 0;
for (i = 0; i < screen_wayland->monitors->len; i++)
{
GdkWaylandMonitor *monitor = screen_wayland->monitors->pdata[i];
width = MAX (width, monitor->geometry.x + monitor->geometry.width);
height = MAX (height, monitor->geometry.y + monitor->geometry.height);
}
if (screen_wayland->width != width ||
screen_wayland->height != height)
{
screen_wayland->width = width;
screen_wayland->height = height;
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;
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;
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 factor)
{
GdkWaylandMonitor *monitor = (GdkWaylandMonitor *)data;
monitor->scale = factor;
}
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;
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 = 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);
}
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;
}