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