[gnome-settings-daemon] power and media-keys: Use logind for suspending and rebooting the system
- From: Bastien Nocera <hadess src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-settings-daemon] power and media-keys: Use logind for suspending and rebooting the system
- Date: Mon, 22 Oct 2012 08:51:08 +0000 (UTC)
commit 6defe42c31b18ad8dbb2fff3869b0fccbd821e97
Author: Richard Hughes <richard hughsie com>
Date: Fri Sep 21 11:56:53 2012 +0100
power and media-keys: Use logind for suspending and rebooting the system
Use the new logind features to suspend and resume but making sure we opt out
of logind handling the sleep and power keys, and also inhibiting for lid close
auto-suspend if there is an external monitor connected.
Also use a delay inihibit for logind so that we can do actions on suspend like
blanking the screen using the screensaver and also poking the screensaver on
resume.
https://bugzilla.gnome.org/show_bug.cgi?id=680689
plugins/common/Makefile.am | 4 +-
plugins/common/gsd-power-helper.c | 203 --------
plugins/common/gsd-power-helper.h | 35 --
plugins/media-keys/gsd-media-keys-manager.c | 156 +++++--
plugins/power/gsd-power-manager.c | 697 ++++++++++++++++++---------
5 files changed, 594 insertions(+), 501 deletions(-)
---
diff --git a/plugins/common/Makefile.am b/plugins/common/Makefile.am
index 7e50db4..b0e907c 100644
--- a/plugins/common/Makefile.am
+++ b/plugins/common/Makefile.am
@@ -6,9 +6,7 @@ libcommon_la_SOURCES = \
gsd-keygrab.c \
gsd-keygrab.h \
gsd-input-helper.c \
- gsd-input-helper.h \
- gsd-power-helper.c \
- gsd-power-helper.h
+ gsd-input-helper.h
libcommon_la_CPPFLAGS = \
$(AM_CPPFLAGS)
diff --git a/plugins/media-keys/gsd-media-keys-manager.c b/plugins/media-keys/gsd-media-keys-manager.c
index 7e38e57..c1bfe8f 100644
--- a/plugins/media-keys/gsd-media-keys-manager.c
+++ b/plugins/media-keys/gsd-media-keys-manager.c
@@ -39,6 +39,7 @@
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#include <gio/gdesktopappinfo.h>
+#include <gio/gunixfdlist.h>
#ifdef HAVE_GUDEV
#include <gudev/gudev.h>
@@ -52,7 +53,6 @@
#include "shortcuts-list.h"
#include "gsd-osd-window.h"
#include "gsd-input-helper.h"
-#include "gsd-power-helper.h"
#include "gsd-enums.h"
#include <canberra.h>
@@ -102,6 +102,10 @@ static const gchar introspection_xml[] =
#define KEY_CURRENT_INPUT_SOURCE "current"
#define KEY_INPUT_SOURCES "sources"
+#define SYSTEMD_DBUS_NAME "org.freedesktop.login1"
+#define SYSTEMD_DBUS_PATH "/org/freedesktop/login1"
+#define SYSTEMD_DBUS_INTERFACE "org.freedesktop.login1.Manager"
+
#define GSD_MEDIA_KEYS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_MEDIA_KEYS_MANAGER, GsdMediaKeysManagerPrivate))
typedef struct {
@@ -145,10 +149,13 @@ struct GsdMediaKeysManagerPrivate
/* Power stuff */
GSettings *power_settings;
- GDBusProxy *upower_proxy;
GDBusProxy *power_screen_proxy;
GDBusProxy *power_keyboard_proxy;
+ /* systemd stuff */
+ GDBusProxy *logind_proxy;
+ gint inhibit_keys_fd;
+
/* Multihead stuff */
GdkScreen *current_screen;
GSList *screens;
@@ -1608,6 +1615,38 @@ do_toggle_contrast_action (GsdMediaKeysManager *manager)
}
static void
+power_action_suspend (GsdMediaKeysManager *manager)
+{
+#ifndef HAVE_SYSTEMD
+ g_warning ("no systemd support");
+ return;
+#endif
+ g_dbus_proxy_call (manager->priv->logind_proxy,
+ "Suspend",
+ g_variant_new ("(b)", TRUE),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ manager->priv->bus_cancellable,
+ NULL, NULL);
+}
+
+static void
+power_action_hibernate (GsdMediaKeysManager *manager)
+{
+#ifndef HAVE_SYSTEMD
+ g_warning ("no systemd support");
+ return;
+#endif
+ g_dbus_proxy_call (manager->priv->logind_proxy,
+ "Hibernate",
+ g_variant_new ("(b)", TRUE),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ manager->priv->bus_cancellable,
+ NULL, NULL);
+}
+
+static void
do_config_power_action (GsdMediaKeysManager *manager,
const gchar *config_key)
{
@@ -1617,14 +1656,14 @@ do_config_power_action (GsdMediaKeysManager *manager,
config_key);
switch (action_type) {
case GSD_POWER_ACTION_SUSPEND:
- gsd_power_suspend (manager->priv->upower_proxy);
+ power_action_suspend (manager);
break;
case GSD_POWER_ACTION_INTERACTIVE:
case GSD_POWER_ACTION_SHUTDOWN:
gnome_session_shutdown (manager);
break;
case GSD_POWER_ACTION_HIBERNATE:
- gsd_power_hibernate (manager->priv->upower_proxy);
+ power_action_hibernate (manager);
break;
case GSD_POWER_ACTION_BLANK:
case GSD_POWER_ACTION_NOTHING:
@@ -2238,6 +2277,7 @@ gsd_media_keys_manager_stop (GsdMediaKeysManager *manager)
}
#endif /* HAVE_GUDEV */
+ g_clear_object (&priv->logind_proxy);
if (priv->settings) {
g_object_unref (priv->settings);
priv->settings = NULL;
@@ -2258,11 +2298,6 @@ gsd_media_keys_manager_stop (GsdMediaKeysManager *manager)
priv->power_keyboard_proxy = NULL;
}
- if (priv->upower_proxy) {
- g_object_unref (priv->upower_proxy);
- priv->upower_proxy = NULL;
- }
-
if (priv->cancellable != NULL) {
g_cancellable_cancel (priv->cancellable);
g_object_unref (priv->cancellable);
@@ -2353,9 +2388,85 @@ gsd_media_keys_manager_class_init (GsdMediaKeysManagerClass *klass)
}
static void
+inhibit_done (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GDBusProxy *proxy = G_DBUS_PROXY (source);
+ GsdMediaKeysManager *manager = GSD_MEDIA_KEYS_MANAGER (user_data);
+ GError *error = NULL;
+ GVariant *res;
+ GUnixFDList *fd_list = NULL;
+ gint idx;
+
+ res = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, &fd_list, result, &error);
+ if (res == NULL) {
+ g_warning ("Unable to inhibit keypresses: %s", error->message);
+ g_error_free (error);
+ } else {
+ g_variant_get (res, "(h)", &idx);
+ manager->priv->inhibit_keys_fd = g_unix_fd_list_get (fd_list, idx, &error);
+ if (manager->priv->inhibit_keys_fd == -1) {
+ g_warning ("Failed to receive system inhibitor fd: %s", error->message);
+ g_error_free (error);
+ }
+ g_debug ("System inhibitor fd is %d", manager->priv->inhibit_keys_fd);
+ g_object_unref (fd_list);
+ g_variant_unref (res);
+ }
+}
+
+static void
gsd_media_keys_manager_init (GsdMediaKeysManager *manager)
{
+ GError *error;
+ GDBusConnection *bus;
+
+ error = NULL;
manager->priv = GSD_MEDIA_KEYS_MANAGER_GET_PRIVATE (manager);
+
+ bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
+ if (bus == NULL) {
+ g_warning ("Failed to connect to system bus: %s",
+ error->message);
+ g_error_free (error);
+ return;
+ }
+
+ manager->priv->logind_proxy =
+ g_dbus_proxy_new_sync (bus,
+ 0,
+ NULL,
+ SYSTEMD_DBUS_NAME,
+ SYSTEMD_DBUS_PATH,
+ SYSTEMD_DBUS_INTERFACE,
+ NULL,
+ &error);
+
+ if (manager->priv->logind_proxy == NULL) {
+ g_warning ("Failed to connect to systemd: %s",
+ error->message);
+ g_error_free (error);
+ }
+
+ g_object_unref (bus);
+
+ g_debug ("Adding system inhibitors for power keys");
+ manager->priv->inhibit_keys_fd = -1;
+ g_dbus_proxy_call_with_unix_fd_list (manager->priv->logind_proxy,
+ "Inhibit",
+ g_variant_new ("(ssss)",
+ "handle-power-key:handle-suspend-key:handle-hibernate-key",
+ g_get_user_name (),
+ "GNOME handling keypresses",
+ "block"),
+ 0,
+ G_MAXINT,
+ NULL,
+ NULL,
+ inhibit_done,
+ manager);
+
}
static void
@@ -2372,6 +2483,8 @@ gsd_media_keys_manager_finalize (GObject *object)
if (media_keys_manager->priv->start_idle_id != 0)
g_source_remove (media_keys_manager->priv->start_idle_id);
+ if (media_keys_manager->priv->inhibit_keys_fd != -1)
+ close (media_keys_manager->priv->inhibit_keys_fd);
G_OBJECT_CLASS (gsd_media_keys_manager_parent_class)->finalize (object);
}
@@ -2391,21 +2504,6 @@ xrandr_ready_cb (GObject *source_object,
}
static void
-upower_ready_cb (GObject *source_object,
- GAsyncResult *res,
- GsdMediaKeysManager *manager)
-{
- GError *error = NULL;
-
- manager->priv->upower_proxy = g_dbus_proxy_new_finish (res, &error);
- if (manager->priv->upower_proxy == NULL) {
- g_warning ("Failed to get proxy for upower: %s",
- error->message);
- g_error_free (error);
- }
-}
-
-static void
power_screen_ready_cb (GObject *source_object,
GAsyncResult *res,
GsdMediaKeysManager *manager)
@@ -2507,16 +2605,6 @@ register_manager (GsdMediaKeysManager *manager)
manager->priv->bus_cancellable,
(GAsyncReadyCallback) on_bus_gotten,
manager);
-
- g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
- G_DBUS_PROXY_FLAGS_NONE,
- NULL,
- "org.freedesktop.UPower",
- "/org/freedesktop/UPower",
- "org.freedesktop.UPower",
- NULL,
- (GAsyncReadyCallback) upower_ready_cb,
- manager);
}
GsdMediaKeysManager *
diff --git a/plugins/power/gsd-power-manager.c b/plugins/power/gsd-power-manager.c
index ad85eba..c0b1cfd 100644
--- a/plugins/power/gsd-power-manager.c
+++ b/plugins/power/gsd-power-manager.c
@@ -1,7 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann jhu edu>
- * Copyright (C) 2011 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2011-2012 Richard Hughes <richard hughsie com>
* Copyright (C) 2011 Ritesh Khadgaray <khadgaray gmail com>
*
* This program is free software; you can redistribute it and/or modify
@@ -32,6 +32,7 @@
#include <libupower-glib/upower.h>
#include <libnotify/notify.h>
#include <canberra-gtk.h>
+#include <gio/gunixfdlist.h>
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include <libgnome-desktop/gnome-rr.h>
@@ -43,7 +44,6 @@
#include "gnome-settings-session.h"
#include "gsd-enums.h"
#include "gsd-power-manager.h"
-#include "gsd-power-helper.h"
#define GNOME_SESSION_DBUS_NAME "org.gnome.SessionManager"
#define GNOME_SESSION_DBUS_PATH_PRESENCE "/org/gnome/SessionManager/Presence"
@@ -76,6 +76,10 @@
#define GSD_POWER_MANAGER_RECALL_DELAY 30 /* seconds */
#define GSD_POWER_MANAGER_LID_CLOSE_SAFETY_TIMEOUT 30 /* seconds */
+#define SYSTEMD_DBUS_NAME "org.freedesktop.login1"
+#define SYSTEMD_DBUS_PATH "/org/freedesktop/login1"
+#define SYSTEMD_DBUS_INTERFACE "org.freedesktop.login1.Manager"
+
/* Keep this in sync with gnome-shell */
#define SCREENSAVER_FADE_TIME 10 /* seconds */
@@ -191,14 +195,20 @@ struct GsdPowerManagerPrivate
ca_context *canberra_context;
ca_proplist *critical_alert_loop_props;
guint32 critical_alert_timeout_id;
- GDBusProxy *screensaver_proxy;
GDBusProxy *session_proxy;
GDBusProxy *session_presence_proxy;
GpmIdletime *idletime;
GsdPowerIdleMode current_idle_mode;
- guint lid_close_safety_timer_id;
GtkStatusIcon *status_icon;
guint xscreensaver_watchdog_timer_id;
+
+ /* systemd stuff */
+ GDBusProxy *logind_proxy;
+ gint inhibit_lid_switch_fd;
+ gboolean inhibit_lid_switch_taken;
+ gint inhibit_suspend_fd;
+ gboolean inhibit_suspend_taken;
+ guint inhibit_lid_switch_timer_id;
};
enum {
@@ -215,8 +225,8 @@ static GIcon *engine_get_icon (GsdPowerManager *manager);
static gchar *engine_get_summary (GsdPowerManager *manager);
static void do_power_action_type (GsdPowerManager *manager, GsdPowerActionType action_type);
static void do_lid_closed_action (GsdPowerManager *manager);
-static void lock_screensaver (GsdPowerManager *manager);
-static void kill_lid_close_safety_timer (GsdPowerManager *manager);
+static void uninhibit_lid_switch (GsdPowerManager *manager);
+static gboolean external_monitor_is_connected (GnomeRRScreen *screen);
G_DEFINE_TYPE (GsdPowerManager, gsd_power_manager, G_TYPE_OBJECT)
@@ -2028,6 +2038,57 @@ gnome_session_shutdown (GsdPowerManager *manager)
}
static void
+action_poweroff (GsdPowerManager *manager)
+{
+ if (manager->priv->logind_proxy == NULL) {
+ g_warning ("no systemd support");
+ return;
+ }
+ g_dbus_proxy_call (manager->priv->logind_proxy,
+ "PowerOff",
+ g_variant_new ("(b)", FALSE),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+action_suspend (GsdPowerManager *manager)
+{
+ if (manager->priv->logind_proxy == NULL) {
+ g_warning ("no systemd support");
+ return;
+ }
+ g_dbus_proxy_call (manager->priv->logind_proxy,
+ "Suspend",
+ g_variant_new ("(b)", FALSE),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+action_hibernate (GsdPowerManager *manager)
+{
+ if (manager->priv->logind_proxy == NULL) {
+ g_warning ("no systemd support");
+ return;
+ }
+ g_dbus_proxy_call (manager->priv->logind_proxy,
+ "Hibernate",
+ g_variant_new ("(b)", FALSE),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
do_power_action_type (GsdPowerManager *manager,
GsdPowerActionType action_type)
{
@@ -2036,19 +2097,19 @@ do_power_action_type (GsdPowerManager *manager,
switch (action_type) {
case GSD_POWER_ACTION_SUSPEND:
- gsd_power_suspend (manager->priv->upower_proxy);
+ action_suspend (manager);
break;
case GSD_POWER_ACTION_INTERACTIVE:
gnome_session_shutdown (manager);
break;
case GSD_POWER_ACTION_HIBERNATE:
- gsd_power_hibernate (manager->priv->upower_proxy);
+ action_hibernate (manager);
break;
case GSD_POWER_ACTION_SHUTDOWN:
/* this is only used on critically low battery where
* hibernate is not available and is marginally better
* than just powering down the computer mid-write */
- gsd_power_poweroff ();
+ action_poweroff (manager);
break;
case GSD_POWER_ACTION_BLANK:
ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen,
@@ -2120,85 +2181,20 @@ upower_kbd_toggle (GsdPowerManager *manager,
return ret;
}
-static void
-do_lid_open_action (GsdPowerManager *manager)
-{
- gboolean ret;
- GError *error = NULL;
-
- /* play a sound, using sounds from the naming spec */
- ca_context_play (manager->priv->canberra_context, 0,
- CA_PROP_EVENT_ID, "lid-open",
- /* TRANSLATORS: this is the sound description */
- CA_PROP_EVENT_DESCRIPTION, _("Lid has been opened"),
- NULL);
-
- /* ensure we turn the panel back on after lid open */
- ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen,
- GNOME_RR_DPMS_ON,
- &error);
- if (!ret) {
- g_warning ("failed to turn the panel on after lid open: %s",
- error->message);
- g_clear_error (&error);
- }
-
- /* only toggle keyboard if present and already toggled off */
- if (manager->priv->upower_kdb_proxy != NULL &&
- manager->priv->kbd_brightness_old != -1) {
- ret = upower_kbd_toggle (manager, &error);
- if (!ret) {
- g_warning ("failed to turn the kbd backlight on: %s",
- error->message);
- g_error_free (error);
- }
- }
-
- kill_lid_close_safety_timer (manager);
-}
-
-static gboolean
-is_on (GnomeRROutput *output)
-{
- GnomeRRCrtc *crtc;
-
- crtc = gnome_rr_output_get_crtc (output);
- if (!crtc)
- return FALSE;
- return gnome_rr_crtc_get_current_mode (crtc) != NULL;
-}
-
static gboolean
-non_laptop_outputs_are_all_off (GnomeRRScreen *screen)
+inhibit_lid_switch_timer_cb (GsdPowerManager *manager)
{
- GnomeRROutput **outputs;
- int i;
-
- outputs = gnome_rr_screen_list_outputs (screen);
- for (i = 0; outputs[i] != NULL; i++) {
- if (gnome_rr_output_is_laptop (outputs[i]))
- continue;
-
- if (is_on (outputs[i]))
- return FALSE;
+ if (!external_monitor_is_connected (manager->priv->x11_screen) ||
+ g_settings_get_boolean (manager->priv->settings,
+ "lid-close-suspend-with-external-monitor")) {
+ g_debug ("no external monitors for a while; uninhibiting lid close");
+ uninhibit_lid_switch (manager);
+ manager->priv->inhibit_lid_switch_timer_id = 0;
+ return G_SOURCE_REMOVE;
}
- return TRUE;
-}
-
-/* Timeout callback used to check conditions when the laptop's lid is closed but
- * the machine is not suspended yet. We try to suspend again, so that the laptop
- * won't overheat if placed in a backpack.
- */
-static gboolean
-lid_close_safety_timer_cb (GsdPowerManager *manager)
-{
- manager->priv->lid_close_safety_timer_id = 0;
-
- g_debug ("lid has been closed for a while; trying to suspend again");
- do_lid_closed_action (manager);
-
- return FALSE;
+ g_debug ("external monitor still there; trying again later");
+ return G_SOURCE_CONTINUE;
}
/* Sets up a timer to be triggered some seconds after closing the laptop lid
@@ -2206,82 +2202,73 @@ lid_close_safety_timer_cb (GsdPowerManager *manager)
* again in the timeout handler to see if we can suspend then.
*/
static void
-setup_lid_close_safety_timer (GsdPowerManager *manager)
+setup_inhibit_lid_switch_timer (GsdPowerManager *manager)
{
- if (manager->priv->lid_close_safety_timer_id != 0)
+ if (manager->priv->inhibit_lid_switch_timer_id != 0) {
+ g_debug ("lid close safety timer already set up");
return;
+ }
- manager->priv->lid_close_safety_timer_id = g_timeout_add_seconds (GSD_POWER_MANAGER_LID_CLOSE_SAFETY_TIMEOUT,
- (GSourceFunc) lid_close_safety_timer_cb,
+ g_debug ("setting up lid close safety timer");
+
+ manager->priv->inhibit_lid_switch_timer_id = g_timeout_add_seconds (GSD_POWER_MANAGER_LID_CLOSE_SAFETY_TIMEOUT,
+ (GSourceFunc) inhibit_lid_switch_timer_cb,
manager);
- g_source_set_name_by_id (manager->priv->lid_close_safety_timer_id, "[GsdPowerManager] lid close safety timer");
+ g_source_set_name_by_id (manager->priv->inhibit_lid_switch_timer_id, "[GsdPowerManager] lid close safety timer");
}
static void
-kill_lid_close_safety_timer (GsdPowerManager *manager)
+restart_inhibit_lid_switch_timer (GsdPowerManager *manager)
{
- if (manager->priv->lid_close_safety_timer_id != 0) {
- g_source_remove (manager->priv->lid_close_safety_timer_id);
- manager->priv->lid_close_safety_timer_id = 0;
+ if (manager->priv->inhibit_lid_switch_timer_id != 0) {
+ g_debug ("restarting lid close safety timer");
+ g_source_remove (manager->priv->inhibit_lid_switch_timer_id);
+ manager->priv->inhibit_lid_switch_timer_id = 0;
+ setup_inhibit_lid_switch_timer (manager);
}
}
static void
-suspend_with_lid_closed (GsdPowerManager *manager)
+do_lid_open_action (GsdPowerManager *manager)
{
gboolean ret;
GError *error = NULL;
- GsdPowerActionType action_type;
-
- /* maybe lock the screen if the lid is closed */
- lock_screensaver (manager);
-
- /* we have different settings depending on AC state */
- if (up_client_get_on_battery (manager->priv->up_client)) {
- action_type = g_settings_get_enum (manager->priv->settings,
- "lid-close-battery-action");
- } else {
- action_type = g_settings_get_enum (manager->priv->settings,
- "lid-close-ac-action");
- }
- /* check we won't melt when the lid is closed */
- if (action_type != GSD_POWER_ACTION_SUSPEND &&
- action_type != GSD_POWER_ACTION_HIBERNATE) {
- if (up_client_get_lid_force_sleep (manager->priv->up_client)) {
- g_warning ("to prevent damage, now forcing suspend");
- do_power_action_type (manager, GSD_POWER_ACTION_SUSPEND);
- return;
- }
- }
+ /* play a sound, using sounds from the naming spec */
+ ca_context_play (manager->priv->canberra_context, 0,
+ CA_PROP_EVENT_ID, "lid-open",
+ /* TRANSLATORS: this is the sound description */
+ CA_PROP_EVENT_DESCRIPTION, _("Lid has been opened"),
+ NULL);
- /* ensure we turn the panel back on after resume */
+ /* ensure we turn the panel back on after lid open */
ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen,
- GNOME_RR_DPMS_OFF,
+ GNOME_RR_DPMS_ON,
&error);
if (!ret) {
- g_warning ("failed to turn the panel off after lid close: %s",
+ g_warning ("failed to turn the panel on after lid open: %s",
error->message);
g_clear_error (&error);
}
- /* only toggle keyboard if present and not already toggled */
- if (manager->priv->upower_kdb_proxy &&
- manager->priv->kbd_brightness_old == -1) {
+ /* only toggle keyboard if present and already toggled off */
+ if (manager->priv->upower_kdb_proxy != NULL &&
+ manager->priv->kbd_brightness_old != -1) {
ret = upower_kbd_toggle (manager, &error);
if (!ret) {
- g_warning ("failed to turn the kbd backlight off: %s",
+ g_warning ("failed to turn the kbd backlight on: %s",
error->message);
g_error_free (error);
}
}
-
- do_power_action_type (manager, action_type);
}
static void
do_lid_closed_action (GsdPowerManager *manager)
{
+ gboolean ret;
+ GError *error = NULL;
+
/* play a sound, using sounds from the naming spec */
ca_context_play (manager->priv->canberra_context, 0,
CA_PROP_EVENT_ID, "lid-close",
@@ -2289,21 +2276,22 @@ do_lid_closed_action (GsdPowerManager *manager)
CA_PROP_EVENT_DESCRIPTION, _("Lid has been closed"),
NULL);
+ /* turn the panel off if the lid is closed (mainly for Dells...) */
+ ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen,
+ GNOME_RR_DPMS_OFF,
+ &error);
+ if (!ret) {
+ g_warning ("failed to turn the panel off after lid close: %s",
+ error->message);
+ g_error_free (error);
+ }
+
/* refresh RANDR so we get an accurate view of what monitors are plugged in when the lid is closed */
gnome_rr_screen_refresh (manager->priv->x11_screen, NULL); /* NULL-GError */
- /* perform policy action */
- if (g_settings_get_boolean (manager->priv->settings, "lid-close-suspend-with-external-monitor")
- || non_laptop_outputs_are_all_off (manager->priv->x11_screen)) {
- g_debug ("lid is closed; suspending or hibernating");
- suspend_with_lid_closed (manager);
- } else {
- g_debug ("lid is closed; not suspending nor hibernating since some external monitor outputs are still active");
- setup_lid_close_safety_timer (manager);
- }
+ restart_inhibit_lid_switch_timer (manager);
}
-
static void
up_client_changed_cb (UpClient *client, GsdPowerManager *manager)
{
@@ -2323,6 +2311,7 @@ up_client_changed_cb (UpClient *client, GsdPowerManager *manager)
if (manager->priv->lid_is_closed == tmp)
return;
manager->priv->lid_is_closed = tmp;
+ g_debug ("up changed: lid is now %s", tmp ? "closed" : "open");
/* fake a keypress */
if (tmp)
@@ -3274,30 +3263,6 @@ gsd_power_manager_class_init (GsdPowerManagerClass *klass)
}
static void
-sleep_cb_screensaver_proxy_ready_cb (GObject *source_object,
- GAsyncResult *res,
- gpointer user_data)
-{
- GError *error = NULL;
- GsdPowerManager *manager = GSD_POWER_MANAGER (user_data);
-
- manager->priv->screensaver_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
- if (manager->priv->screensaver_proxy == NULL) {
- g_warning ("Could not connect to gnome-screensaver: %s",
- error->message);
- g_error_free (error);
- return;
- }
-
- /* Finish the upower_notify_sleep_cb() call by locking the screen */
- g_debug ("gnome-screensaver activated, doing gnome-screensaver lock");
- g_dbus_proxy_call (manager->priv->screensaver_proxy,
- "Lock",
- NULL, G_DBUS_CALL_FLAGS_NONE, -1,
- NULL, NULL, NULL);
-}
-
-static void
idle_dbus_signal_cb (GDBusProxy *proxy,
const gchar *sender_name,
const gchar *signal_name,
@@ -3430,75 +3395,38 @@ out:
}
static void
-lock_screensaver (GsdPowerManager *manager)
+lock_screensaver (GsdPowerManager *manager,
+ GSourceFunc done_cb)
{
gboolean do_lock;
do_lock = g_settings_get_boolean (manager->priv->settings_screensaver,
"lock-enabled");
- if (!do_lock)
+ if (!do_lock && done_cb) {
+ done_cb (manager);
return;
-
- if (manager->priv->screensaver_proxy != NULL) {
- g_debug ("doing gnome-screensaver lock");
- g_dbus_proxy_call (manager->priv->screensaver_proxy,
- "Lock",
- NULL, G_DBUS_CALL_FLAGS_NONE, -1,
- NULL, NULL, NULL);
- } else {
- /* connect to the screensaver first */
- g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
- G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
- NULL,
- GS_DBUS_NAME,
- GS_DBUS_PATH,
- GS_DBUS_INTERFACE,
- NULL,
- sleep_cb_screensaver_proxy_ready_cb,
- manager);
- }
-}
-
-static void
-upower_notify_sleep_cb (UpClient *client,
- UpSleepKind sleep_kind,
- GsdPowerManager *manager)
-{
- lock_screensaver (manager);
-}
-
-static void
-upower_notify_resume_cb (UpClient *client,
- UpSleepKind sleep_kind,
- GsdPowerManager *manager)
-{
- gboolean ret;
- GError *error = NULL;
-
- /* this displays the unlock dialogue so the user doesn't have
- * to move the mouse or press any key before the window comes up */
- if (manager->priv->screensaver_proxy != NULL) {
- g_dbus_proxy_call (manager->priv->screensaver_proxy,
- "SimulateUserActivity",
- NULL,
- G_DBUS_CALL_FLAGS_NONE,
- -1, NULL, NULL, NULL);
}
- /* close existing notifications on resume, the system power
- * state is probably different now */
- notify_close_if_showing (manager->priv->notification_low);
- notify_close_if_showing (manager->priv->notification_discharging);
-
- /* ensure we turn the panel back on after resume */
- ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen,
- GNOME_RR_DPMS_ON,
- &error);
- if (!ret) {
- g_warning ("failed to turn the panel on after resume: %s",
- error->message);
- g_error_free (error);
- }
+ g_dbus_connection_call (manager->priv->connection,
+ GS_DBUS_NAME,
+ GS_DBUS_PATH,
+ GS_DBUS_INTERFACE,
+ "Lock",
+ NULL, NULL,
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, NULL, NULL);
+
+ /* Wait until gnome-shell shield animation is done
+ *
+ * FIXME: the shell should mark the lock as active
+ * when the shield is down, then we could wait for
+ * that. This would also fix the problem that we wait
+ * needlessly when the shell has already locked the
+ * screen because it is initiating the suspend.
+ *
+ * https://bugzilla.gnome.org/show_bug.cgi?id=685053
+ */
+ g_timeout_add (500, done_cb, manager);
}
static void
@@ -3657,6 +3585,287 @@ disable_builtin_screensaver (gpointer unused)
return TRUE;
}
+static void
+inhibit_lid_switch_done (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GDBusProxy *proxy = G_DBUS_PROXY (source);
+ GsdPowerManager *manager = GSD_POWER_MANAGER (user_data);
+ GError *error = NULL;
+ GVariant *res;
+ GUnixFDList *fd_list = NULL;
+ gint idx;
+
+ res = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, &fd_list, result, &error);
+ if (res == NULL) {
+ g_warning ("Unable to inhibit lid switch: %s", error->message);
+ g_error_free (error);
+ } else {
+ g_variant_get (res, "(h)", &idx);
+ manager->priv->inhibit_lid_switch_fd = g_unix_fd_list_get (fd_list, idx, &error);
+ if (manager->priv->inhibit_lid_switch_fd == -1) {
+ g_warning ("Failed to receive system inhibitor fd: %s", error->message);
+ g_error_free (error);
+ }
+ g_debug ("System inhibitor fd is %d", manager->priv->inhibit_lid_switch_fd);
+ g_object_unref (fd_list);
+ g_variant_unref (res);
+ }
+}
+
+static void
+inhibit_lid_switch (GsdPowerManager *manager)
+{
+ GVariant *params;
+
+ if (manager->priv->inhibit_lid_switch_taken) {
+ g_debug ("already inhibited lid-switch");
+ return;
+ }
+ g_debug ("Adding lid switch system inhibitor");
+ manager->priv->inhibit_lid_switch_taken = TRUE;
+
+ params = g_variant_new ("(ssss)",
+ "handle-lid-switch",
+ g_get_user_name (),
+ "Multiple displays attached",
+ "block");
+ g_dbus_proxy_call_with_unix_fd_list (manager->priv->logind_proxy,
+ "Inhibit",
+ params,
+ 0,
+ G_MAXINT,
+ NULL,
+ NULL,
+ inhibit_lid_switch_done,
+ manager);
+}
+
+static void
+uninhibit_lid_switch (GsdPowerManager *manager)
+{
+ if (manager->priv->inhibit_lid_switch_fd == -1) {
+ g_debug ("no lid-switch inhibitor");
+ return;
+ }
+ g_debug ("Removing lid switch system inhibitor");
+ close (manager->priv->inhibit_lid_switch_fd);
+ manager->priv->inhibit_lid_switch_fd = -1;
+ manager->priv->inhibit_lid_switch_taken = FALSE;
+}
+
+static void
+inhibit_suspend_done (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GDBusProxy *proxy = G_DBUS_PROXY (source);
+ GsdPowerManager *manager = GSD_POWER_MANAGER (user_data);
+ GError *error = NULL;
+ GVariant *res;
+ GUnixFDList *fd_list = NULL;
+ gint idx;
+
+ res = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, &fd_list, result, &error);
+ if (res == NULL) {
+ g_warning ("Unable to inhibit suspend: %s", error->message);
+ g_error_free (error);
+ } else {
+ g_variant_get (res, "(h)", &idx);
+ manager->priv->inhibit_suspend_fd = g_unix_fd_list_get (fd_list, idx, &error);
+ if (manager->priv->inhibit_suspend_fd == -1) {
+ g_warning ("Failed to receive system inhibitor fd: %s", error->message);
+ g_error_free (error);
+ }
+ g_debug ("System inhibitor fd is %d", manager->priv->inhibit_suspend_fd);
+ g_object_unref (fd_list);
+ g_variant_unref (res);
+ }
+}
+
+/* We take a delay inhibitor here, which causes logind to send a
+ * PrepareToSleep signal, which gives us a chance to lock the screen
+ * and do some other preparations.
+ */
+static void
+inhibit_suspend (GsdPowerManager *manager)
+{
+ if (manager->priv->inhibit_suspend_taken) {
+ g_debug ("already inhibited lid-switch");
+ return;
+ }
+ g_debug ("Adding suspend delay inhibitor");
+ manager->priv->inhibit_suspend_taken = TRUE;
+ g_dbus_proxy_call_with_unix_fd_list (manager->priv->logind_proxy,
+ "Inhibit",
+ g_variant_new ("(ssss)",
+ "sleep",
+ g_get_user_name (),
+ "GNOME needs to lock the screen",
+ "delay"),
+ 0,
+ G_MAXINT,
+ NULL,
+ NULL,
+ inhibit_suspend_done,
+ manager);
+}
+
+static void
+uninhibit_suspend (GsdPowerManager *manager)
+{
+ if (manager->priv->inhibit_suspend_fd == -1) {
+ g_debug ("no suspend delay inhibitor");
+ return;
+ }
+ g_debug ("Removing suspend delay inhibitor");
+ close (manager->priv->inhibit_suspend_fd);
+ manager->priv->inhibit_suspend_fd = -1;
+ manager->priv->inhibit_suspend_taken = FALSE;
+}
+
+static gboolean
+randr_output_is_on (GnomeRROutput *output)
+{
+ GnomeRRCrtc *crtc;
+
+ crtc = gnome_rr_output_get_crtc (output);
+ if (!crtc)
+ return FALSE;
+ return gnome_rr_crtc_get_current_mode (crtc) != NULL;
+}
+
+static gboolean
+external_monitor_is_connected (GnomeRRScreen *screen)
+{
+ GnomeRROutput **outputs;
+ guint i;
+
+ if (g_file_test ("/tmp/external_connected", G_FILE_TEST_EXISTS))
+ return TRUE;
+
+ /* see if we have more than one screen plugged in */
+ outputs = gnome_rr_screen_list_outputs (screen);
+ for (i = 0; outputs[i] != NULL; i++) {
+ if (randr_output_is_on (outputs[i]) &&
+ !gnome_rr_output_is_laptop (outputs[i]))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+on_randr_event (GnomeRRScreen *screen, gpointer user_data)
+{
+ GsdPowerManager *manager = GSD_POWER_MANAGER (user_data);
+
+ /* when a second monitor is plugged in, we take the
+ * handle-lid-switch inhibitor lock of logind to prevent
+ * it from suspending.
+ *
+ * Uninhibiting is done in the inhibit_lid_switch_timer,
+ * since we want to give users a few seconds when unplugging
+ * and replugging an external monitor, not suspend right away.
+ */
+ if (external_monitor_is_connected (screen) &&
+ !g_settings_get_boolean (manager->priv->settings,
+ "lid-close-suspend-with-external-monitor")) {
+ inhibit_lid_switch (manager);
+ setup_inhibit_lid_switch_timer (manager);
+ }
+ else {
+ restart_inhibit_lid_switch_timer (manager);
+ }
+}
+
+static gboolean
+screen_lock_done_cb (gpointer data)
+{
+ GsdPowerManager *manager = data;
+
+ /* lift the delay inhibit, so logind can proceed */
+ uninhibit_suspend (manager);
+
+ return FALSE;
+}
+
+static void
+handle_suspend_actions (GsdPowerManager *manager)
+{
+ gboolean ret;
+ GError *error = NULL;
+
+ /* ensure we turn the panel back on after resume */
+ ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen,
+ GNOME_RR_DPMS_ON,
+ &error);
+ if (!ret) {
+ g_warning ("failed to turn the panel on after resume: %s",
+ error->message);
+ g_error_free (error);
+ }
+
+ lock_screensaver (manager, screen_lock_done_cb);
+}
+
+static void
+handle_resume_actions (GsdPowerManager *manager)
+{
+ gboolean ret;
+ GError *error = NULL;
+
+ /* this displays the unlock dialogue so the user doesn't have
+ * to move the mouse or press any key before the window comes up */
+ g_dbus_connection_call (manager->priv->connection,
+ GS_DBUS_NAME,
+ GS_DBUS_PATH,
+ GS_DBUS_INTERFACE,
+ "SimulateUserActivity",
+ NULL, NULL,
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, NULL, NULL);
+
+ /* close existing notifications on resume, the system power
+ * state is probably different now */
+ notify_close_if_showing (manager->priv->notification_low);
+ notify_close_if_showing (manager->priv->notification_discharging);
+
+ /* ensure we turn the panel back on after resume */
+ ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen,
+ GNOME_RR_DPMS_ON,
+ &error);
+ if (!ret) {
+ g_warning ("failed to turn the panel on after resume: %s",
+ error->message);
+ g_error_free (error);
+ }
+
+ /* set up the delay again */
+ inhibit_suspend (manager);
+}
+
+static void
+logind_proxy_signal_cb (GDBusProxy *proxy,
+ const gchar *sender_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ GsdPowerManager *manager = GSD_POWER_MANAGER (user_data);
+ gboolean is_about_to_suspend;
+
+ if (g_strcmp0 (signal_name, "PrepareForSleep") != 0)
+ return;
+ g_variant_get (parameters, "(b)", &is_about_to_suspend);
+ if (is_about_to_suspend) {
+ handle_suspend_actions (manager);
+ } else {
+ handle_resume_actions (manager);
+ }
+}
+
gboolean
gsd_power_manager_start (GsdPowerManager *manager,
GError **error)
@@ -3666,6 +3875,25 @@ gsd_power_manager_start (GsdPowerManager *manager,
g_debug ("Starting power manager");
gnome_settings_profile_start (NULL);
+ manager->priv->logind_proxy =
+ g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+ 0,
+ NULL,
+ SYSTEMD_DBUS_NAME,
+ SYSTEMD_DBUS_PATH,
+ SYSTEMD_DBUS_INTERFACE,
+ NULL,
+ error);
+ if (manager->priv->logind_proxy == NULL) {
+ g_warning ("no systemd support");
+ return FALSE;
+ }
+ g_signal_connect (manager->priv->logind_proxy, "g-signal",
+ G_CALLBACK (logind_proxy_signal_cb),
+ manager);
+ /* Set up a delay inhibitor to be informed about suspend attempts */
+ inhibit_suspend (manager);
+
/* track the active session */
manager->priv->session = gnome_settings_session_new ();
g_signal_connect (manager->priv->session, "notify::state",
@@ -3680,10 +3908,6 @@ gsd_power_manager_start (GsdPowerManager *manager,
G_CALLBACK (engine_settings_key_changed_cb), manager);
manager->priv->settings_screensaver = g_settings_new ("org.gnome.desktop.screensaver");
manager->priv->up_client = up_client_new ();
- g_signal_connect (manager->priv->up_client, "notify-sleep",
- G_CALLBACK (upower_notify_sleep_cb), manager);
- g_signal_connect (manager->priv->up_client, "notify-resume",
- G_CALLBACK (upower_notify_resume_cb), manager);
manager->priv->lid_is_closed = up_client_get_lid_is_closed (manager->priv->up_client);
g_signal_connect (manager->priv->up_client, "device-added",
G_CALLBACK (engine_device_added_cb), manager);
@@ -3792,6 +4016,9 @@ gsd_power_manager_start (GsdPowerManager *manager,
manager->priv->x11_screen = gnome_rr_screen_new (gdk_screen_get_default (), error);
if (manager->priv->x11_screen == NULL)
return FALSE;
+ g_signal_connect (manager->priv->x11_screen, "changed", G_CALLBACK (on_randr_event), manager);
+ /* set up initial state */
+ on_randr_event (manager->priv->x11_screen, manager);
/* ensure the default dpms timeouts are cleared */
ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen,
@@ -3821,6 +4048,11 @@ gsd_power_manager_stop (GsdPowerManager *manager)
{
g_debug ("Stopping power manager");
+ if (manager->priv->inhibit_lid_switch_timer_id != 0) {
+ g_source_remove (manager->priv->inhibit_lid_switch_timer_id);
+ manager->priv->inhibit_lid_switch_timer_id = 0;
+ }
+
if (manager->priv->bus_cancellable != NULL) {
g_cancellable_cancel (manager->priv->bus_cancellable);
g_object_unref (manager->priv->bus_cancellable);
@@ -3832,8 +4064,6 @@ gsd_power_manager_stop (GsdPowerManager *manager)
manager->priv->introspection_data = NULL;
}
- kill_lid_close_safety_timer (manager);
-
g_signal_handlers_disconnect_by_data (manager->priv->up_client, manager);
g_clear_object (&manager->priv->connection);
@@ -3841,6 +4071,19 @@ gsd_power_manager_stop (GsdPowerManager *manager)
g_clear_object (&manager->priv->settings);
g_clear_object (&manager->priv->settings_screensaver);
g_clear_object (&manager->priv->up_client);
+
+ if (manager->priv->inhibit_lid_switch_fd != -1) {
+ close (manager->priv->inhibit_lid_switch_fd);
+ manager->priv->inhibit_lid_switch_fd = -1;
+ manager->priv->inhibit_lid_switch_taken = FALSE;
+ }
+ if (manager->priv->inhibit_suspend_fd != -1) {
+ close (manager->priv->inhibit_suspend_fd);
+ manager->priv->inhibit_suspend_fd = -1;
+ manager->priv->inhibit_suspend_taken = FALSE;
+ }
+
+ g_clear_object (&manager->priv->logind_proxy);
g_clear_object (&manager->priv->x11_screen);
g_ptr_array_unref (manager->priv->devices_array);
@@ -3874,6 +4117,8 @@ static void
gsd_power_manager_init (GsdPowerManager *manager)
{
manager->priv = GSD_POWER_MANAGER_GET_PRIVATE (manager);
+ manager->priv->inhibit_lid_switch_fd = -1;
+ manager->priv->inhibit_suspend_fd = -1;
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]