Blob Blame History Raw
From 0a205c86df3422c4918d225c29adc0a06bc4e2d5 Mon Sep 17 00:00:00 2001
From: Rui Matos <tiagomatos@gmail.com>
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