forked from AuroraMiddleware/gtk
8c0b11998d
Width and height of a GdkMonitor are derived via wl_output which talks about physical dimensions of a device and compositors usually implement this as the untransformed values (e.g. weston, wlroots). Since the GTK client has no way to figure out if a monitor was rotated, transform the physical dimensions according to the applied wayland transform to have the physical dimensions match the logical ones. Mutter flips the physical dimensions itself but doesn't announce the transform so this shouldn't break anything there.
1886 lines
59 KiB
C
1886 lines
59 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 "gdkmonitor-wayland.h"
|
|
#include "gdkwayland.h"
|
|
#include "gdkprivate-wayland.h"
|
|
#include "gdk-private.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 {
|
|
guint fontconfig_timestamp;
|
|
gchar *modules;
|
|
} GsdExtSettings;
|
|
|
|
struct _GdkWaylandScreen
|
|
{
|
|
GdkScreen parent_instance;
|
|
|
|
GdkDisplay *display;
|
|
GdkWindow *root_window;
|
|
|
|
int width, height;
|
|
int width_mm, height_mm;
|
|
|
|
/* Visual Part */
|
|
GdkVisual *visual;
|
|
|
|
GHashTable *settings;
|
|
GsdXftSettings xft_settings;
|
|
GsdExtSettings dbus_settings;
|
|
GDBusProxy *settings_portal;
|
|
|
|
GDBusProxy *dbus_proxy;
|
|
GCancellable *dbus_cancellable;
|
|
gulong dbus_setting_change_id;
|
|
|
|
guint32 shell_capabilities;
|
|
};
|
|
|
|
struct _GdkWaylandScreenClass
|
|
{
|
|
GdkScreenClass parent_class;
|
|
};
|
|
|
|
#define OUTPUT_VERSION_WITH_DONE 2
|
|
#define NO_XDG_OUTPUT_DONE_SINCE_VERSION 3
|
|
|
|
#define GTK_SETTINGS_DBUS_PATH "/org/gtk/Settings"
|
|
#define GTK_SETTINGS_DBUS_NAME "org.gtk.Settings"
|
|
|
|
GType _gdk_wayland_screen_get_type (void);
|
|
|
|
G_DEFINE_TYPE (GdkWaylandScreen, _gdk_wayland_screen, GDK_TYPE_SCREEN)
|
|
|
|
static void
|
|
gdk_wayland_screen_dispose (GObject *object)
|
|
{
|
|
GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (object);
|
|
|
|
if (screen_wayland->dbus_proxy && screen_wayland->dbus_setting_change_id > 0)
|
|
{
|
|
g_signal_handler_disconnect (screen_wayland->dbus_proxy,
|
|
screen_wayland->dbus_setting_change_id);
|
|
screen_wayland->dbus_setting_change_id = 0;
|
|
}
|
|
|
|
g_cancellable_cancel (screen_wayland->dbus_cancellable);
|
|
|
|
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);
|
|
|
|
g_clear_object (&screen_wayland->dbus_proxy);
|
|
g_clear_object (&screen_wayland->dbus_cancellable);
|
|
|
|
if (screen_wayland->root_window)
|
|
g_object_unref (screen_wayland->root_window);
|
|
|
|
g_object_unref (screen_wayland->visual);
|
|
|
|
if (screen_wayland->settings)
|
|
g_hash_table_destroy (screen_wayland->settings);
|
|
|
|
g_clear_object (&screen_wayland->settings_portal);
|
|
|
|
g_free (screen_wayland->dbus_settings.modules);
|
|
|
|
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 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;
|
|
|
|
static int
|
|
get_antialiasing (const char *s)
|
|
{
|
|
const char *names[] = { "none", "grayscale", "rgba" };
|
|
int i;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (names); i++)
|
|
if (strcmp (s, names[i]) == 0)
|
|
return i;
|
|
|
|
return 0;
|
|
}
|
|
|
|
typedef enum
|
|
{
|
|
GSD_FONT_HINTING_NONE,
|
|
GSD_FONT_HINTING_SLIGHT,
|
|
GSD_FONT_HINTING_MEDIUM,
|
|
GSD_FONT_HINTING_FULL
|
|
} GsdFontHinting;
|
|
|
|
static int
|
|
get_hinting (const char *s)
|
|
{
|
|
const char *names[] = { "none", "slight", "medium", "full" };
|
|
int i;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (names); i++)
|
|
if (strcmp (s, names[i]) == 0)
|
|
return i;
|
|
|
|
return 0;
|
|
}
|
|
|
|
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 int
|
|
get_order (const char *s)
|
|
{
|
|
const char *names[] = { "rgba", "rgb", "bgr", "vrgb", "vbgr" };
|
|
int i;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (names); i++)
|
|
if (strcmp (s, names[i]) == 0)
|
|
return i;
|
|
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/* When using the Settings portal, we cache the value in
|
|
* the fallback member, and we ignore the valid field
|
|
*/
|
|
typedef struct _TranslationEntry TranslationEntry;
|
|
struct _TranslationEntry {
|
|
gboolean valid;
|
|
const gchar *schema;
|
|
const gchar *key;
|
|
const gchar *setting;
|
|
GType type;
|
|
union {
|
|
const char *s;
|
|
gint i;
|
|
gboolean b;
|
|
} fallback;
|
|
};
|
|
|
|
static TranslationEntry * find_translation_entry_by_schema (const char *schema,
|
|
const char *key);
|
|
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;
|
|
double dpi;
|
|
|
|
if (screen_wayland->settings_portal)
|
|
{
|
|
TranslationEntry *entry;
|
|
|
|
entry = find_translation_entry_by_schema ("org.gnome.desktop.interface", "font-antialiasing");
|
|
|
|
if (entry->valid)
|
|
{
|
|
antialiasing = entry->fallback.i;
|
|
|
|
entry = find_translation_entry_by_schema ("org.gnome.desktop.interface", "font-hinting");
|
|
hinting = entry->fallback.i;
|
|
|
|
entry = find_translation_entry_by_schema ("org.gnome.desktop.interface", "font-rgba-order");
|
|
order = entry->fallback.i;
|
|
}
|
|
else
|
|
{
|
|
entry = find_translation_entry_by_schema ("org.gnome.settings-daemon.plugins.xsettings", "antialiasing");
|
|
antialiasing = entry->fallback.i;
|
|
|
|
entry = find_translation_entry_by_schema ("org.gnome.settings-daemon.plugins.xsettings", "hinting");
|
|
hinting = entry->fallback.i;
|
|
|
|
entry = find_translation_entry_by_schema ("org.gnome.settings-daemon.plugins.xsettings", "rgba-order");
|
|
order = entry->fallback.i;
|
|
}
|
|
|
|
entry = find_translation_entry_by_schema ("org.gnome.desktop.interface", "text-scaling-factor");
|
|
dpi = 96.0 * entry->fallback.i / 65536.0 * 1024; /* Xft wants 1/1024th of an inch */
|
|
}
|
|
else
|
|
{
|
|
TranslationEntry *entry;
|
|
|
|
entry = find_translation_entry_by_schema ("org.gnome.desktop.interface", "font-antialiasing");
|
|
|
|
if (entry && entry->valid)
|
|
{
|
|
settings = g_hash_table_lookup (screen_wayland->settings,
|
|
"org.gnome.desktop.interface");
|
|
antialiasing = g_settings_get_enum (settings, "font-antialiasing");
|
|
hinting = g_settings_get_enum (settings, "font-hinting");
|
|
order = g_settings_get_enum (settings, "font-rgba-order");
|
|
}
|
|
else if (g_hash_table_contains (screen_wayland->settings,
|
|
"org.gnome.settings-daemon.plugins.xsettings"))
|
|
{
|
|
settings = g_hash_table_lookup (screen_wayland->settings,
|
|
"org.gnome.settings-daemon.plugins.xsettings");
|
|
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;
|
|
}
|
|
|
|
dpi = get_dpi_from_gsettings (screen_wayland) * 1024;
|
|
}
|
|
|
|
xft_settings.antialias = (antialiasing != GSD_FONT_ANTIALIASING_MODE_NONE);
|
|
xft_settings.hinting = (hinting != GSD_FONT_HINTING_NONE);
|
|
xft_settings.dpi = dpi;
|
|
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"
|
|
|
|
static TranslationEntry translations[] = {
|
|
{ FALSE, "org.gnome.desktop.interface", "gtk-theme", "gtk-theme-name" , G_TYPE_STRING, { .s = "Adwaita" } },
|
|
{ FALSE, "org.gnome.desktop.interface", "gtk-key-theme", "gtk-key-theme-name" , G_TYPE_STRING, { .s = "Default" } },
|
|
{ FALSE, "org.gnome.desktop.interface", "icon-theme", "gtk-icon-theme-name", G_TYPE_STRING, { .s = "gnome" } },
|
|
{ FALSE, "org.gnome.desktop.interface", "cursor-theme", "gtk-cursor-theme-name", G_TYPE_STRING, { .s = "Adwaita" } },
|
|
{ FALSE, "org.gnome.desktop.interface", "cursor-size", "gtk-cursor-theme-size", G_TYPE_INT, { .i = 32 } },
|
|
{ FALSE, "org.gnome.desktop.interface", "font-name", "gtk-font-name", G_TYPE_STRING, { .s = "Cantarell 11" } },
|
|
{ FALSE, "org.gnome.desktop.interface", "cursor-blink", "gtk-cursor-blink", G_TYPE_BOOLEAN, { .b = TRUE } },
|
|
{ FALSE, "org.gnome.desktop.interface", "cursor-blink-time", "gtk-cursor-blink-time", G_TYPE_INT, { .i = 1200 } },
|
|
{ FALSE, "org.gnome.desktop.interface", "cursor-blink-timeout", "gtk-cursor-blink-timeout", G_TYPE_INT, { .i = 3600 } },
|
|
{ FALSE, "org.gnome.desktop.interface", "gtk-im-module", "gtk-im-module", G_TYPE_STRING, { .s = "simple" } },
|
|
{ FALSE, "org.gnome.desktop.interface", "enable-animations", "gtk-enable-animations", G_TYPE_BOOLEAN, { .b = TRUE } },
|
|
{ FALSE, "org.gnome.desktop.interface", "gtk-enable-primary-paste", "gtk-enable-primary-paste", G_TYPE_BOOLEAN, { .b = TRUE } },
|
|
{ FALSE, "org.gnome.desktop.interface", "overlay-scrolling", "gtk-overlay-scrolling", G_TYPE_BOOLEAN, { .b = TRUE } },
|
|
{ FALSE, "org.gnome.desktop.peripherals.mouse", "double-click", "gtk-double-click-time", G_TYPE_INT, { .i = 400 } },
|
|
{ FALSE, "org.gnome.desktop.peripherals.mouse", "drag-threshold", "gtk-dnd-drag-threshold", G_TYPE_INT, {.i = 8 } },
|
|
{ FALSE, "org.gnome.settings-daemon.peripherals.mouse", "double-click", "gtk-double-click-time", G_TYPE_INT, { .i = 400 } },
|
|
{ FALSE, "org.gnome.settings-daemon.peripherals.mouse", "drag-threshold", "gtk-dnd-drag-threshold", G_TYPE_INT, {.i = 8 } },
|
|
{ FALSE, "org.gnome.desktop.sound", "theme-name", "gtk-sound-theme-name", G_TYPE_STRING, { .s = "freedesktop" } },
|
|
{ FALSE, "org.gnome.desktop.sound", "event-sounds", "gtk-enable-event-sounds", G_TYPE_BOOLEAN, { .b = TRUE } },
|
|
{ FALSE, "org.gnome.desktop.sound", "input-feedback-sounds", "gtk-enable-input-feedback-sounds", G_TYPE_BOOLEAN, { . b = FALSE } },
|
|
{ FALSE, "org.gnome.desktop.privacy", "recent-files-max-age", "gtk-recent-files-max-age", G_TYPE_INT, { .i = 30 } },
|
|
{ FALSE, "org.gnome.desktop.privacy", "remember-recent-files", "gtk-recent-files-enabled", G_TYPE_BOOLEAN, { .b = TRUE } },
|
|
{ FALSE, WM_SETTINGS_SCHEMA, "button-layout", "gtk-decoration-layout", G_TYPE_STRING, { .s = "menu:close" } },
|
|
{ FALSE, CLASSIC_WM_SETTINGS_SCHEMA, "button-layout", "gtk-decoration-layout", G_TYPE_STRING, { .s = "menu:close" } },
|
|
{ FALSE, "org.gnome.desktop.interface", "font-antialiasing", "gtk-xft-antialias", G_TYPE_NONE, { .i = 1 } },
|
|
{ FALSE, "org.gnome.desktop.interface", "font-hinting", "gtk-xft-hinting", G_TYPE_NONE, { .i = 1 } },
|
|
{ FALSE, "org.gnome.desktop.interface", "font-hinting", "gtk-xft-hintstyle", G_TYPE_NONE, { .i = 1 } },
|
|
{ FALSE, "org.gnome.desktop.interface", "font-rgba-order", "gtk-xft-rgba", G_TYPE_NONE, { .i = 0 } },
|
|
{ FALSE, "org.gnome.settings-daemon.plugins.xsettings", "antialiasing", "gtk-xft-antialias", G_TYPE_NONE, { .i = 1 } },
|
|
{ FALSE, "org.gnome.settings-daemon.plugins.xsettings", "hinting", "gtk-xft-hinting", G_TYPE_NONE, { .i = 1 } },
|
|
{ FALSE, "org.gnome.settings-daemon.plugins.xsettings", "hinting", "gtk-xft-hintstyle", G_TYPE_NONE, { .i = 1 } },
|
|
{ FALSE, "org.gnome.settings-daemon.plugins.xsettings", "rgba-order", "gtk-xft-rgba", G_TYPE_NONE, { .i = 0 } },
|
|
{ FALSE, "org.gnome.desktop.interface", "text-scaling-factor", "gtk-xft-dpi" , G_TYPE_NONE, { .i = 0 } },
|
|
{ FALSE, "org.gnome.desktop.wm.preferences", "action-double-click-titlebar", "gtk-titlebar-double-click", G_TYPE_STRING, { .s = "toggle-maximize" } },
|
|
{ FALSE, "org.gnome.desktop.wm.preferences", "action-middle-click-titlebar", "gtk-titlebar-middle-click", G_TYPE_STRING, { .s = "none" } },
|
|
{ FALSE, "org.gnome.desktop.wm.preferences", "action-right-click-titlebar", "gtk-titlebar-right-click", G_TYPE_STRING, { .s = "menu" } },
|
|
{ FALSE, "org.gnome.desktop.a11y", "always-show-text-caret", "gtk-keynav-use-caret", G_TYPE_BOOLEAN, { .b = FALSE } },
|
|
{ FALSE, "org.gnome.fontconfig", "serial", "gtk-fontconfig-timestamp", G_TYPE_INT, { .i = 0 } }
|
|
};
|
|
|
|
static TranslationEntry *
|
|
find_translation_entry_by_schema (const char *schema,
|
|
const gchar *key)
|
|
{
|
|
guint i;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (translations); i++)
|
|
{
|
|
if (g_str_equal (schema, translations[i].schema) &&
|
|
g_str_equal (key, translations[i].key))
|
|
return &translations[i];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static TranslationEntry *
|
|
find_translation_entry_by_key (GSettings *settings,
|
|
const char *key)
|
|
{
|
|
char *schema;
|
|
TranslationEntry *entry;
|
|
|
|
g_object_get (settings, "schema", &schema, NULL);
|
|
entry = find_translation_entry_by_schema (schema, key);
|
|
g_free (schema);
|
|
|
|
return entry;
|
|
}
|
|
|
|
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
|
|
apply_portal_setting (TranslationEntry *entry,
|
|
GVariant *value,
|
|
GdkScreen *screen)
|
|
{
|
|
switch (entry->type)
|
|
{
|
|
case G_TYPE_STRING:
|
|
entry->fallback.s = g_intern_string (g_variant_get_string (value, NULL));
|
|
break;
|
|
case G_TYPE_INT:
|
|
entry->fallback.i = g_variant_get_int32 (value);
|
|
break;
|
|
case G_TYPE_BOOLEAN:
|
|
entry->fallback.b = g_variant_get_boolean (value);
|
|
break;
|
|
case G_TYPE_NONE:
|
|
if (strcmp (entry->key, "antialiasing") == 0 ||
|
|
strcmp (entry->key, "font-antialiasing") == 0)
|
|
entry->fallback.i = get_antialiasing (g_variant_get_string (value, NULL));
|
|
else if (strcmp (entry->key, "hinting") == 0 ||
|
|
strcmp (entry->key, "font-hinting") == 0)
|
|
entry->fallback.i = get_hinting (g_variant_get_string (value, NULL));
|
|
else if (strcmp (entry->key, "rgba-order") == 0 ||
|
|
strcmp (entry->key, "font-rgba-order") == 0)
|
|
entry->fallback.i = get_order (g_variant_get_string (value, NULL));
|
|
else if (strcmp (entry->key, "text-scaling-factor") == 0)
|
|
entry->fallback.i = (int) (g_variant_get_double (value) * 65536.0);
|
|
update_xft_settings (screen);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
settings_portal_changed (GDBusProxy *proxy,
|
|
const char *sender_name,
|
|
const char *signal_name,
|
|
GVariant *parameters,
|
|
GdkScreen *screen)
|
|
{
|
|
if (strcmp (signal_name, "SettingChanged") == 0)
|
|
{
|
|
const char *namespace;
|
|
const char *name;
|
|
GVariant *value;
|
|
TranslationEntry *entry;
|
|
|
|
g_variant_get (parameters, "(&s&sv)", &namespace, &name, &value);
|
|
|
|
entry = find_translation_entry_by_schema (namespace, name);
|
|
if (entry != NULL)
|
|
{
|
|
char *a = g_variant_print (value, FALSE);
|
|
g_debug ("Using changed portal setting %s %s: %s", namespace, name, a);
|
|
g_free (a);
|
|
apply_portal_setting (entry, value, screen);
|
|
notify_setting (screen, entry->setting);
|
|
}
|
|
else
|
|
g_debug ("Ignoring portal setting %s %s", namespace, name);
|
|
|
|
g_variant_unref (value);
|
|
}
|
|
}
|
|
|
|
static void fontconfig_dbus_proxy_open_cb (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data);
|
|
|
|
#define PORTAL_BUS_NAME "org.freedesktop.portal.Desktop"
|
|
#define PORTAL_OBJECT_PATH "/org/freedesktop/portal/desktop"
|
|
#define PORTAL_SETTINGS_INTERFACE "org.freedesktop.portal.Settings"
|
|
|
|
static void
|
|
init_settings (GdkScreen *screen)
|
|
{
|
|
GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen);
|
|
GSettingsSchemaSource *source;
|
|
GSettingsSchema *schema;
|
|
GSettings *settings;
|
|
gint i;
|
|
|
|
if (gdk_should_use_portal ())
|
|
{
|
|
GVariant *ret;
|
|
GError *error = NULL;
|
|
const char *schema;
|
|
GVariant *val;
|
|
GVariantIter *iter;
|
|
const char *patterns[] = { "org.gnome.*", NULL };
|
|
|
|
screen_wayland->settings_portal = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
|
NULL,
|
|
PORTAL_BUS_NAME,
|
|
PORTAL_OBJECT_PATH,
|
|
PORTAL_SETTINGS_INTERFACE,
|
|
NULL,
|
|
&error);
|
|
if (error)
|
|
{
|
|
g_warning ("Settings portal not found: %s", error->message);
|
|
g_error_free (error);
|
|
|
|
goto fallback;
|
|
}
|
|
|
|
ret = g_dbus_proxy_call_sync (screen_wayland->settings_portal,
|
|
"ReadAll",
|
|
g_variant_new ("(^as)", patterns),
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
G_MAXINT,
|
|
NULL,
|
|
&error);
|
|
if (error)
|
|
{
|
|
g_warning ("Failed to read portal settings: %s", error->message);
|
|
g_error_free (error);
|
|
g_clear_object (&screen_wayland->settings_portal);
|
|
|
|
goto fallback;
|
|
}
|
|
|
|
if (g_variant_n_children (ret) == 0)
|
|
{
|
|
g_debug ("Received no portal settings");
|
|
g_clear_pointer (&ret, g_variant_unref);
|
|
|
|
goto fallback;
|
|
}
|
|
|
|
g_variant_get (ret, "(a{sa{sv}})", &iter);
|
|
|
|
while (g_variant_iter_loop (iter, "{s@a{sv}}", &schema, &val))
|
|
{
|
|
GVariantIter *iter2 = g_variant_iter_new (val);
|
|
const char *key;
|
|
GVariant *v;
|
|
|
|
while (g_variant_iter_loop (iter2, "{sv}", &key, &v))
|
|
{
|
|
TranslationEntry *entry = find_translation_entry_by_schema (schema, key);
|
|
if (entry)
|
|
{
|
|
char *a = g_variant_print (v, FALSE);
|
|
g_debug ("Using portal setting for %s %s: %s\n", schema, key, a);
|
|
g_free (a);
|
|
entry->valid = TRUE;
|
|
apply_portal_setting (entry, v, screen);
|
|
}
|
|
else
|
|
{
|
|
g_debug ("Ignoring portal setting for %s %s", schema, key);
|
|
}
|
|
}
|
|
g_variant_iter_free (iter2);
|
|
}
|
|
g_variant_iter_free (iter);
|
|
|
|
g_variant_unref (ret);
|
|
|
|
g_signal_connect (screen_wayland->settings_portal, "g-signal",
|
|
G_CALLBACK (settings_portal_changed), screen_wayland);
|
|
|
|
return;
|
|
|
|
fallback:
|
|
g_debug ("Failed to use Settings portal; falling back to gsettings");
|
|
}
|
|
|
|
screen_wayland->dbus_cancellable = g_cancellable_new ();
|
|
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
|
NULL,
|
|
GTK_SETTINGS_DBUS_NAME,
|
|
GTK_SETTINGS_DBUS_PATH,
|
|
GTK_SETTINGS_DBUS_NAME,
|
|
screen_wayland->dbus_cancellable,
|
|
fontconfig_dbus_proxy_open_cb,
|
|
screen_wayland);
|
|
|
|
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++)
|
|
{
|
|
schema = g_settings_schema_source_lookup (source, translations[i].schema, TRUE);
|
|
if (!schema)
|
|
continue;
|
|
|
|
if (g_hash_table_lookup (screen_wayland->settings, (gpointer)translations[i].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);
|
|
}
|
|
|
|
if (g_settings_schema_has_key (schema, translations[i].key))
|
|
translations[i].valid = TRUE;
|
|
|
|
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 *display_wayland =
|
|
GDK_WAYLAND_DISPLAY (GDK_WAYLAND_SCREEN (screen)->display);
|
|
|
|
gtk_shell1_add_listener (display_wayland->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;
|
|
|
|
if (screen_wayland->settings_portal)
|
|
{
|
|
switch (entry->type)
|
|
{
|
|
case G_TYPE_STRING:
|
|
g_value_set_string (value, entry->fallback.s);
|
|
break;
|
|
case G_TYPE_INT:
|
|
if (g_str_equal (entry->setting, "gtk-fontconfig-timestamp"))
|
|
g_value_set_uint (value, (guint)entry->fallback.i);
|
|
else
|
|
g_value_set_int (value, entry->fallback.i);
|
|
break;
|
|
case G_TYPE_BOOLEAN:
|
|
g_value_set_boolean (value, 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 ();
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
settings = (GSettings *)g_hash_table_lookup (screen_wayland->settings, entry->schema);
|
|
switch (entry->type)
|
|
{
|
|
case G_TYPE_STRING:
|
|
if (settings && entry->valid)
|
|
{
|
|
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:
|
|
if (g_str_equal (entry->setting, "gtk-fontconfig-timestamp"))
|
|
g_value_set_uint (value, screen_wayland->dbus_settings.fontconfig_timestamp);
|
|
else
|
|
g_value_set_int (value, settings && entry->valid
|
|
? g_settings_get_int (settings, entry->key)
|
|
: entry->fallback.i);
|
|
break;
|
|
case G_TYPE_BOOLEAN:
|
|
g_value_set_boolean (value, settings && entry->valid
|
|
? 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;
|
|
|
|
if (screen_wayland->settings_portal)
|
|
{
|
|
g_value_set_string (value, entry->fallback.s);
|
|
return;
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
GdkWaylandScreen *wayland_screen = GDK_WAYLAND_SCREEN (screen);
|
|
TranslationEntry *entry;
|
|
|
|
g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
|
|
|
|
if (wayland_screen->settings != NULL &&
|
|
g_hash_table_size (wayland_screen->settings) == 0)
|
|
return 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;
|
|
}
|
|
|
|
if (strcmp (name, "gtk-fontconfig-timestamp") == 0)
|
|
{
|
|
g_value_set_uint (value, wayland_screen->dbus_settings.fontconfig_timestamp);
|
|
return TRUE;
|
|
}
|
|
|
|
if (strcmp (name, "gtk-modules") == 0)
|
|
{
|
|
g_value_set_string (value, wayland_screen->dbus_settings.modules);
|
|
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)
|
|
{
|
|
if (depth == 32)
|
|
return GDK_WAYLAND_SCREEN (screen)->visual;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
static GdkVisual*
|
|
gdk_wayland_screen_visual_get_best_with_type (GdkScreen *screen,
|
|
GdkVisualType visual_type)
|
|
{
|
|
if (visual_type == GDK_VISUAL_TRUE_COLOR)
|
|
return GDK_WAYLAND_SCREEN (screen)->visual;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
static GdkVisual*
|
|
gdk_wayland_screen_visual_get_best_with_both (GdkScreen *screen,
|
|
gint depth,
|
|
GdkVisualType visual_type)
|
|
{
|
|
if (depth == 32 && visual_type == GDK_VISUAL_TRUE_COLOR)
|
|
return GDK_WAYLAND_SCREEN (screen)->visual;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
static void
|
|
dbus_properties_change_cb (GDBusProxy *proxy,
|
|
GVariant *changed_properties,
|
|
const gchar* const *invalidated_properties,
|
|
gpointer user_data)
|
|
{
|
|
GdkWaylandScreen *screen_wayland = user_data;
|
|
GVariant *value;
|
|
gint64 timestamp;
|
|
|
|
if (g_variant_n_children (changed_properties) <= 0)
|
|
return;
|
|
|
|
value = g_variant_lookup_value (changed_properties,
|
|
"FontconfigTimestamp",
|
|
G_VARIANT_TYPE_INT64);
|
|
|
|
if (value != NULL)
|
|
{
|
|
timestamp = g_variant_get_int64 (value);
|
|
timestamp = timestamp / G_TIME_SPAN_SECOND;
|
|
|
|
if (timestamp > 0 && timestamp <= G_MAXUINT)
|
|
screen_wayland->dbus_settings.fontconfig_timestamp = (guint)timestamp;
|
|
else if (timestamp > G_MAXUINT)
|
|
g_warning ("Could not handle fontconfig update: timestamp out of bound");
|
|
|
|
notify_setting (GDK_SCREEN (screen_wayland), "gtk-fontconfig-timestamp");
|
|
|
|
g_variant_unref (value);
|
|
}
|
|
|
|
value = g_variant_lookup_value (changed_properties,
|
|
"Modules",
|
|
G_VARIANT_TYPE_STRING);
|
|
|
|
if (value != NULL)
|
|
{
|
|
g_free (screen_wayland->dbus_settings.modules);
|
|
|
|
screen_wayland->dbus_settings.modules = g_variant_dup_string (value, NULL);
|
|
|
|
notify_setting (GDK_SCREEN (screen_wayland), "gtk-modules");
|
|
|
|
g_variant_unref (value);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fontconfig_dbus_proxy_open_cb (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
GdkWaylandScreen *screen_wayland = user_data;
|
|
GDBusProxy *proxy;
|
|
GVariant *value;
|
|
gint64 timestamp;
|
|
|
|
proxy = g_dbus_proxy_new_for_bus_finish (result, NULL);
|
|
|
|
if (proxy == NULL)
|
|
return;
|
|
|
|
screen_wayland->dbus_proxy = proxy;
|
|
screen_wayland->dbus_setting_change_id =
|
|
g_signal_connect (screen_wayland->dbus_proxy,
|
|
"g-properties-changed",
|
|
G_CALLBACK (dbus_properties_change_cb),
|
|
screen_wayland);
|
|
|
|
value = g_dbus_proxy_get_cached_property (screen_wayland->dbus_proxy,
|
|
"FontconfigTimestamp");
|
|
|
|
if (value && g_variant_is_of_type (value, G_VARIANT_TYPE_INT64))
|
|
{
|
|
timestamp = g_variant_get_int64 (value);
|
|
timestamp = timestamp / G_TIME_SPAN_SECOND;
|
|
|
|
if (timestamp > 0 && timestamp <= G_MAXUINT)
|
|
screen_wayland->dbus_settings.fontconfig_timestamp = (guint)timestamp;
|
|
else if (timestamp > G_MAXUINT)
|
|
g_warning ("Could not handle fontconfig init: timestamp out of bound");
|
|
}
|
|
|
|
if (value != NULL)
|
|
g_variant_unref (value);
|
|
|
|
value = g_dbus_proxy_get_cached_property (screen_wayland->dbus_proxy,
|
|
"Modules");
|
|
|
|
if (value && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
|
|
{
|
|
g_free (screen_wayland->dbus_settings.modules);
|
|
|
|
screen_wayland->dbus_settings.modules = g_variant_dup_string (value, NULL);
|
|
}
|
|
|
|
if (value != NULL)
|
|
g_variant_unref (value);
|
|
}
|
|
|
|
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);
|
|
|
|
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_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)
|
|
{
|
|
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (screen_wayland->display);
|
|
gboolean emit_changed = FALSE;
|
|
gint width, height;
|
|
gint width_mm, height_mm;
|
|
int i;
|
|
|
|
width = height = 0;
|
|
width_mm = height_mm = 0;
|
|
for (i = 0; i < display_wayland->monitors->len; i++)
|
|
{
|
|
GdkMonitor *monitor = display_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");
|
|
}
|
|
|
|
#ifdef G_ENABLE_DEBUG
|
|
|
|
static const char *
|
|
subpixel_to_string (int layout)
|
|
{
|
|
int i;
|
|
struct { int layout; const char *name; } layouts[] = {
|
|
{ WL_OUTPUT_SUBPIXEL_UNKNOWN, "unknown" },
|
|
{ WL_OUTPUT_SUBPIXEL_NONE, "none" },
|
|
{ WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB, "rgb" },
|
|
{ WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR, "bgr" },
|
|
{ WL_OUTPUT_SUBPIXEL_VERTICAL_RGB, "vrgb" },
|
|
{ WL_OUTPUT_SUBPIXEL_VERTICAL_BGR, "vbgr" },
|
|
{ 0xffffffff, NULL }
|
|
};
|
|
|
|
for (i = 0; layouts[i].name; i++)
|
|
{
|
|
if (layouts[i].layout == layout)
|
|
return layouts[i].name;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static const char *
|
|
transform_to_string (int transform)
|
|
{
|
|
int i;
|
|
struct { int transform; const char *name; } transforms[] = {
|
|
{ WL_OUTPUT_TRANSFORM_NORMAL, "normal" },
|
|
{ WL_OUTPUT_TRANSFORM_90, "90" },
|
|
{ WL_OUTPUT_TRANSFORM_180, "180" },
|
|
{ WL_OUTPUT_TRANSFORM_270, "270" },
|
|
{ WL_OUTPUT_TRANSFORM_FLIPPED, "flipped" },
|
|
{ WL_OUTPUT_TRANSFORM_FLIPPED_90, "flipped 90" },
|
|
{ WL_OUTPUT_TRANSFORM_FLIPPED_180, "flipped 180" },
|
|
{ WL_OUTPUT_TRANSFORM_FLIPPED_270, "flipped 270" },
|
|
{ 0xffffffff, NULL }
|
|
};
|
|
|
|
for (i = 0; transforms[i].name; i++)
|
|
{
|
|
if (transforms[i].transform == transform)
|
|
return transforms[i].name;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#endif
|
|
|
|
static gboolean
|
|
screen_has_xdg_output_support (GdkScreen *screen)
|
|
{
|
|
GdkDisplay *display = gdk_screen_get_display (screen);
|
|
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
|
|
|
|
return (display_wayland->xdg_output_manager != NULL);
|
|
}
|
|
|
|
static gboolean
|
|
monitor_has_xdg_output (GdkWaylandMonitor *monitor)
|
|
{
|
|
return (monitor->xdg_output != NULL);
|
|
}
|
|
|
|
static gboolean
|
|
should_update_monitor (GdkWaylandMonitor *monitor)
|
|
{
|
|
return (GDK_MONITOR (monitor)->geometry.width != 0 &&
|
|
monitor->version < OUTPUT_VERSION_WITH_DONE);
|
|
}
|
|
|
|
static gboolean
|
|
should_expect_xdg_output_done (GdkWaylandMonitor *monitor)
|
|
{
|
|
GdkDisplay *display = GDK_MONITOR (monitor)->display;
|
|
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
|
|
|
|
return (monitor_has_xdg_output (monitor) &&
|
|
display_wayland->xdg_output_version < NO_XDG_OUTPUT_DONE_SINCE_VERSION);
|
|
}
|
|
|
|
static void
|
|
apply_monitor_change (GdkWaylandMonitor *monitor)
|
|
{
|
|
GdkDisplay *display = GDK_MONITOR (monitor)->display;
|
|
GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (gdk_display_get_default_screen (display));
|
|
|
|
GDK_NOTE (MISC,
|
|
g_message ("monitor %d changed position %d %d, size %d %d",
|
|
monitor->id,
|
|
monitor->x, monitor->y,
|
|
monitor->width, monitor->height));
|
|
|
|
gdk_monitor_set_position (GDK_MONITOR (monitor), monitor->x, monitor->y);
|
|
gdk_monitor_set_size (GDK_MONITOR (monitor), monitor->width, monitor->height);
|
|
gdk_monitor_set_connector (GDK_MONITOR (monitor), monitor->name);
|
|
monitor->wl_output_done = FALSE;
|
|
monitor->xdg_output_done = FALSE;
|
|
|
|
g_signal_emit_by_name (screen_wayland, "monitors-changed");
|
|
update_screen_size (screen_wayland);
|
|
}
|
|
|
|
static void
|
|
xdg_output_handle_logical_position (void *data,
|
|
struct zxdg_output_v1 *xdg_output,
|
|
int32_t x,
|
|
int32_t y)
|
|
{
|
|
GdkWaylandMonitor *monitor = (GdkWaylandMonitor *) data;
|
|
|
|
GDK_NOTE (MISC,
|
|
g_message ("handle logical position xdg-output %d, position %d %d",
|
|
monitor->id, x, y));
|
|
monitor->x = x;
|
|
monitor->y = y;
|
|
}
|
|
|
|
static void
|
|
xdg_output_handle_logical_size (void *data,
|
|
struct zxdg_output_v1 *xdg_output,
|
|
int32_t width,
|
|
int32_t height)
|
|
{
|
|
GdkWaylandMonitor *monitor = (GdkWaylandMonitor *) data;
|
|
|
|
GDK_NOTE (MISC,
|
|
g_message ("handle logical size xdg-output %d, size %d %d",
|
|
monitor->id, width, height));
|
|
monitor->width = width;
|
|
monitor->height = height;
|
|
}
|
|
|
|
static void
|
|
xdg_output_handle_done (void *data,
|
|
struct zxdg_output_v1 *xdg_output)
|
|
{
|
|
GdkWaylandMonitor *monitor = (GdkWaylandMonitor *) data;
|
|
|
|
GDK_NOTE (MISC,
|
|
g_message ("handle done xdg-output %d", monitor->id));
|
|
|
|
monitor->xdg_output_done = TRUE;
|
|
if (monitor->wl_output_done && should_expect_xdg_output_done (monitor))
|
|
apply_monitor_change (monitor);
|
|
}
|
|
|
|
static void
|
|
xdg_output_handle_name (void *data,
|
|
struct zxdg_output_v1 *xdg_output,
|
|
const char *name)
|
|
{
|
|
GdkWaylandMonitor *monitor = (GdkWaylandMonitor *) data;
|
|
|
|
GDK_NOTE (MISC,
|
|
g_message ("handle name xdg-output %d", monitor->id));
|
|
|
|
monitor->name = g_strdup (name);
|
|
}
|
|
|
|
static void
|
|
xdg_output_handle_description (void *data,
|
|
struct zxdg_output_v1 *xdg_output,
|
|
const char *description)
|
|
{
|
|
#ifdef G_ENABLE_DEBUG
|
|
GdkWaylandMonitor *monitor = (GdkWaylandMonitor *) data;
|
|
|
|
GDK_NOTE (MISC,
|
|
g_message ("handle description xdg-output %d", monitor->id));
|
|
#endif
|
|
}
|
|
|
|
static const struct zxdg_output_v1_listener xdg_output_listener = {
|
|
xdg_output_handle_logical_position,
|
|
xdg_output_handle_logical_size,
|
|
xdg_output_handle_done,
|
|
xdg_output_handle_name,
|
|
xdg_output_handle_description,
|
|
};
|
|
|
|
static void
|
|
gdk_wayland_screen_get_xdg_output (GdkWaylandMonitor *monitor)
|
|
{
|
|
GdkDisplay *display = GDK_MONITOR (monitor)->display;
|
|
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
|
|
|
|
GDK_NOTE (MISC,
|
|
g_message ("get xdg-output for monitor %d", monitor->id));
|
|
|
|
monitor->xdg_output =
|
|
zxdg_output_manager_v1_get_xdg_output (display_wayland->xdg_output_manager,
|
|
monitor->output);
|
|
|
|
zxdg_output_v1_add_listener (monitor->xdg_output,
|
|
&xdg_output_listener,
|
|
monitor);
|
|
}
|
|
|
|
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, subpixel layout %s, manufacturer %s, model %s, transform %s",
|
|
monitor->id, x, y, physical_width, physical_height, subpixel_to_string (subpixel), make, model, transform_to_string (transform)));
|
|
|
|
monitor->x = x;
|
|
monitor->y = y;
|
|
|
|
switch (transform)
|
|
{
|
|
case WL_OUTPUT_TRANSFORM_90:
|
|
case WL_OUTPUT_TRANSFORM_270:
|
|
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
|
|
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
|
|
gdk_monitor_set_physical_size (GDK_MONITOR (monitor),
|
|
physical_height, physical_width);
|
|
break;
|
|
default:
|
|
gdk_monitor_set_physical_size (GDK_MONITOR (monitor),
|
|
physical_width, physical_height);
|
|
}
|
|
|
|
gdk_monitor_set_subpixel_layout (GDK_MONITOR (monitor), subpixel);
|
|
gdk_monitor_set_manufacturer (GDK_MONITOR (monitor), make);
|
|
gdk_monitor_set_model (GDK_MONITOR (monitor), model);
|
|
|
|
if (should_update_monitor (monitor) || !monitor_has_xdg_output (monitor))
|
|
apply_monitor_change (monitor);
|
|
}
|
|
|
|
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));
|
|
|
|
monitor->wl_output_done = TRUE;
|
|
|
|
if (!should_expect_xdg_output_done (monitor) || monitor->xdg_output_done)
|
|
apply_monitor_change (monitor);
|
|
}
|
|
|
|
static void
|
|
output_handle_scale (void *data,
|
|
struct wl_output *wl_output,
|
|
int32_t scale)
|
|
{
|
|
GdkWaylandMonitor *monitor = (GdkWaylandMonitor *)data;
|
|
GdkRectangle previous_geometry;
|
|
int previous_scale;
|
|
int width;
|
|
int height;
|
|
|
|
GDK_NOTE (MISC,
|
|
g_message ("handle scale output %d, scale %d", monitor->id, scale));
|
|
|
|
gdk_monitor_get_geometry (GDK_MONITOR (monitor), &previous_geometry);
|
|
previous_scale = gdk_monitor_get_scale_factor (GDK_MONITOR (monitor));
|
|
|
|
/* Set the scale from wl_output protocol, regardless of xdg-output support */
|
|
gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), scale);
|
|
|
|
if (monitor_has_xdg_output (monitor))
|
|
return;
|
|
|
|
width = previous_geometry.width * previous_scale;
|
|
height = previous_geometry.height * previous_scale;
|
|
|
|
monitor->width = width / scale;
|
|
monitor->height = height / scale;
|
|
|
|
if (should_update_monitor (monitor))
|
|
apply_monitor_change (monitor);
|
|
}
|
|
|
|
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;
|
|
int scale;
|
|
|
|
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;
|
|
|
|
scale = gdk_monitor_get_scale_factor (GDK_MONITOR (monitor));
|
|
monitor->width = width / scale;
|
|
monitor->height = height / scale;
|
|
gdk_monitor_set_refresh_rate (GDK_MONITOR (monitor), refresh);
|
|
|
|
if (should_update_monitor (monitor) || !monitor_has_xdg_output (monitor))
|
|
apply_monitor_change (monitor);
|
|
}
|
|
|
|
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)
|
|
{
|
|
GdkDisplay *display = gdk_screen_get_display (screen);
|
|
GdkWaylandMonitor *monitor;
|
|
|
|
monitor = g_object_new (GDK_TYPE_WAYLAND_MONITOR,
|
|
"display", display,
|
|
NULL);
|
|
|
|
monitor->id = id;
|
|
monitor->output = output;
|
|
monitor->version = version;
|
|
|
|
g_ptr_array_add (GDK_WAYLAND_DISPLAY (display)->monitors, monitor);
|
|
gdk_display_monitor_added (display, GDK_MONITOR (monitor));
|
|
wl_output_add_listener (output, &output_listener, monitor);
|
|
|
|
GDK_NOTE (MISC,
|
|
g_message ("xdg_output_manager %p",
|
|
GDK_WAYLAND_DISPLAY (display)->xdg_output_manager));
|
|
|
|
if (screen_has_xdg_output_support (screen))
|
|
gdk_wayland_screen_get_xdg_output (monitor);
|
|
}
|
|
|
|
struct wl_output *
|
|
_gdk_wayland_screen_get_wl_output (GdkScreen *screen,
|
|
gint monitor_num)
|
|
{
|
|
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (GDK_WAYLAND_SCREEN (screen)->display);
|
|
GdkWaylandMonitor *monitor;
|
|
|
|
monitor = display_wayland->monitors->pdata[monitor_num];
|
|
|
|
return monitor->output;
|
|
}
|
|
|
|
static GdkWaylandMonitor *
|
|
get_monitor_for_id (GdkWaylandScreen *screen_wayland,
|
|
guint32 id)
|
|
{
|
|
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (screen_wayland->display);
|
|
int i;
|
|
|
|
for (i = 0; i < display_wayland->monitors->len; i++)
|
|
{
|
|
GdkWaylandMonitor *monitor = display_wayland->monitors->pdata[i];
|
|
|
|
if (monitor->id == id)
|
|
return monitor;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static GdkWaylandMonitor *
|
|
get_monitor_for_output (GdkWaylandScreen *screen_wayland,
|
|
struct wl_output *output)
|
|
{
|
|
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (screen_wayland->display);
|
|
int i;
|
|
|
|
for (i = 0; i < display_wayland->monitors->len; i++)
|
|
{
|
|
GdkWaylandMonitor *monitor = display_wayland->monitors->pdata[i];
|
|
|
|
if (monitor->output == output)
|
|
return monitor;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
_gdk_wayland_screen_remove_output (GdkScreen *screen,
|
|
guint32 id)
|
|
{
|
|
GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen);
|
|
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (screen_wayland->display);
|
|
GdkWaylandMonitor *monitor;
|
|
|
|
monitor = get_monitor_for_id (screen_wayland, id);
|
|
if (monitor != NULL)
|
|
{
|
|
g_object_ref (monitor);
|
|
g_ptr_array_remove (display_wayland->monitors, monitor);
|
|
gdk_display_monitor_removed (GDK_DISPLAY (display_wayland), GDK_MONITOR (monitor));
|
|
g_object_unref (monitor);
|
|
g_signal_emit_by_name (screen_wayland, "monitors-changed");
|
|
update_screen_size (screen_wayland);
|
|
}
|
|
}
|
|
|
|
int
|
|
_gdk_wayland_screen_get_output_refresh_rate (GdkScreen *screen,
|
|
struct wl_output *output)
|
|
{
|
|
GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen);
|
|
GdkWaylandMonitor *monitor;
|
|
|
|
monitor = get_monitor_for_output (screen_wayland, output);
|
|
if (monitor != NULL)
|
|
return gdk_monitor_get_refresh_rate (GDK_MONITOR (monitor));
|
|
|
|
return 0;
|
|
}
|
|
|
|
guint32
|
|
_gdk_wayland_screen_get_output_scale (GdkScreen *screen,
|
|
struct wl_output *output)
|
|
{
|
|
GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen);
|
|
GdkWaylandMonitor *monitor;
|
|
|
|
monitor = get_monitor_for_output (screen_wayland, output);
|
|
if (monitor != NULL)
|
|
return gdk_monitor_get_scale_factor (GDK_MONITOR (monitor));
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
_gdk_wayland_screen_init_xdg_output (GdkScreen *screen)
|
|
{
|
|
GdkDisplay *display = gdk_screen_get_display (screen);
|
|
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
|
|
int i;
|
|
|
|
GDK_NOTE (MISC,
|
|
g_message ("init xdg-output support, %d monitor(s) already present",
|
|
display_wayland->monitors->len));
|
|
|
|
for (i = 0; i < display_wayland->monitors->len; i++)
|
|
gdk_wayland_screen_get_xdg_output (display_wayland->monitors->pdata[i]);
|
|
}
|