From 0a205c86df3422c4918d225c29adc0a06bc4e2d5 Mon Sep 17 00:00:00 2001 From: Rui Matos Date: Sun, 25 Oct 2015 16:14:58 +0100 Subject: [PATCH 4/4] 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 | 215 +++++++++++++++++-------- 1 file changed, 151 insertions(+), 64 deletions(-) diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c index 9a64bb2..d2a5df2 100644 --- a/src/backends/x11/meta-monitor-manager-xrandr.c +++ b/src/backends/x11/meta-monitor-manager-xrandr.c @@ -59,6 +59,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; }; struct _MetaMonitorManagerXrandrClass @@ -506,8 +511,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; @@ -1083,60 +1095,6 @@ meta_monitor_manager_xrandr_rebuild_derived (MetaMonitorManager *manager) meta_monitor_manager_rebuild_derived (manager); } -static void -meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr) -{ - MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ()); - - manager_xrandr->xdisplay = meta_backend_x11_get_xdisplay (backend); - - if (!XRRQueryExtension (manager_xrandr->xdisplay, - &manager_xrandr->rr_event_base, - &manager_xrandr->rr_error_base)) - { - return; - } - else - { - /* We only use ScreenChangeNotify, but GDK uses the others, - and we don't want to step on its toes */ - XRRSelectInput (manager_xrandr->xdisplay, - DefaultRootWindow (manager_xrandr->xdisplay), - RRScreenChangeNotifyMask - | RRCrtcChangeNotifyMask - | RROutputPropertyNotifyMask); - } -} - -static void -meta_monitor_manager_xrandr_finalize (GObject *object) -{ - MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (object); - - if (manager_xrandr->resources) - XRRFreeScreenResources (manager_xrandr->resources); - manager_xrandr->resources = NULL; - - G_OBJECT_CLASS (meta_monitor_manager_xrandr_parent_class)->finalize (object); -} - -static void -meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass) -{ - MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass); - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = meta_monitor_manager_xrandr_finalize; - - manager_class->read_current = meta_monitor_manager_xrandr_read_current; - manager_class->read_edid = meta_monitor_manager_xrandr_read_edid; - manager_class->apply_configuration = meta_monitor_manager_xrandr_apply_configuration; - manager_class->set_power_save_mode = meta_monitor_manager_xrandr_set_power_save_mode; - manager_class->change_backlight = meta_monitor_manager_xrandr_change_backlight; - manager_class->get_crtc_gamma = meta_monitor_manager_xrandr_get_crtc_gamma; - manager_class->set_crtc_gamma = meta_monitor_manager_xrandr_set_crtc_gamma; -} - static gboolean is_xvnc (MetaMonitorManager *manager) { @@ -1149,9 +1107,8 @@ is_xvnc (MetaMonitorManager *manager) return FALSE; } -gboolean -meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xrandr, - XEvent *event) +static void +meta_monitor_manager_xrandr_update (MetaMonitorManagerXrandr *manager_xrandr) { MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr); MetaOutput *old_outputs; @@ -1162,11 +1119,6 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra gboolean applied_config = FALSE; unsigned int timestamp; - if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify) - return FALSE; - - XRRUpdateConfiguration (event); - /* Save the old structures, so they stay valid during the update */ old_outputs = manager->outputs; n_old_outputs = manager->n_outputs; @@ -1210,6 +1162,141 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra meta_monitor_manager_free_output_array (old_outputs, n_old_outputs); meta_monitor_manager_free_mode_array (old_modes, n_old_modes); g_free (old_crtcs); +} + +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) +{ + MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ()); + + manager_xrandr->xdisplay = meta_backend_x11_get_xdisplay (backend); + + if (!XRRQueryExtension (manager_xrandr->xdisplay, + &manager_xrandr->rr_event_base, + &manager_xrandr->rr_error_base)) + { + return; + } + else + { + /* We only use ScreenChangeNotify, but GDK uses the others, + and we don't want to step on its toes */ + XRRSelectInput (manager_xrandr->xdisplay, + DefaultRootWindow (manager_xrandr->xdisplay), + RRScreenChangeNotifyMask + | RRCrtcChangeNotifyMask + | RROutputPropertyNotifyMask); + } + + 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 +meta_monitor_manager_xrandr_finalize (GObject *object) +{ + MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (object); + + if (manager_xrandr->resources) + 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); +} + +static void +meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass) +{ + MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_monitor_manager_xrandr_finalize; + + manager_class->read_current = meta_monitor_manager_xrandr_read_current; + manager_class->read_edid = meta_monitor_manager_xrandr_read_edid; + manager_class->apply_configuration = meta_monitor_manager_xrandr_apply_configuration; + manager_class->set_power_save_mode = meta_monitor_manager_xrandr_set_power_save_mode; + manager_class->change_backlight = meta_monitor_manager_xrandr_change_backlight; + manager_class->get_crtc_gamma = meta_monitor_manager_xrandr_get_crtc_gamma; + manager_class->set_crtc_gamma = meta_monitor_manager_xrandr_set_crtc_gamma; +} + +gboolean +meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xrandr, + XEvent *event) +{ + if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify) + return FALSE; + + XRRUpdateConfiguration (event); + + meta_monitor_manager_xrandr_update (manager_xrandr); return TRUE; } -- 2.5.0