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
This commit is contained in:
parent
3b61b85f2c
commit
bbbcd8c631
@ -75,6 +75,7 @@ MUTTER_PC_MODULES="
|
|||||||
xcomposite >= 0.2 xfixes xrender xdamage xi >= 1.6.0
|
xcomposite >= 0.2 xfixes xrender xdamage xi >= 1.6.0
|
||||||
$CLUTTER_PACKAGE >= 1.14.3
|
$CLUTTER_PACKAGE >= 1.14.3
|
||||||
cogl-1.0 >= 1.13.3
|
cogl-1.0 >= 1.13.3
|
||||||
|
upower-glib > 0.9.11
|
||||||
"
|
"
|
||||||
|
|
||||||
GLIB_GSETTINGS
|
GLIB_GSETTINGS
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <clutter/clutter.h>
|
#include <clutter/clutter.h>
|
||||||
|
#include <libupower-glib/upower.h>
|
||||||
|
|
||||||
#ifdef HAVE_RANDR
|
#ifdef HAVE_RANDR
|
||||||
#include <X11/extensions/Xrandr.h>
|
#include <X11/extensions/Xrandr.h>
|
||||||
@ -88,9 +89,13 @@ struct _MetaMonitorConfig {
|
|||||||
GHashTable *configs;
|
GHashTable *configs;
|
||||||
MetaConfiguration *current;
|
MetaConfiguration *current;
|
||||||
gboolean current_is_stored;
|
gboolean current_is_stored;
|
||||||
|
MetaConfiguration *previous;
|
||||||
|
|
||||||
GFile *file;
|
GFile *file;
|
||||||
GCancellable *save_cancellable;
|
GCancellable *save_cancellable;
|
||||||
|
|
||||||
|
UpClient *up_client;
|
||||||
|
gboolean lid_is_closed;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _MetaMonitorConfigClass {
|
struct _MetaMonitorConfigClass {
|
||||||
@ -104,6 +109,9 @@ static gboolean meta_monitor_config_assign_crtcs (MetaConfiguration *config,
|
|||||||
GPtrArray *crtcs,
|
GPtrArray *crtcs,
|
||||||
GPtrArray *outputs);
|
GPtrArray *outputs);
|
||||||
|
|
||||||
|
static void power_client_changed_cb (UpClient *client,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
free_output_key (MetaOutputKey *key)
|
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);
|
path = g_build_filename (g_get_user_config_dir (), filename, NULL);
|
||||||
self->file = g_file_new_for_path (path);
|
self->file = g_file_new_for_path (path);
|
||||||
g_free (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
|
static void
|
||||||
@ -808,6 +822,8 @@ apply_configuration (MetaMonitorConfig *self,
|
|||||||
{
|
{
|
||||||
g_ptr_array_unref (crtcs);
|
g_ptr_array_unref (crtcs);
|
||||||
g_ptr_array_unref (outputs);
|
g_ptr_array_unref (outputs);
|
||||||
|
if (!stored)
|
||||||
|
config_free (config);
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -816,16 +832,108 @@ apply_configuration (MetaMonitorConfig *self,
|
|||||||
(MetaCRTCInfo**)crtcs->pdata, crtcs->len,
|
(MetaCRTCInfo**)crtcs->pdata, crtcs->len,
|
||||||
(MetaOutputInfo**)outputs->pdata, outputs->len);
|
(MetaOutputInfo**)outputs->pdata, outputs->len);
|
||||||
|
|
||||||
if (self->current && !self->current_is_stored)
|
/* Stored (persistent) configurations override the previous one always.
|
||||||
config_free (self->current);
|
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 = config;
|
||||||
self->current_is_stored = stored;
|
self->current_is_stored = stored;
|
||||||
|
|
||||||
|
if (self->current == self->previous)
|
||||||
|
self->previous = NULL;
|
||||||
|
|
||||||
g_ptr_array_unref (crtcs);
|
g_ptr_array_unref (crtcs);
|
||||||
g_ptr_array_unref (outputs);
|
g_ptr_array_unref (outputs);
|
||||||
return TRUE;
|
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
|
gboolean
|
||||||
meta_monitor_config_apply_stored (MetaMonitorConfig *self,
|
meta_monitor_config_apply_stored (MetaMonitorConfig *self,
|
||||||
MetaMonitorManager *manager)
|
MetaMonitorManager *manager)
|
||||||
@ -839,7 +947,13 @@ meta_monitor_config_apply_stored (MetaMonitorConfig *self,
|
|||||||
|
|
||||||
if (stored)
|
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
|
else
|
||||||
return FALSE;
|
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);
|
default_config = make_default_config (self, outputs, n_outputs, max_width, max_height);
|
||||||
|
|
||||||
if (default_config != NULL)
|
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
|
else
|
||||||
ok = FALSE;
|
ok = FALSE;
|
||||||
|
|
||||||
@ -1137,6 +1262,53 @@ meta_monitor_config_update_current (MetaMonitorConfig *self,
|
|||||||
self->current_is_stored = FALSE;
|
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 {
|
typedef struct {
|
||||||
MetaMonitorConfig *config;
|
MetaMonitorConfig *config;
|
||||||
GString *buffer;
|
GString *buffer;
|
||||||
@ -1276,6 +1448,10 @@ meta_monitor_config_make_persistent (MetaMonitorConfig *self)
|
|||||||
self->current_is_stored = TRUE;
|
self->current_is_stored = TRUE;
|
||||||
g_hash_table_replace (self->configs, self->current, self->current);
|
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);
|
meta_monitor_config_save (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,6 +269,9 @@ void meta_monitor_config_update_current (MetaMonitorConfig *confi
|
|||||||
MetaMonitorManager *manager);
|
MetaMonitorManager *manager);
|
||||||
void meta_monitor_config_make_persistent (MetaMonitorConfig *config);
|
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_crtc_info_free (MetaCRTCInfo *info);
|
||||||
void meta_output_info_free (MetaOutputInfo *info);
|
void meta_output_info_free (MetaOutputInfo *info);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user