diff options
author | Federico Mena Quintero <federico@gnome.org> | 2012-01-10 18:09:18 -0600 |
---|---|---|
committer | Federico Mena Quintero <federico@gnome.org> | 2012-01-10 18:09:31 -0600 |
commit | 6e17bc786f55f283f2c721249197e7740174fd43 (patch) | |
tree | 1a2452bf78450046e78afa61846f5b34345d7765 | |
parent | 7675bffde2fb0e0f25d41d3f30748809353e128a (diff) | |
parent | 7e238f2da29c383ba391fd8d133bbcf3e5348fe2 (diff) | |
download | gnome-settings-daemon-6e17bc786f55f283f2c721249197e7740174fd43.tar.gz |
Merge branch 'docking-stations' - bgo#663126
This lets docking stations work better in the light of plugging external monitors.
It used to be that a docked laptop, with a closed lid, would still keep the
LCD active, thus making it pretty useless with an external monitor.
Now, we disable the LCD if the laptop's lid is closed, as expected.
Additionally, to decide when to suspend the laptop, we do so if there
are no plugged or usable RANDR outputs. For example, a docked laptop
with a closed lid and *no* external monitor has no usable outputs, so
it will get suspended.
This requires gnome-desktop 3.3.4 or later, as the semantics of
gnome_rr_screen_new() are slightly different there - now it returns a
singleton instead of a new object every time.
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | gnome-settings-daemon/Makefile.am | 2 | ||||
-rw-r--r-- | gnome-settings-daemon/gnome-settings-session.c | 15 | ||||
-rw-r--r-- | gnome-settings-daemon/gnome-settings-session.h | 4 | ||||
-rw-r--r-- | plugins/color/gsd-color-manager.c | 2 | ||||
-rw-r--r-- | plugins/power/gsd-power-manager.c | 107 | ||||
-rw-r--r-- | plugins/xrandr/Makefile.am | 2 | ||||
-rw-r--r-- | plugins/xrandr/gsd-xrandr-manager.c | 589 |
8 files changed, 453 insertions, 270 deletions
diff --git a/configure.ac b/configure.ac index 64f93d5f..895e4431 100644 --- a/configure.ac +++ b/configure.ac @@ -48,7 +48,7 @@ GLIB_REQUIRED_VERSION=2.29.14 GTK_REQUIRED_VERSION=3.3.4 GCONF_REQUIRED_VERSION=2.6.1 GIO_REQUIRED_VERSION=2.26.0 -GNOME_DESKTOP_REQUIRED_VERSION=3.3.1 +GNOME_DESKTOP_REQUIRED_VERSION=3.3.4 LIBNOTIFY_REQUIRED_VERSION=0.7.3 UPOWER_GLIB_REQUIRED_VERSION=0.9.1 PA_REQUIRED_VERSION=0.9.16 diff --git a/gnome-settings-daemon/Makefile.am b/gnome-settings-daemon/Makefile.am index 7e0e0929..37734a76 100644 --- a/gnome-settings-daemon/Makefile.am +++ b/gnome-settings-daemon/Makefile.am @@ -9,6 +9,7 @@ INCLUDES = \ $(DISABLE_DEPRECATED_CFLAGS) \ $(SETTINGS_DAEMON_CFLAGS) \ $(LIBNOTIFY_CFLAGS) \ + $(UPOWER_CFLAGS) \ $(GNOME_DESKTOP_CFLAGS) \ $(NULL) @@ -75,6 +76,7 @@ gnome_settings_daemon_LDADD = \ libgsd-profile.la \ $(SETTINGS_DAEMON_LIBS) \ $(LIBNOTIFY_LIBS) \ + $(UPOWER_LIBS) \ $(GNOME_DESKTOP_LIBS) \ $(NULL) diff --git a/gnome-settings-daemon/gnome-settings-session.c b/gnome-settings-daemon/gnome-settings-session.c index d32490af..af4922f9 100644 --- a/gnome-settings-daemon/gnome-settings-session.c +++ b/gnome-settings-daemon/gnome-settings-session.c @@ -307,18 +307,3 @@ gnome_settings_session_new (void) session = g_object_new (GNOME_TYPE_SETTINGS_SESSION, NULL); return GNOME_SETTINGS_SESSION (session); } - -GnomeRRScreen * -gnome_settings_session_get_screen (GError **error) -{ - static GnomeRRScreen *screen = NULL; - - if (screen != NULL) - return g_object_ref (screen); - - screen = gnome_rr_screen_new (gdk_screen_get_default (), error); - if (screen != NULL) - g_object_add_weak_pointer (G_OBJECT (screen), (gpointer *) &screen); - - return screen; -} diff --git a/gnome-settings-daemon/gnome-settings-session.h b/gnome-settings-daemon/gnome-settings-session.h index ba93cf22..c9b64ee9 100644 --- a/gnome-settings-daemon/gnome-settings-session.h +++ b/gnome-settings-daemon/gnome-settings-session.h @@ -24,9 +24,6 @@ #include <glib-object.h> -#define GNOME_DESKTOP_USE_UNSTABLE_API -#include <libgnome-desktop/gnome-rr.h> - G_BEGIN_DECLS #define GNOME_TYPE_SETTINGS_SESSION (gnome_settings_session_get_type ()) @@ -61,7 +58,6 @@ GType gnome_settings_session_state_get_type (void); GnomeSettingsSession *gnome_settings_session_new (void); GnomeSettingsSessionState gnome_settings_session_get_state (GnomeSettingsSession *session); -GnomeRRScreen *gnome_settings_session_get_screen (GError **error); G_END_DECLS diff --git a/plugins/color/gsd-color-manager.c b/plugins/color/gsd-color-manager.c index ef62c22f..89f2fb85 100644 --- a/plugins/color/gsd-color-manager.c +++ b/plugins/color/gsd-color-manager.c @@ -1590,7 +1590,7 @@ gsd_color_manager_start (GsdColorManager *manager, gnome_settings_profile_start (NULL); /* coldplug the list of screens */ - priv->x11_screen = gnome_settings_session_get_screen (error); + priv->x11_screen = gnome_rr_screen_new (gdk_screen_get_default (), error); if (priv->x11_screen == NULL) goto out; diff --git a/plugins/power/gsd-power-manager.c b/plugins/power/gsd-power-manager.c index b51d29d2..8d12c2c5 100644 --- a/plugins/power/gsd-power-manager.c +++ b/plugins/power/gsd-power-manager.c @@ -32,7 +32,7 @@ #include <canberra-gtk.h> #define GNOME_DESKTOP_USE_UNSTABLE_API -#include <libgnome-desktop/gnome-rr.h> +#include <libgnome-desktop/gnome-rr-config.h> #include "gpm-common.h" #include "gpm-phone.h" @@ -2163,6 +2163,46 @@ do_lid_open_action (GsdPowerManager *manager) } +static gboolean +is_laptop (GnomeRRScreen *screen, GnomeRROutputInfo *output) +{ + GnomeRROutput *rr_output; + + rr_output = gnome_rr_screen_get_output_by_name (screen, gnome_rr_output_info_get_name (output)); + + return gnome_rr_output_is_laptop (rr_output); +} + +static gboolean +non_laptop_outputs_are_all_off (GnomeRRScreen *screen) +{ + GnomeRRConfig *config; + GnomeRROutputInfo **outputs; + int i; + gboolean all_off; + + config = gnome_rr_config_new_current (screen, NULL); /* NULL-GError */ + if (!config) + return FALSE; + + outputs = gnome_rr_config_get_outputs (config); + for (i = 0; outputs[i] != NULL; i++) { + if (is_laptop (screen, outputs[i])) + continue; + + if (gnome_rr_output_info_is_active (outputs[i])) { + all_off = FALSE; + goto out; + } + } + + all_off = TRUE; + +out: + g_object_unref (config); + return all_off; +} + static void do_lid_closed_action (GsdPowerManager *manager) { @@ -2196,12 +2236,6 @@ do_lid_closed_action (GsdPowerManager *manager) } } - /* are we docked? */ - if (up_client_get_is_docked (manager->priv->up_client)) { - g_debug ("ignoring lid closed action because we are docked"); - return; - } - /* ensure we turn the panel back on after resume */ ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen, GNOME_RR_DPMS_OFF, @@ -2224,7 +2258,11 @@ do_lid_closed_action (GsdPowerManager *manager) } /* perform policy action */ - do_power_action_type (manager, action_type); + if (non_laptop_outputs_are_all_off (manager->priv->x11_screen)) { + g_debug ("lid is closed; suspending or hibernating"); + do_power_action_type (manager, action_type); + } else + g_debug ("lid is closed; not suspending nor hibernating since some external monitor outputs are still active"); } @@ -3487,8 +3525,8 @@ gsd_power_manager_start (GsdPowerManager *manager, G_CALLBACK (engine_device_removed_cb), manager); g_signal_connect (manager->priv->up_client, "device-changed", G_CALLBACK (engine_device_changed_cb), manager); - g_signal_connect (manager->priv->up_client, "changed", - G_CALLBACK (up_client_changed_cb), manager); + g_signal_connect_after (manager->priv->up_client, "changed", + G_CALLBACK (up_client_changed_cb), manager); /* use the fallback name from gnome-power-manager so the shell * blocks this, and uses the power extension instead */ @@ -3601,7 +3639,7 @@ gsd_power_manager_start (GsdPowerManager *manager, G_CALLBACK (idle_idletime_alarm_expired_cb), manager); /* coldplug the list of screens */ - manager->priv->x11_screen = gnome_settings_session_get_screen (error); + manager->priv->x11_screen = gnome_rr_screen_new (gdk_screen_get_default (), error); if (manager->priv->x11_screen == NULL) return FALSE; @@ -3644,40 +3682,71 @@ gsd_power_manager_stop (GsdPowerManager *manager) manager->priv->connection = NULL; } - if (manager->priv->timeout_blank_id != 0) + if (manager->priv->timeout_blank_id != 0) { g_source_remove (manager->priv->timeout_blank_id); - if (manager->priv->timeout_sleep_id != 0) + manager->priv->timeout_blank_id = 0; + } + + if (manager->priv->timeout_sleep_id != 0) { g_source_remove (manager->priv->timeout_sleep_id); + manager->priv->timeout_sleep_id = 0; + } g_object_unref (manager->priv->session); g_object_unref (manager->priv->settings); g_object_unref (manager->priv->settings_screensaver); g_object_unref (manager->priv->up_client); - if (manager->priv->x11_screen != NULL) + manager->priv->session = NULL; + manager->priv->settings = NULL; + manager->priv->settings_screensaver = NULL; + manager->priv->up_client = NULL; + + if (manager->priv->x11_screen != NULL) { g_object_unref (manager->priv->x11_screen); + manager->priv->x11_screen = NULL; + } g_ptr_array_unref (manager->priv->devices_array); g_object_unref (manager->priv->phone); g_object_unref (manager->priv->device_composite); + manager->priv->devices_array = NULL; + manager->priv->phone = NULL; + manager->priv->device_composite = NULL; - if (manager->priv->previous_icon != NULL) + if (manager->priv->previous_icon != NULL) { g_object_unref (manager->priv->previous_icon); + manager->priv->previous_icon = NULL; + } + g_free (manager->priv->previous_summary); + manager->priv->previous_summary = NULL; - if (manager->priv->upower_proxy != NULL) + if (manager->priv->upower_proxy != NULL) { g_object_unref (manager->priv->upower_proxy); - if (manager->priv->session_proxy != NULL) + manager->priv->upower_proxy = NULL; + } + + if (manager->priv->session_proxy != NULL) { g_object_unref (manager->priv->session_proxy); - if (manager->priv->session_presence_proxy != NULL) + manager->priv->session_proxy = NULL; + } + + if (manager->priv->session_presence_proxy != NULL) { g_object_unref (manager->priv->session_presence_proxy); + manager->priv->session_presence_proxy = NULL; + } - if (manager->priv->critical_alert_timeout_id > 0) + if (manager->priv->critical_alert_timeout_id > 0) { g_source_remove (manager->priv->critical_alert_timeout_id); + manager->priv->critical_alert_timeout_id = 0; + } gpm_idletime_alarm_remove (manager->priv->idletime, GSD_POWER_IDLETIME_ID); g_object_unref (manager->priv->idletime); g_object_unref (manager->priv->status_icon); + manager->priv->idletime = NULL; + manager->priv->status_icon = NULL; } static void diff --git a/plugins/xrandr/Makefile.am b/plugins/xrandr/Makefile.am index aaba341f..a6deabfc 100644 --- a/plugins/xrandr/Makefile.am +++ b/plugins/xrandr/Makefile.am @@ -49,6 +49,7 @@ libxrandr_la_CPPFLAGS = \ libxrandr_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ + $(UPOWER_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(GNOME_DESKTOP_CFLAGS) \ $(AM_CFLAGS) @@ -58,6 +59,7 @@ libxrandr_la_LDFLAGS = \ libxrandr_la_LIBADD = \ $(top_builddir)/plugins/common/libcommon.la \ + $(UPOWER_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ $(GNOME_DESKTOP_LIBS) diff --git a/plugins/xrandr/gsd-xrandr-manager.c b/plugins/xrandr/gsd-xrandr-manager.c index a9893527..26a7e02b 100644 --- a/plugins/xrandr/gsd-xrandr-manager.c +++ b/plugins/xrandr/gsd-xrandr-manager.c @@ -38,6 +38,7 @@ #include <gdk/gdk.h> #include <gdk/gdkx.h> #include <gtk/gtk.h> +#include <libupower-glib/upower.h> #define GNOME_DESKTOP_USE_UNSTABLE_API @@ -102,6 +103,9 @@ struct GsdXrandrManagerPrivate GnomeRRScreen *rw_screen; gboolean running; + UpClient *upower_client; + gboolean laptop_lid_is_closed; + GSettings *settings; GDBusNodeInfo *introspection_data; GDBusConnection *connection; @@ -353,10 +357,68 @@ print_configuration (GnomeRRConfig *config, const char *header) print_output (outputs[i]); } -/* This function centralizes the use of gnome_rr_config_apply_from_filename_with_time(). +static gboolean +is_laptop (GnomeRRScreen *screen, GnomeRROutputInfo *output) +{ + GnomeRROutput *rr_output; + + rr_output = gnome_rr_screen_get_output_by_name (screen, gnome_rr_output_info_get_name (output)); + + return gnome_rr_output_is_laptop (rr_output); +} + +static GnomeRROutputInfo * +get_laptop_output_info (GnomeRRScreen *screen, GnomeRRConfig *config) +{ + int i; + GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (config); + + for (i = 0; outputs[i] != NULL; i++) { + if (is_laptop (screen, outputs[i])) + return outputs[i]; + } + + return NULL; +} + +static gboolean +non_laptop_outputs_are_active (GnomeRRConfig *config, GnomeRROutputInfo *laptop_info) +{ + GnomeRROutputInfo **outputs; + int i; + + outputs = gnome_rr_config_get_outputs (config); + for (i = 0; outputs[i] != NULL; i++) { + if (outputs[i] == laptop_info) + continue; + + if (gnome_rr_output_info_is_active (outputs[i])) + return TRUE; + } + + return FALSE; +} + +static void +turn_off_laptop_display_in_configuration (GnomeRRScreen *screen, GnomeRRConfig *config) +{ + GnomeRROutputInfo *laptop_info; + + laptop_info = get_laptop_output_info (screen, config); + if (laptop_info) { + /* Turn off the laptop's screen only if other displays are on. This is to avoid an all-black-screens scenario. */ + if (non_laptop_outputs_are_active (config, laptop_info)) + gnome_rr_output_info_set_active (laptop_info, FALSE); + } + + /* Adjust the offsets of outputs so they start at (0, 0) */ + gnome_rr_config_sanitize (config); +} + +/* This function effectively centralizes the use of gnome_rr_config_apply_from_filename_with_time(). * - * Optionally filters out GNOME_RR_ERROR_NO_MATCHING_CONFIG from - * gnome_rr_config_apply_from_filename_with_time(), since that is not usually an error. + * Optionally filters out GNOME_RR_ERROR_NO_MATCHING_CONFIG from the matching + * process(), since that is not usually an error. */ static gboolean apply_configuration_from_filename (GsdXrandrManager *manager, @@ -366,6 +428,7 @@ apply_configuration_from_filename (GsdXrandrManager *manager, GError **error) { struct GsdXrandrManagerPrivate *priv = manager->priv; + GnomeRRConfig *config; GError *my_error; gboolean success; char *str; @@ -375,24 +438,37 @@ apply_configuration_from_filename (GsdXrandrManager *manager, g_free (str); my_error = NULL; - success = gnome_rr_config_apply_from_filename_with_time (priv->rw_screen, filename, timestamp, &my_error); - if (success) - return TRUE; - if (g_error_matches (my_error, GNOME_RR_ERROR, GNOME_RR_ERROR_NO_MATCHING_CONFIG)) { - if (no_matching_config_is_an_error) - goto fail; + config = g_object_new (GNOME_TYPE_RR_CONFIG, "screen", priv->rw_screen, NULL); + if (!gnome_rr_config_load_filename (config, filename, &my_error)) { + g_object_unref (config); - /* This is not an error; the user probably changed his monitors - * and so they don't match any of the stored configurations. - */ - g_error_free (my_error); - return TRUE; + if (g_error_matches (my_error, GNOME_RR_ERROR, GNOME_RR_ERROR_NO_MATCHING_CONFIG)) { + if (no_matching_config_is_an_error) { + g_propagate_error (error, my_error); + return FALSE; + } else { + /* This is not an error; the user probably changed his monitors + * and so they don't match any of the stored configurations. + */ + g_error_free (my_error); + return TRUE; + } + } else { + g_propagate_error (error, my_error); + return FALSE; + } } -fail: - g_propagate_error (error, my_error); - return FALSE; + if (up_client_get_lid_is_closed (priv->upower_client)) + turn_off_laptop_display_in_configuration (priv->rw_screen, config); + + gnome_rr_config_ensure_primary (config); + success = gnome_rr_config_apply_with_time (config, priv->rw_screen, timestamp, error); + + g_object_unref (config); + + return success; } /* This function centralizes the use of gnome_rr_config_apply_with_time(). @@ -401,7 +477,7 @@ fail: * We just return whether setting the configuration succeeded. */ static gboolean -apply_configuration (GsdXrandrManager *manager, GnomeRRConfig *config, guint32 timestamp, gboolean show_error) +apply_configuration (GsdXrandrManager *manager, GnomeRRConfig *config, guint32 timestamp, gboolean show_error, gboolean save_configuration) { GsdXrandrManagerPrivate *priv = manager->priv; GError *error; @@ -413,7 +489,10 @@ apply_configuration (GsdXrandrManager *manager, GnomeRRConfig *config, guint32 t error = NULL; success = gnome_rr_config_apply_with_time (config, priv->rw_screen, timestamp, &error); - if (!success) { + if (success) { + if (save_configuration) + gnome_rr_config_save (config, NULL); /* NULL-GError - there's not much we can do if this fails */ + } else { log_msg ("Could not switch to the following configuration (timestamp %u): %s\n", timestamp, error->message); log_configuration (config); if (show_error) @@ -716,16 +795,6 @@ gsd_xrandr_manager_2_rotate_to (GsdXrandrManager *manager, } static gboolean -is_laptop (GnomeRRScreen *screen, GnomeRROutputInfo *output) -{ - GnomeRROutput *rr_output; - - rr_output = gnome_rr_screen_get_output_by_name (screen, gnome_rr_output_info_get_name (output)); - - return gnome_rr_output_is_laptop (rr_output); -} - -static gboolean get_clone_size (GnomeRRScreen *screen, int *width, int *height) { GnomeRRMode **modes = gnome_rr_screen_list_clone_modes (screen); @@ -777,8 +846,20 @@ config_is_all_off (GnomeRRConfig *config) return TRUE; } +static gboolean +laptop_lid_is_closed (GsdXrandrManager *manager) +{ + return up_client_get_lid_is_closed (manager->priv->upower_client); +} + +static gboolean +is_laptop_with_closed_lid (GsdXrandrManager *manager, GnomeRRScreen *screen, GnomeRROutputInfo *info) +{ + return is_laptop (screen, info) && laptop_lid_is_closed (manager); +} + static GnomeRRConfig * -make_clone_setup (GnomeRRScreen *screen) +make_clone_setup (GsdXrandrManager *manager, GnomeRRScreen *screen) { GnomeRRConfig *result; GnomeRROutputInfo **outputs; @@ -795,7 +876,7 @@ make_clone_setup (GnomeRRScreen *screen) GnomeRROutputInfo *info = outputs[i]; gnome_rr_output_info_set_active (info, FALSE); - if (gnome_rr_output_info_is_connected (info)) { + if (!is_laptop_with_closed_lid (manager, screen, info) && gnome_rr_output_info_is_connected (info)) { GnomeRROutput *output = gnome_rr_screen_get_output_by_name (screen, gnome_rr_output_info_get_name (info)); GnomeRRMode **modes = gnome_rr_output_list_modes (output); @@ -904,7 +985,7 @@ turn_on (GnomeRRScreen *screen, } static GnomeRRConfig * -make_laptop_setup (GnomeRRScreen *screen) +make_laptop_setup (GsdXrandrManager *manager, GnomeRRScreen *screen) { /* Turn on the laptop, disable everything else */ GnomeRRConfig *result = gnome_rr_config_new_current (screen, NULL); @@ -914,7 +995,7 @@ make_laptop_setup (GnomeRRScreen *screen) for (i = 0; outputs[i] != NULL; ++i) { GnomeRROutputInfo *info = outputs[i]; - if (is_laptop (screen, info)) { + if (is_laptop (screen, info) && !laptop_lid_is_closed (manager)) { if (!turn_on (screen, info, 0, 0)) { g_object_unref (G_OBJECT (result)); result = NULL; @@ -952,8 +1033,88 @@ turn_on_and_get_rightmost_offset (GnomeRRScreen *screen, GnomeRROutputInfo *info return x; } +/* Used from qsort(); compares outputs based on their X position */ +static int +compare_output_positions (const void *a, const void *b) +{ + GnomeRROutputInfo *oa = (GnomeRROutputInfo *) a; + GnomeRROutputInfo *ob = (GnomeRROutputInfo *) b; + int xa, xb; + + gnome_rr_output_info_get_geometry (oa, &xa, NULL, NULL, NULL); + gnome_rr_output_info_get_geometry (ob, &xb, NULL, NULL, NULL); + + return xb - xa; +} + +/* A set of outputs with already-set sizes and positions may not fit in the + * frame buffer that is available. Turn off outputs right-to-left until we find + * a size that fits. Returns whether something applicable was found + * (i.e. something that fits and that does not consist of only-off outputs). + */ +static gboolean +trim_rightmost_outputs_that_dont_fit_in_framebuffer (GnomeRRScreen *rr_screen, GnomeRRConfig *config) +{ + GnomeRROutputInfo **outputs; + GnomeRROutputInfo **sorted_outputs; + int num_on_outputs; + int i, j; + gboolean applicable; + + outputs = gnome_rr_config_get_outputs (config); + + /* How many are on? */ + + num_on_outputs = 0; + for (i = 0; outputs[i] != NULL; i++) { + if (gnome_rr_output_info_is_active (outputs[i])) + num_on_outputs++; + } + + /* Lay them out from left to right */ + + sorted_outputs = g_new (GnomeRROutputInfo *, num_on_outputs); + j = 0; + for (i = 0; outputs[i] != NULL; i++) { + if (gnome_rr_output_info_is_active (outputs[i])) { + sorted_outputs[j] = outputs[i]; + j++; + } + } + + qsort (sorted_outputs, num_on_outputs, sizeof (sorted_outputs[0]), compare_output_positions); + + /* Trim! */ + + applicable = FALSE; + + for (i = num_on_outputs - 1; i >= 0; i--) { + GError *error = NULL; + gboolean is_bounds_error; + + applicable = gnome_rr_config_applicable (config, rr_screen, &error); + if (applicable) + break; + + is_bounds_error = g_error_matches (error, GNOME_RR_ERROR, GNOME_RR_ERROR_BOUNDS_ERROR); + g_error_free (error); + + if (!is_bounds_error) + break; + + gnome_rr_output_info_set_active (sorted_outputs[i], FALSE); + } + + if (config_is_all_off (config)) + applicable = FALSE; + + g_free (sorted_outputs); + + return applicable; +} + static GnomeRRConfig * -make_xinerama_setup (GnomeRRScreen *screen) +make_xinerama_setup (GsdXrandrManager *manager, GnomeRRScreen *screen) { /* Turn on everything that has a preferred mode, and * position it from left to right @@ -967,18 +1128,26 @@ make_xinerama_setup (GnomeRRScreen *screen) for (i = 0; outputs[i] != NULL; ++i) { GnomeRROutputInfo *info = outputs[i]; - if (is_laptop (screen, info)) - x = turn_on_and_get_rightmost_offset (screen, info, x); + if (is_laptop (screen, info)) { + if (laptop_lid_is_closed (manager)) + gnome_rr_output_info_set_active (info, FALSE); + else { + gnome_rr_output_info_set_primary (info, TRUE); + x = turn_on_and_get_rightmost_offset (screen, info, x); + } + } } for (i = 0; outputs[i] != NULL; ++i) { GnomeRROutputInfo *info = outputs[i]; - if (gnome_rr_output_info_is_connected (info) && !is_laptop (screen, info)) + if (gnome_rr_output_info_is_connected (info) && !is_laptop (screen, info)) { + gnome_rr_output_info_set_primary (info, FALSE); x = turn_on_and_get_rightmost_offset (screen, info, x); + } } - if (config_is_all_off (result)) { + if (!trim_rightmost_outputs_that_dont_fit_in_framebuffer (screen, result)) { g_object_unref (G_OBJECT (result)); result = NULL; } @@ -1011,7 +1180,7 @@ make_other_setup (GnomeRRScreen *screen) } } - if (config_is_all_off (result)) { + if (!trim_rightmost_outputs_that_dont_fit_in_framebuffer (screen, result)) { g_object_unref (G_OBJECT (result)); result = NULL; } @@ -1129,9 +1298,9 @@ generate_fn_f7_configs (GsdXrandrManager *mgr) } g_ptr_array_add (array, gnome_rr_config_new_current (screen, NULL)); - g_ptr_array_add (array, make_clone_setup (screen)); - g_ptr_array_add (array, make_xinerama_setup (screen)); - g_ptr_array_add (array, make_laptop_setup (screen)); + g_ptr_array_add (array, make_clone_setup (mgr, screen)); + g_ptr_array_add (array, make_xinerama_setup (mgr, screen)); + g_ptr_array_add (array, make_laptop_setup (mgr, screen)); g_ptr_array_add (array, make_other_setup (screen)); array = sanitize (mgr, array); @@ -1245,7 +1414,7 @@ handle_fn_f7 (GsdXrandrManager *mgr, guint32 timestamp) if (timestamp < server_timestamp) timestamp = server_timestamp; - success = apply_configuration (mgr, priv->fn_f7_configs[mgr->priv->current_fn_f7_config], timestamp, TRUE); + success = apply_configuration (mgr, priv->fn_f7_configs[mgr->priv->current_fn_f7_config], timestamp, TRUE, TRUE); if (success) { log_msg ("Successfully switched to configuration (timestamp %u):\n", timestamp); @@ -1261,20 +1430,6 @@ handle_fn_f7 (GsdXrandrManager *mgr, guint32 timestamp) g_debug ("done handling fn-f7"); } -static GnomeRROutputInfo * -get_laptop_output_info (GnomeRRScreen *screen, GnomeRRConfig *config) -{ - int i; - GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (config); - - for (i = 0; outputs[i] != NULL; i++) { - if (is_laptop (screen, outputs[i])) - return outputs[i]; - } - - return NULL; -} - static GnomeRRRotation get_next_rotation (GnomeRRRotation allowed_rotations, GnomeRRRotation current_rotation) { @@ -1458,7 +1613,7 @@ handle_rotate_windows (GsdXrandrManager *mgr, gnome_rr_output_info_set_rotation (rotatable_output_info, next_rotation); - success = apply_configuration (mgr, current, timestamp, show_error); + success = apply_configuration (mgr, current, timestamp, show_error, TRUE); if (success) rotate_touchscreens (mgr, next_rotation); @@ -1471,129 +1626,58 @@ auto_configure_outputs (GsdXrandrManager *manager, guint32 timestamp) { GsdXrandrManagerPrivate *priv = manager->priv; GnomeRRConfig *config; - GnomeRROutputInfo **outputs; - int i; - GList *just_turned_on; - GList *l; - int x; - GError *error; - gboolean applicable; - - config = gnome_rr_config_new_current (priv->rw_screen, NULL); - - /* For outputs that are connected and on (i.e. they have a CRTC assigned - * to them, so they are getting a signal), we leave them as they are - * with their current modes. - * - * For other outputs, we will turn on connected-but-off outputs and turn - * off disconnected-but-on outputs. - * - * FIXME: If an output remained connected+on, it would be nice to ensure - * that the output's CRTCs still has a reasonable mode (think of - * changing one monitor for another with different capabilities). - */ - - just_turned_on = NULL; - outputs = gnome_rr_config_get_outputs (config); - - for (i = 0; outputs[i] != NULL; i++) { - GnomeRROutputInfo *output = outputs[i]; - - if (gnome_rr_output_info_is_connected (output) && !gnome_rr_output_info_is_active (output)) { - gnome_rr_output_info_set_active (output, TRUE); - gnome_rr_output_info_set_rotation (output, GNOME_RR_ROTATION_0); - just_turned_on = g_list_prepend (just_turned_on, GINT_TO_POINTER (i)); - } else if (!gnome_rr_output_info_is_connected (output) && gnome_rr_output_info_is_active (output)) - gnome_rr_output_info_set_active (output, FALSE); - } - - /* Now, lay out the outputs from left to right. Put first the outputs - * which remained on; put last the outputs that were newly turned on. - */ - - x = 0; - - /* First, outputs that remained on */ - - for (i = 0; outputs[i] != NULL; i++) { - GnomeRROutputInfo *output = outputs[i]; - - if (g_list_find (just_turned_on, GINT_TO_POINTER (i))) - continue; - - if (gnome_rr_output_info_is_active (output)) { - int width, height; - g_assert (gnome_rr_output_info_is_connected (output)); - - gnome_rr_output_info_get_geometry (output, NULL, NULL, &width, &height); - gnome_rr_output_info_set_geometry (output, x, 0, width, height); - x += width; - } - } - - /* Second, outputs that were newly-turned on */ - - for (l = just_turned_on; l; l = l->next) { - GnomeRROutputInfo *output; - int width; - i = GPOINTER_TO_INT (l->data); - output = outputs[i]; - - g_assert (gnome_rr_output_info_is_active (output) && gnome_rr_output_info_is_connected (output)); - - /* since the output was off, use its preferred width/height (it doesn't have a real width/height yet) */ - width = gnome_rr_output_info_get_preferred_width (output); - gnome_rr_output_info_set_geometry (output, x, 0, width, gnome_rr_output_info_get_preferred_height (output)); - - x += width; + config = make_xinerama_setup (manager, priv->rw_screen); + if (config) { + print_configuration (config, "auto-configure - xinerama mode"); + apply_configuration (manager, config, timestamp, TRUE, FALSE); + g_object_unref (config); + } else { + g_debug ("No applicable configuration found during auto-configure"); } +} - /* Check if we have a large enough framebuffer size. If not, turn off - * outputs from right to left until we reach a usable size. - */ - - just_turned_on = g_list_reverse (just_turned_on); /* now the outputs here are from right to left */ - - l = just_turned_on; - while (1) { - GnomeRROutputInfo *output; - gboolean is_bounds_error; - - error = NULL; - applicable = gnome_rr_config_applicable (config, priv->rw_screen, &error); +static void +use_stored_configuration_or_auto_configure_outputs (GsdXrandrManager *manager, guint32 timestamp) +{ + GsdXrandrManagerPrivate *priv = manager->priv; + char *intended_filename; + GError *error; + gboolean success; - if (applicable) - break; + intended_filename = gnome_rr_config_get_intended_filename (); - is_bounds_error = g_error_matches (error, GNOME_RR_ERROR, GNOME_RR_ERROR_BOUNDS_ERROR); - g_error_free (error); + error = NULL; + success = apply_configuration_from_filename (manager, intended_filename, TRUE, timestamp, &error); + g_free (intended_filename); - if (!is_bounds_error) - break; + if (!success) { + /* We don't bother checking the error type. + * + * Both G_FILE_ERROR_NOENT and + * GNOME_RR_ERROR_NO_MATCHING_CONFIG would mean, "there + * was no configuration to apply, or none that matched + * the current outputs", and in that case we need to run + * our fallback. + * + * Any other error means "we couldn't do the smart thing + * of using a previously- saved configuration, anyway, + * for some other reason. In that case, we also need to + * run our fallback to avoid leaving the user with a + * bogus configuration. + */ - if (l) { - i = GPOINTER_TO_INT (l->data); - l = l->next; + if (error) + g_error_free (error); - output = outputs[i]; - gnome_rr_output_info_set_active (output, FALSE); + if (timestamp != priv->last_config_timestamp || timestamp == GDK_CURRENT_TIME) { + priv->last_config_timestamp = timestamp; + auto_configure_outputs (manager, timestamp); + log_msg (" Automatically configured outputs\n"); } else - break; - } - - /* Apply the configuration! */ - - if (applicable) { - print_configuration (config, "auto configure"); - - apply_configuration (manager, config, timestamp, TRUE); - } else { - g_debug ("Not an applicable config"); - } - - g_list_free (just_turned_on); - g_object_unref (config); + log_msg (" Ignored autoconfiguration as old and new config timestamps are the same\n"); + } else + log_msg ("Applied stored configuration\n"); } static void @@ -1645,45 +1729,8 @@ on_randr_event (GnomeRRScreen *screen, gpointer data) * outputs in a sane way. */ - char *intended_filename; - GError *error; - gboolean success; - show_timestamps_dialog (manager, "need to deal with reconfiguration, as config > change"); - - intended_filename = gnome_rr_config_get_intended_filename (); - - error = NULL; - success = apply_configuration_from_filename (manager, intended_filename, TRUE, config_timestamp, &error); - g_free (intended_filename); - - if (!success) { - /* We don't bother checking the error type. - * - * Both G_FILE_ERROR_NOENT and - * GNOME_RR_ERROR_NO_MATCHING_CONFIG would mean, "there - * was no configuration to apply, or none that matched - * the current outputs", and in that case we need to run - * our fallback. - * - * Any other error means "we couldn't do the smart thing - * of using a previously- saved configuration, anyway, - * for some other reason. In that case, we also need to - * run our fallback to avoid leaving the user with a - * bogus configuration. - */ - - if (error) - g_error_free (error); - - if (config_timestamp != priv->last_config_timestamp) { - priv->last_config_timestamp = config_timestamp; - auto_configure_outputs (manager, config_timestamp); - log_msg (" Automatically configured outputs to deal with event\n"); - } else - log_msg (" Ignored event as old and new config timestamps are the same\n"); - } else - log_msg ("Applied stored configuration to deal with event\n"); + use_stored_configuration_or_auto_configure_outputs (manager, config_timestamp); } log_close (); @@ -1763,7 +1810,7 @@ apply_default_boot_configuration (GsdXrandrManager *mgr, guint32 timestamp) case GSD_XRANDR_BOOT_BEHAVIOUR_DO_NOTHING: return; case GSD_XRANDR_BOOT_BEHAVIOUR_CLONE: - config = make_clone_setup (screen); + config = make_clone_setup (mgr, screen); break; case GSD_XRANDR_BOOT_BEHAVIOUR_DOCK: config = make_other_setup (screen); @@ -1773,7 +1820,10 @@ apply_default_boot_configuration (GsdXrandrManager *mgr, guint32 timestamp) } if (config) { - apply_configuration (mgr, config, timestamp, TRUE); + /* We don't save the configuration (the "false" parameter to the following function) because we don't want to + * install a user-side setting when *here* we are using a system-default setting. + */ + apply_configuration (mgr, config, timestamp, TRUE, FALSE); g_object_unref (config); } } @@ -1852,6 +1902,55 @@ apply_default_configuration_from_file (GsdXrandrManager *manager, guint32 timest return result; } +static void +turn_off_laptop_display (GsdXrandrManager *manager, guint32 timestamp) +{ + GsdXrandrManagerPrivate *priv = manager->priv; + GnomeRRConfig *config; + + config = gnome_rr_config_new_current (priv->rw_screen, NULL); + + turn_off_laptop_display_in_configuration (priv->rw_screen, config); + + /* We don't turn the laptop's display off if it is the only display present. */ + if (!config_is_all_off (config)) { + /* We don't save the configuration (the "false" parameter to the following function) because we + * wouldn't want to restore a configuration with the laptop's display turned off, if at some + * point later the user booted his laptop with the lid open. + */ + apply_configuration (manager, config, timestamp, FALSE, FALSE); + } + + g_object_unref (config); +} + +static void +power_client_changed_cb (UpClient *client, gpointer data) +{ + GsdXrandrManager *manager = data; + GsdXrandrManagerPrivate *priv = manager->priv; + gboolean is_closed; + + is_closed = up_client_get_lid_is_closed (priv->upower_client); + + if (is_closed != priv->laptop_lid_is_closed) { + priv->laptop_lid_is_closed = is_closed; + + /* Refresh the RANDR state. The lid just got opened/closed, so we can afford to + * probe the outputs right now. It will also help the case where we can't detect + * hotplug/unplug, but the fact that the lid's state changed lets us know that the + * user probably did something interesting. + */ + + gnome_rr_screen_refresh (priv->rw_screen, NULL); /* NULL-GError */ + + if (is_closed) + turn_off_laptop_display (manager, GDK_CURRENT_TIME); /* sucks not to have a timestamp for the notification */ + else + use_stored_configuration_or_auto_configure_outputs (manager, GDK_CURRENT_TIME); + } +} + gboolean gsd_xrandr_manager_start (GsdXrandrManager *manager, GError **error) @@ -1862,7 +1961,7 @@ gsd_xrandr_manager_start (GsdXrandrManager *manager, log_open (); log_msg ("------------------------------------------------------------\nSTARTING XRANDR PLUGIN\n"); - manager->priv->rw_screen = gnome_settings_session_get_screen (error); + manager->priv->rw_screen = gnome_rr_screen_new (gdk_screen_get_default (), error); if (manager->priv->rw_screen == NULL) { log_msg ("Could not initialize the RANDR plugin%s%s\n", @@ -1874,6 +1973,11 @@ gsd_xrandr_manager_start (GsdXrandrManager *manager, g_signal_connect (manager->priv->rw_screen, "changed", G_CALLBACK (on_randr_event), manager); + manager->priv->upower_client = up_client_new (); + manager->priv->laptop_lid_is_closed = up_client_get_lid_is_closed (manager->priv->upower_client); + g_signal_connect (manager->priv->upower_client, "changed", + G_CALLBACK (power_client_changed_cb), manager); + log_msg ("State of screen at startup:\n"); log_screen (manager->priv->rw_screen); @@ -1918,6 +2022,11 @@ gsd_xrandr_manager_stop (GsdXrandrManager *manager) manager->priv->rw_screen = NULL; } + if (manager->priv->upower_client != NULL) { + g_object_unref (manager->priv->upower_client); + manager->priv->upower_client = NULL; + } + if (manager->priv->introspection_data) { g_dbus_node_info_unref (manager->priv->introspection_data); manager->priv->introspection_data = NULL; @@ -1983,20 +2092,15 @@ gsd_xrandr_manager_finalize (GObject *object) } static void -handle_method_call (GDBusConnection *connection, - const gchar *sender, - const gchar *object_path, - const gchar *interface_name, - const gchar *method_name, - GVariant *parameters, - GDBusMethodInvocation *invocation, - gpointer user_data) +handle_method_call_xrandr_2 (GsdXrandrManager *manager, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation) { - GsdXrandrManager *manager = (GsdXrandrManager *) user_data; gint64 timestamp; GError *error = NULL; - g_debug ("Calling method '%s' for XRandR", method_name); + g_debug ("Calling method '%s' for org.gnome.SettingsDaemon.XRANDR_2", method_name); if (g_strcmp0 (method_name, "ApplyConfiguration") == 0) { gint64 parent_window_id; @@ -2024,6 +2128,26 @@ handle_method_call (GDBusConnection *connection, } } +static void +handle_method_call (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + GsdXrandrManager *manager = (GsdXrandrManager *) user_data; + + g_debug ("Handling method call %s.%s", interface_name, method_name); + + if (g_strcmp0 (interface_name, "org.gnome.SettingsDaemon.XRANDR_2") == 0) + handle_method_call_xrandr_2 (manager, method_name, parameters, invocation); + else + g_warning ("unknown interface: %s", interface_name); +} + static const GDBusInterfaceVTable interface_vtable = { @@ -2039,6 +2163,8 @@ on_bus_gotten (GObject *source_object, { GDBusConnection *connection; GError *error = NULL; + GDBusInterfaceInfo **infos; + int i; if (manager->priv->bus_cancellable == NULL || g_cancellable_is_cancelled (manager->priv->bus_cancellable)) { @@ -2054,13 +2180,16 @@ on_bus_gotten (GObject *source_object, } manager->priv->connection = connection; - g_dbus_connection_register_object (connection, - GSD_XRANDR_DBUS_PATH, - manager->priv->introspection_data->interfaces[0], - &interface_vtable, - manager, - NULL, - NULL); + infos = manager->priv->introspection_data->interfaces; + for (i = 0; infos[i] != NULL; i++) { + g_dbus_connection_register_object (connection, + GSD_XRANDR_DBUS_PATH, + infos[i], + &interface_vtable, + manager, + NULL, + NULL); + } } static void |