From 677c216fbf52e5cbc1d5f0890ebc1ee9216cfd27 Mon Sep 17 00:00:00 2001 From: Rui Matos Date: Sun, 25 Oct 2015 16:14:58 +0100 Subject: [PATCH] monitor-manager-xrandr: Force an update when resuming from suspend The stack below us isn't as reliable as we'd like and in some cases doesn't generate RRScreenChangeNotify events when e.g. resuming a laptop on a dock, meaning that we'd miss newly attached outputs. --- src/backends/x11/meta-monitor-manager-xrandr.c | 157 +++++++++++++++++++------ 1 file changed, 122 insertions(+), 35 deletions(-) diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c index 4a27b3a14..aa3ff76f5 100644 --- a/src/backends/x11/meta-monitor-manager-xrandr.c +++ b/src/backends/x11/meta-monitor-manager-xrandr.c @@ -58,6 +58,11 @@ struct _MetaMonitorManagerXrandr XRRScreenResources *resources; int rr_event_base; int rr_error_base; + + guint logind_watch_id; + guint logind_signal_sub_id; + + gboolean need_hardware_poll; gboolean has_randr15; }; @@ -763,8 +768,15 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager) manager->screen_width = WidthOfScreen (screen); manager->screen_height = HeightOfScreen (screen); - resources = XRRGetScreenResourcesCurrent (manager_xrandr->xdisplay, - DefaultRootWindow (manager_xrandr->xdisplay)); + if (manager_xrandr->need_hardware_poll) + { + resources = XRRGetScreenResources (manager_xrandr->xdisplay, + DefaultRootWindow (manager_xrandr->xdisplay)); + manager_xrandr->need_hardware_poll = FALSE; + } + else + resources = XRRGetScreenResourcesCurrent (manager_xrandr->xdisplay, + DefaultRootWindow (manager_xrandr->xdisplay)); if (!resources) return; @@ -1414,6 +1426,100 @@ meta_monitor_manager_xrandr_init_monitors(MetaMonitorManagerXrandr *manager_xran } #endif +static gboolean +is_xvnc (MetaMonitorManager *manager) +{ + unsigned int i; + + for (i = 0; i < manager->n_outputs; ++i) + if (g_str_has_prefix (manager->outputs[i].name, "VNC-")) + return TRUE; + + return FALSE; +} + +static void +meta_monitor_manager_xrandr_update (MetaMonitorManagerXrandr *manager_xrandr) +{ + MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr); + gboolean hotplug; + unsigned int timestamp; + + meta_monitor_manager_read_current_config (manager); + + timestamp = manager_xrandr->resources->timestamp; + if (is_xvnc (manager)) + timestamp += 100; + + hotplug = timestamp < manager_xrandr->resources->configTimestamp; + if (hotplug) + { + /* This is a hotplug event, so go ahead and build a new configuration. */ + meta_monitor_manager_on_hotplug (manager); + } + else + { + /* Something else changed -- tell the world about it. */ + meta_monitor_manager_rebuild_derived (manager); + } +} + +static void +logind_signal_handler (GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + MetaMonitorManagerXrandr *manager_xrandr = user_data; + gboolean suspending; + + if (!g_str_equal (signal_name, "PrepareForSleep")) + return; + + g_variant_get (parameters, "(b)", &suspending); + if (!suspending) + { + manager_xrandr->need_hardware_poll = TRUE; + meta_monitor_manager_xrandr_update (manager_xrandr); + } +} + +static void +logind_appeared (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + gpointer user_data) +{ + MetaMonitorManagerXrandr *manager_xrandr = user_data; + + manager_xrandr->logind_signal_sub_id = g_dbus_connection_signal_subscribe (connection, + "org.freedesktop.login1", + "org.freedesktop.login1.Manager", + "PrepareForSleep", + "/org/freedesktop/login1", + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + logind_signal_handler, + manager_xrandr, + NULL); +} + +static void +logind_vanished (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + MetaMonitorManagerXrandr *manager_xrandr = user_data; + + if (connection && manager_xrandr->logind_signal_sub_id > 0) + g_dbus_connection_signal_unsubscribe (connection, manager_xrandr->logind_signal_sub_id); + + manager_xrandr->logind_signal_sub_id = 0; +} + static void meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr) { @@ -1449,6 +1555,15 @@ meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr) meta_monitor_manager_xrandr_init_monitors (manager_xrandr); #endif } + + manager_xrandr->logind_watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM, + "org.freedesktop.login1", + G_BUS_NAME_WATCHER_FLAGS_NONE, + logind_appeared, + logind_vanished, + manager_xrandr, + NULL); + manager_xrandr->need_hardware_poll = TRUE; } static void @@ -1460,6 +1575,10 @@ meta_monitor_manager_xrandr_finalize (GObject *object) XRRFreeScreenResources (manager_xrandr->resources); manager_xrandr->resources = NULL; + if (manager_xrandr->logind_watch_id > 0) + g_bus_unwatch_name (manager_xrandr->logind_watch_id); + manager_xrandr->logind_watch_id = 0; + G_OBJECT_CLASS (meta_monitor_manager_xrandr_parent_class)->finalize (object); } @@ -1484,48 +1603,16 @@ meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass) #endif } -static gboolean -is_xvnc (MetaMonitorManager *manager) -{ - unsigned int i; - - for (i = 0; i < manager->n_outputs; ++i) - if (g_str_has_prefix (manager->outputs[i].name, "VNC-")) - return TRUE; - - return FALSE; -} - gboolean meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xrandr, XEvent *event) { - MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr); - gboolean hotplug; - unsigned int timestamp; - if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify) return FALSE; XRRUpdateConfiguration (event); - meta_monitor_manager_read_current_config (manager); - - timestamp = manager_xrandr->resources->timestamp; - if (is_xvnc (manager)) - timestamp += 100; - - hotplug = timestamp < manager_xrandr->resources->configTimestamp; - if (hotplug) - { - /* This is a hotplug event, so go ahead and build a new configuration. */ - meta_monitor_manager_on_hotplug (manager); - } - else - { - /* Something else changed -- tell the world about it. */ - meta_monitor_manager_rebuild_derived (manager); - } + meta_monitor_manager_xrandr_update (manager_xrandr); return TRUE; } -- 2.12.0