[gtk: 1/2] wayland: Add support for xdg-output
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk: 1/2] wayland: Add support for xdg-output
- Date: Wed, 1 May 2019 03:35:17 +0000 (UTC)
commit 1f58e0ed6b5eaf6140bebdfb3560ba935ce1ef66
Author: Olivier Fourdan <ofourdan redhat com>
Date: Mon Apr 15 16:42:45 2019 +0200
wayland: Add support for xdg-output
Previously, the GDK backend for Wayland would deduce the logical size
of the monitors from the wl_output size and scale.
With the addition of fractional scaling which advertises a larger scale
value and then scale down the client surface, the computed logical size
of the monitors in GDK would be wrong and confuse applications which
insist on using the monitor size and position (like Firefox).
The xdg-output protocol aims at describing outputs in a way which is more
in line with the concept of an output on desktop oriented systems by
presenting the outputs using their logical size and position appropriately
transformed.
Add support for the optional xdg-output protocol so that the size and
position of the monitors as reported by GDK is correct even when using
fractional scaling.
Fixes: https://gitlab.gnome.org/GNOME/gtk/issues/1828
gdk/wayland/gdkdisplay-wayland.c | 176 ++++++++++++++++++++++++++++++++++-----
gdk/wayland/gdkdisplay-wayland.h | 2 +
gdk/wayland/gdkmonitor-wayland.h | 9 ++
gdk/wayland/meson.build | 1 +
4 files changed, 167 insertions(+), 21 deletions(-)
---
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index 777b90b7ef..b4e51d6c63 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -396,6 +396,8 @@ static void gdk_wayland_display_add_output (GdkWaylandDisplay *display_wa
guint32 version);
static void gdk_wayland_display_remove_output (GdkWaylandDisplay *display_wayland,
guint32 id);
+static void gdk_wayland_display_init_xdg_output (GdkWaylandDisplay *display_wayland);
+static void gdk_wayland_display_get_xdg_output (GdkWaylandMonitor *monitor);
static void
gdk_registry_handle_global (void *data,
@@ -527,6 +529,13 @@ gdk_registry_handle_global (void *data,
&server_decoration_listener,
display_wayland);
}
+ else if (strcmp(interface, "zxdg_output_manager_v1") == 0)
+ {
+ display_wayland->xdg_output_manager =
+ wl_registry_bind (registry, id, &zxdg_output_manager_v1_interface, 1);
+ gdk_wayland_display_init_xdg_output (display_wayland);
+ _gdk_wayland_display_async_roundtrip (display_wayland);
+ }
g_hash_table_insert (display_wayland->known_globals,
GUINT_TO_POINTER (id), g_strdup (interface));
@@ -2170,6 +2179,123 @@ update_scale (GdkDisplay *display)
g_list_free (seats);
}
+static void
+gdk_wayland_display_init_xdg_output (GdkWaylandDisplay *display_wayland)
+{
+ 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_display_get_xdg_output (display_wayland->monitors->pdata[i]);
+}
+
+static gboolean
+display_has_xdg_output_support (GdkWaylandDisplay *display_wayland)
+{
+ 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 void
+apply_monitor_change (GdkWaylandMonitor *monitor)
+{
+ 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);
+ monitor->wl_output_done = FALSE;
+ monitor->xdg_output_done = FALSE;
+
+ update_scale (GDK_MONITOR (monitor)->display);
+}
+
+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)
+ apply_monitor_change (monitor);
+}
+
+static const struct zxdg_output_v1_listener xdg_output_listener = {
+ xdg_output_handle_logical_position,
+ xdg_output_handle_logical_size,
+ xdg_output_handle_done,
+};
+
+static void
+gdk_wayland_display_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,
@@ -2188,13 +2314,17 @@ output_handle_geometry (void *data,
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)));
- gdk_monitor_set_position (GDK_MONITOR (monitor), x, y);
+ monitor->x = x;
+ monitor->y = y;
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 (GDK_MONITOR (monitor)->geometry.width != 0 && monitor->version < OUTPUT_VERSION_WITH_DONE)
+ if (should_update_monitor (monitor) || !monitor_has_xdg_output (monitor))
+ apply_monitor_change (monitor);
+
+ if (should_update_monitor (monitor))
update_scale (GDK_MONITOR (monitor)->display);
}
@@ -2203,19 +2333,14 @@ output_handle_done (void *data,
struct wl_output *wl_output)
{
GdkWaylandMonitor *monitor = (GdkWaylandMonitor *)data;
- GdkDisplay *display = gdk_monitor_get_display (GDK_MONITOR (monitor));
GDK_NOTE (MISC,
g_message ("handle done output %d", monitor->id));
- if (!monitor->added)
- {
- monitor->added = TRUE;
- g_ptr_array_add (GDK_WAYLAND_DISPLAY (display)->monitors, monitor);
- gdk_display_monitor_added (display, GDK_MONITOR (monitor));
- }
+ monitor->wl_output_done = TRUE;
- update_scale (display);
+ if (!monitor_has_xdg_output (monitor) || monitor->xdg_output_done)
+ apply_monitor_change (monitor);
}
static void
@@ -2232,6 +2357,9 @@ output_handle_scale (void *data,
GDK_NOTE (MISC,
g_message ("handle scale output %d, scale %d", monitor->id, scale));
+ if (monitor_has_xdg_output (monitor))
+ return;
+
gdk_monitor_get_geometry (GDK_MONITOR (monitor), &previous_geometry);
previous_scale = gdk_monitor_get_scale_factor (GDK_MONITOR (monitor));
@@ -2239,10 +2367,11 @@ output_handle_scale (void *data,
height = previous_geometry.height * previous_scale;
gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), scale);
- gdk_monitor_set_size (GDK_MONITOR (monitor), width / scale, height / scale);
+ monitor->width = width / scale;
+ monitor->height = height / scale;
- if (GDK_MONITOR (monitor)->geometry.width != 0 && monitor->version < OUTPUT_VERSION_WITH_DONE)
- update_scale (GDK_MONITOR (monitor)->display);
+ if (should_update_monitor (monitor))
+ apply_monitor_change (monitor);
}
static void
@@ -2264,11 +2393,12 @@ output_handle_mode (void *data,
return;
scale = gdk_monitor_get_scale_factor (GDK_MONITOR (monitor));
- gdk_monitor_set_size (GDK_MONITOR (monitor), width / scale, height / scale);
+ monitor->width = width / scale;
+ monitor->height = height / scale;
gdk_monitor_set_refresh_rate (GDK_MONITOR (monitor), refresh);
- if (width != 0 && monitor->version < OUTPUT_VERSION_WITH_DONE)
- update_scale (GDK_MONITOR (monitor)->display);
+ if (should_update_monitor (monitor) || !monitor_has_xdg_output (monitor))
+ apply_monitor_change (monitor);
}
static const struct wl_output_listener output_listener =
@@ -2295,13 +2425,17 @@ gdk_wayland_display_add_output (GdkWaylandDisplay *display_wayland,
monitor->output = output;
monitor->version = version;
- if (monitor->version < OUTPUT_VERSION_WITH_DONE)
- {
- g_ptr_array_add (display_wayland->monitors, monitor);
- gdk_display_monitor_added (GDK_DISPLAY (display_wayland), GDK_MONITOR (monitor));
- }
+ g_ptr_array_add (display_wayland->monitors, monitor);
+ gdk_display_monitor_added (GDK_DISPLAY (display_wayland), GDK_MONITOR (monitor));
wl_output_add_listener (output, &output_listener, monitor);
+
+ GDK_NOTE (MISC,
+ g_message ("xdg_output_manager %p",
+ display_wayland->xdg_output_manager));
+
+ if (display_has_xdg_output_support (display_wayland))
+ gdk_wayland_display_get_xdg_output (monitor);
}
struct wl_output *
diff --git a/gdk/wayland/gdkdisplay-wayland.h b/gdk/wayland/gdkdisplay-wayland.h
index 8f06188841..6c5265f6a4 100644
--- a/gdk/wayland/gdkdisplay-wayland.h
+++ b/gdk/wayland/gdkdisplay-wayland.h
@@ -35,6 +35,7 @@
#include <gdk/wayland/xdg-foreign-unstable-v1-client-protocol.h>
#include <gdk/wayland/keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h>
#include <gdk/wayland/server-decoration-client-protocol.h>
+#include <gdk/wayland/xdg-output-unstable-v1-client-protocol.h>
#include <glib.h>
#include <gdk/gdkkeys.h>
@@ -109,6 +110,7 @@ struct _GdkWaylandDisplay
struct zxdg_importer_v1 *xdg_importer;
struct zwp_keyboard_shortcuts_inhibit_manager_v1 *keyboard_shortcuts_inhibit;
struct org_kde_kwin_server_decoration_manager *server_decoration_manager;
+ struct zxdg_output_manager_v1 *xdg_output_manager;
GList *async_roundtrips;
diff --git a/gdk/wayland/gdkmonitor-wayland.h b/gdk/wayland/gdkmonitor-wayland.h
index 581908c513..593ab1d85c 100644
--- a/gdk/wayland/gdkmonitor-wayland.h
+++ b/gdk/wayland/gdkmonitor-wayland.h
@@ -30,6 +30,15 @@ struct _GdkWaylandMonitor {
guint32 version;
struct wl_output *output;
gboolean added;
+
+ struct zxdg_output_v1 *xdg_output;
+ /* Size and position, can be either from wl_output or xdg_output */
+ int32_t x;
+ int32_t y;
+ int32_t width;
+ int32_t height;
+ gboolean wl_output_done;
+ gboolean xdg_output_done;
};
struct _GdkWaylandMonitorClass {
diff --git a/gdk/wayland/meson.build b/gdk/wayland/meson.build
index 0d0cf80851..40f08bdd88 100644
--- a/gdk/wayland/meson.build
+++ b/gdk/wayland/meson.build
@@ -58,6 +58,7 @@ proto_sources = [
['tablet', 'unstable', 'v2', ],
['keyboard-shortcuts-inhibit', 'unstable', 'v1', ],
['server-decoration', 'private' ],
+ ['xdg-output', 'unstable', 'v1', ],
]
gdk_wayland_gen_headers = []
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]