[mutter/wip/display-no-wayland: 26/33] MonitorConfig: handle changes in the laptop lid



commit 028fa6cd4e86d3ddaee5d857d5177a20422527e2
Author: Giovanni Campagna <gcampagn redhat com>
Date:   Fri Jul 26 18:22:59 2013 +0200

    MonitorConfig: handle changes in the laptop lid
    
    This way we don't need to track the current and previous
    configuration in gnome-settings-daemon, when we already do so
    in mutter.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=705670

 configure.ac               |    1 +
 src/core/monitor-config.c  |  186 +++++++++++++++++++++++++++++++++++++++++++-
 src/core/monitor-private.h |    3 +
 3 files changed, 186 insertions(+), 4 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 9baf35b..49d6e9d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -75,6 +75,7 @@ MUTTER_PC_MODULES="
    xcomposite >= 0.2 xfixes xrender xdamage xi >= 1.6.0
    $CLUTTER_PACKAGE >= 1.14.3
    cogl-1.0 >= 1.13.3
+   upower-glib > 0.9.11
 "
 
 GLIB_GSETTINGS
diff --git a/src/core/monitor-config.c b/src/core/monitor-config.c
index 8b656b7..98089c1 100644
--- a/src/core/monitor-config.c
+++ b/src/core/monitor-config.c
@@ -38,6 +38,7 @@
 
 #include <string.h>
 #include <clutter/clutter.h>
+#include <libupower-glib/upower.h>
 
 #ifdef HAVE_RANDR
 #include <X11/extensions/Xrandr.h>
@@ -88,9 +89,13 @@ struct _MetaMonitorConfig {
   GHashTable *configs;
   MetaConfiguration *current;
   gboolean current_is_stored;
+  MetaConfiguration *previous;
 
   GFile *file;
   GCancellable *save_cancellable;
+
+  UpClient *up_client;
+  gboolean lid_is_closed;
 };
 
 struct _MetaMonitorConfigClass {
@@ -104,6 +109,9 @@ static gboolean meta_monitor_config_assign_crtcs (MetaConfiguration  *config,
                                                   GPtrArray          *crtcs,
                                                   GPtrArray          *outputs);
 
+static void     power_client_changed_cb (UpClient *client,
+                                         gpointer  user_data);
+
 static void
 free_output_key (MetaOutputKey *key)
 {
@@ -199,6 +207,12 @@ meta_monitor_config_init (MetaMonitorConfig *self)
   path = g_build_filename (g_get_user_config_dir (), filename, NULL);
   self->file = g_file_new_for_path (path);
   g_free (path);
+
+  self->up_client = up_client_new ();
+  self->lid_is_closed = up_client_get_lid_is_closed (self->up_client);
+
+  g_signal_connect_object (self->up_client, "changed",
+                           G_CALLBACK (power_client_changed_cb), self, 0);
 }
 
 static void
@@ -808,6 +822,8 @@ apply_configuration (MetaMonitorConfig  *self,
     {
       g_ptr_array_unref (crtcs);
       g_ptr_array_unref (outputs);
+      if (!stored)
+        config_free (config);
 
       return FALSE;
     }
@@ -816,16 +832,108 @@ apply_configuration (MetaMonitorConfig  *self,
                                             (MetaCRTCInfo**)crtcs->pdata, crtcs->len,
                                             (MetaOutputInfo**)outputs->pdata, outputs->len);
 
-  if (self->current && !self->current_is_stored)
-    config_free (self->current);
+  /* Stored (persistent) configurations override the previous one always.
+     Also, we clear the previous configuration if the current one (which is
+     about to become previous) is stored.
+  */
+  if (stored ||
+      (self->current && self->current_is_stored))
+    {
+      if (self->previous)
+        config_free (self->previous);
+      self->previous = NULL;
+    }
+  else
+    {
+      self->previous = self->current;
+    }
+
   self->current = config;
   self->current_is_stored = stored;
 
+  if (self->current == self->previous)
+    self->previous = NULL;
+
   g_ptr_array_unref (crtcs);
   g_ptr_array_unref (outputs);
   return TRUE;
 }
 
+static gboolean
+key_is_laptop (MetaOutputKey *key)
+{
+  /* FIXME: extend with better heuristics */
+  return g_str_has_prefix (key->connector, "LVDS") ||
+    g_str_has_prefix (key->connector, "eDP");
+}
+
+static gboolean
+laptop_display_is_on (MetaConfiguration *config)
+{
+  unsigned int i;
+
+  for (i = 0; i < config->n_outputs; i++)
+    {
+      MetaOutputKey *key = &config->keys[i];
+      MetaOutputConfig *output = &config->outputs[i];
+
+      if (key_is_laptop (key) && output->enabled)
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+static MetaConfiguration *
+make_laptop_lid_config (MetaConfiguration  *reference)
+{
+  MetaConfiguration *new;
+  unsigned int i;
+  gboolean has_primary;
+
+  g_assert (reference->n_outputs > 1);
+
+  new = g_slice_new0 (MetaConfiguration);
+  new->n_outputs = reference->n_outputs;
+  new->keys = g_new0 (MetaOutputKey, reference->n_outputs);
+  new->outputs = g_new0 (MetaOutputConfig, reference->n_outputs);
+
+  for (i = 0; i < new->n_outputs; i++)
+    {
+      MetaOutputKey *current_key = &reference->keys[i];
+      MetaOutputConfig *current_output = &reference->outputs[i];
+
+      new->keys[i].connector = g_strdup (current_key->connector);
+      new->keys[i].vendor = g_strdup (current_key->vendor);
+      new->keys[i].product = g_strdup (current_key->product);
+      new->keys[i].serial = g_strdup (current_key->serial);
+
+      if (g_str_has_prefix (current_key->connector, "LVDS") ||
+          g_str_has_prefix (current_key->connector, "eDP"))
+        new->outputs[i].enabled = FALSE;
+      else
+        /* This can potentially leave a "hole" in the screen,
+           but this is actually a good thing, as it means windows
+           don't move around.
+        */
+        new->outputs[i] = *current_output;
+    }
+
+  has_primary = FALSE;
+  for (i = 0; i < new->n_outputs; i++)
+    {
+      if (new->outputs[i].is_primary)
+        {
+          has_primary = TRUE;
+          break;
+        }
+    }
+  if (!has_primary)
+    new->outputs[0].is_primary = TRUE;
+
+  return new;
+}
+
 gboolean
 meta_monitor_config_apply_stored (MetaMonitorConfig  *self,
                                  MetaMonitorManager *manager)
@@ -839,7 +947,13 @@ meta_monitor_config_apply_stored (MetaMonitorConfig  *self,
 
   if (stored)
     {
-      return apply_configuration (self, stored, manager, TRUE);
+      if (self->lid_is_closed &&
+          stored->n_outputs > 1 &&
+          laptop_display_is_on (stored))
+        return apply_configuration (self, make_laptop_lid_config (stored),
+                                    manager, FALSE);
+      else
+        return apply_configuration (self, stored, manager, TRUE);
     }
   else
     return FALSE;
@@ -1080,7 +1194,18 @@ meta_monitor_config_make_default (MetaMonitorConfig  *self,
   default_config = make_default_config (self, outputs, n_outputs, max_width, max_height);
 
   if (default_config != NULL)
-    ok = apply_configuration (self, default_config, manager, FALSE);
+    {
+      if (self->lid_is_closed &&
+          default_config->n_outputs > 1 &&
+          laptop_display_is_on (default_config))
+        {
+          ok = apply_configuration (self, make_laptop_lid_config (default_config),
+                                    manager, FALSE);
+          config_free (default_config);
+        }
+      else
+        ok = apply_configuration (self, default_config, manager, FALSE);
+    }
   else
     ok = FALSE;
 
@@ -1137,6 +1262,55 @@ meta_monitor_config_update_current (MetaMonitorConfig  *self,
   self->current_is_stored = FALSE;
 }
 
+void
+meta_monitor_config_restore_previous (MetaMonitorConfig  *self,
+                                      MetaMonitorManager *manager)
+{
+  if (self->previous)
+    {
+      apply_configuration (self, self->previous, manager, FALSE);
+    }
+  else
+    {
+      if (!meta_monitor_config_apply_stored (self, manager))
+        meta_monitor_config_make_default (self, manager);
+    }
+}
+
+static void
+turn_off_laptop_display (MetaMonitorConfig  *self,
+                         MetaMonitorManager *manager)
+{
+  MetaConfiguration *new;
+
+  if (self->current->n_outputs == 1)
+    return;
+
+  new = make_laptop_lid_config (self->current);
+  apply_configuration (self, new, manager, FALSE);
+}
+
+static void
+power_client_changed_cb (UpClient *client,
+                         gpointer  user_data)
+{
+  MetaMonitorManager *manager = meta_monitor_manager_get ();
+  MetaMonitorConfig *self = user_data;
+  gboolean is_closed;
+
+  is_closed = up_client_get_lid_is_closed (self->up_client);
+
+  if (is_closed != self->lid_is_closed)
+    {
+      self->lid_is_closed = is_closed;
+
+      if (is_closed)
+        turn_off_laptop_display (self, manager);
+      else
+        meta_monitor_config_restore_previous (self, manager);
+    }
+}
+
 typedef struct {
   MetaMonitorConfig *config;
   GString *buffer;
@@ -1276,6 +1450,10 @@ meta_monitor_config_make_persistent (MetaMonitorConfig *self)
   self->current_is_stored = TRUE;
   g_hash_table_replace (self->configs, self->current, self->current);
 
+  if (self->previous)
+    config_free (self->previous);
+  self->previous = NULL;
+
   meta_monitor_config_save (self);
 }
 
diff --git a/src/core/monitor-private.h b/src/core/monitor-private.h
index 1da575f..6c11ef7 100644
--- a/src/core/monitor-private.h
+++ b/src/core/monitor-private.h
@@ -269,6 +269,9 @@ void               meta_monitor_config_update_current (MetaMonitorConfig  *confi
                                                        MetaMonitorManager *manager);
 void               meta_monitor_config_make_persistent (MetaMonitorConfig *config);
 
+void               meta_monitor_config_restore_previous (MetaMonitorConfig  *config,
+                                                         MetaMonitorManager *manager);
+
 void               meta_crtc_info_free   (MetaCRTCInfo   *info);
 void               meta_output_info_free (MetaOutputInfo *info);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]