0096bb677a
With tiny changes from @vcunat.
536 lines
21 KiB
Diff
536 lines
21 KiB
Diff
|
|
diff --git a/plugins/media-keys/csd-media-keys-manager.c b/plugins/media-keys/csd-media-keys-manager.c
|
|
index 02930a3..7c1c519 100644
|
|
--- a/plugins/media-keys/csd-media-keys-manager.c
|
|
+++ b/plugins/media-keys/csd-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>
|
|
@@ -121,6 +122,10 @@ static const gchar kb_introspection_xml[] =
|
|
#define VOLUME_STEP 5 /* percents for one volume button press */
|
|
#define MAX_VOLUME 65536.0
|
|
|
|
+#define SYSTEMD_DBUS_NAME "org.freedesktop.login1"
|
|
+#define SYSTEMD_DBUS_PATH "/org/freedesktop/login1"
|
|
+#define SYSTEMD_DBUS_INTERFACE "org.freedesktop.login1.Manager"
|
|
+
|
|
#define CSD_MEDIA_KEYS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_MEDIA_KEYS_MANAGER, CsdMediaKeysManagerPrivate))
|
|
|
|
typedef struct {
|
|
@@ -167,6 +172,10 @@ struct CsdMediaKeysManagerPrivate
|
|
GDBusProxy *power_screen_proxy;
|
|
GDBusProxy *power_keyboard_proxy;
|
|
|
|
+ /* systemd stuff */
|
|
+ GDBusProxy *logind_proxy;
|
|
+ gint inhibit_keys_fd;
|
|
+
|
|
/* Multihead stuff */
|
|
GdkScreen *current_screen;
|
|
GSList *screens;
|
|
@@ -2213,6 +2222,11 @@ csd_media_keys_manager_stop (CsdMediaKeysManager *manager)
|
|
}
|
|
#endif /* HAVE_GUDEV */
|
|
|
|
+ if (priv->logind_proxy) {
|
|
+ g_object_unref (priv->logind_proxy);
|
|
+ priv->logind_proxy = NULL;
|
|
+ }
|
|
+
|
|
if (priv->settings) {
|
|
g_object_unref (priv->settings);
|
|
priv->settings = NULL;
|
|
@@ -2356,9 +2370,85 @@ csd_media_keys_manager_class_init (CsdMediaKeysManagerClass *klass)
|
|
}
|
|
|
|
static void
|
|
+inhibit_done (GObject *source,
|
|
+ GAsyncResult *result,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ GDBusProxy *proxy = G_DBUS_PROXY (source);
|
|
+ CsdMediaKeysManager *manager = CSD_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
|
|
csd_media_keys_manager_init (CsdMediaKeysManager *manager)
|
|
{
|
|
+ GError *error;
|
|
+ GDBusConnection *bus;
|
|
+
|
|
+ error = NULL;
|
|
manager->priv = CSD_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 (),
|
|
+ "Cinnamon handling keypresses",
|
|
+ "block"),
|
|
+ 0,
|
|
+ G_MAXINT,
|
|
+ NULL,
|
|
+ NULL,
|
|
+ inhibit_done,
|
|
+ manager);
|
|
+
|
|
}
|
|
|
|
static void
|
|
@@ -2375,6 +2465,8 @@ csd_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 (csd_media_keys_manager_parent_class)->finalize (object);
|
|
}
|
|
diff --git a/plugins/power/csd-power-manager.c b/plugins/power/csd-power-manager.c
|
|
index b54cb5b..b9c5429 100644
|
|
--- a/plugins/power/csd-power-manager.c
|
|
+++ b/plugins/power/csd-power-manager.c
|
|
@@ -32,6 +32,7 @@
|
|
#include <libupower-glib/upower.h>
|
|
#include <libnotify/notify.h>
|
|
#include <canberra-gtk.h>
|
|
+#include <gio/gunixfdlist.h>
|
|
|
|
#include <X11/extensions/dpms.h>
|
|
|
|
@@ -79,6 +80,10 @@
|
|
#define CSD_POWER_MANAGER_CRITICAL_ALERT_TIMEOUT 5 /* seconds */
|
|
#define CSD_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 */
|
|
|
|
@@ -203,6 +208,13 @@ struct CsdPowerManagerPrivate
|
|
GtkStatusIcon *status_icon;
|
|
guint xscreensaver_watchdog_timer_id;
|
|
gboolean is_virtual_machine;
|
|
+
|
|
+ /* systemd stuff */
|
|
+ GDBusProxy *logind_proxy;
|
|
+ gint inhibit_lid_switch_fd;
|
|
+ gboolean inhibit_lid_switch_taken;
|
|
+ gint inhibit_suspend_fd;
|
|
+ gboolean inhibit_suspend_taken;
|
|
};
|
|
|
|
enum {
|
|
@@ -3350,30 +3362,6 @@ lock_screensaver (CsdPowerManager *manager)
|
|
if (!do_lock)
|
|
return;
|
|
|
|
- /* 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,
|
|
- CsdPowerManager *manager)
|
|
-{
|
|
- gboolean do_lock;
|
|
-
|
|
- do_lock = g_settings_get_boolean (manager->priv->settings,
|
|
- "lock-on-suspend");
|
|
- if (!do_lock)
|
|
- return;
|
|
-
|
|
/* connect to the screensaver first */
|
|
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
|
|
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
|
|
@@ -3384,46 +3372,6 @@ upower_notify_sleep_cb (UpClient *client,
|
|
NULL,
|
|
sleep_cb_screensaver_proxy_ready_cb,
|
|
manager);
|
|
-
|
|
-}
|
|
-
|
|
-static void
|
|
-upower_notify_resume_cb (UpClient *client,
|
|
- UpSleepKind sleep_kind,
|
|
- CsdPowerManager *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);
|
|
- }
|
|
-
|
|
- if (manager->priv->screensaver_proxy != NULL) {
|
|
- g_object_unref (manager->priv->screensaver_proxy);
|
|
- manager->priv->screensaver_proxy = 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);
|
|
- }
|
|
}
|
|
|
|
static void
|
|
@@ -3582,6 +3530,219 @@ 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);
|
|
+ CsdPowerManager *manager = CSD_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 (CsdPowerManager *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
|
|
+inhibit_suspend_done (GObject *source,
|
|
+ GAsyncResult *result,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ GDBusProxy *proxy = G_DBUS_PROXY (source);
|
|
+ CsdPowerManager *manager = CSD_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 (CsdPowerManager *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 (),
|
|
+ "Cinnamon needs to lock the screen",
|
|
+ "delay"),
|
|
+ 0,
|
|
+ G_MAXINT,
|
|
+ NULL,
|
|
+ NULL,
|
|
+ inhibit_suspend_done,
|
|
+ manager);
|
|
+}
|
|
+
|
|
+static void
|
|
+uninhibit_suspend (CsdPowerManager *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 void
|
|
+handle_suspend_actions (CsdPowerManager *manager)
|
|
+{
|
|
+ gboolean do_lock;
|
|
+
|
|
+ do_lock = g_settings_get_boolean (manager->priv->settings,
|
|
+ "lock-on-suspend");
|
|
+ if (do_lock)
|
|
+ lock_screensaver (manager);
|
|
+
|
|
+ /* lift the delay inhibit, so logind can proceed */
|
|
+ uninhibit_suspend (manager);
|
|
+}
|
|
+
|
|
+static void
|
|
+handle_resume_actions (CsdPowerManager *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
|
|
+upower_notify_sleep_cb (UpClient *client,
|
|
+ UpSleepKind sleep_kind,
|
|
+ CsdPowerManager *manager)
|
|
+{
|
|
+ handle_suspend_actions (manager);
|
|
+}
|
|
+
|
|
+static void
|
|
+upower_notify_resume_cb (UpClient *client,
|
|
+ UpSleepKind sleep_kind,
|
|
+ CsdPowerManager *manager)
|
|
+{
|
|
+ handle_resume_actions (manager);
|
|
+}
|
|
+
|
|
+static void
|
|
+logind_proxy_signal_cb (GDBusProxy *proxy,
|
|
+ const gchar *sender_name,
|
|
+ const gchar *signal_name,
|
|
+ GVariant *parameters,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ CsdPowerManager *manager = CSD_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);
|
|
+ }
|
|
+}
|
|
+
|
|
static gboolean
|
|
is_hardware_a_virtual_machine (void)
|
|
{
|
|
@@ -3647,6 +3808,26 @@ csd_power_manager_start (CsdPowerManager *manager,
|
|
if (manager->priv->x11_screen == NULL)
|
|
return FALSE;
|
|
|
|
+ /* Set up the logind proxy */
|
|
+ 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);
|
|
+ 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);
|
|
+
|
|
+ /* Disable logind's lid handling while g-s-d is active */
|
|
+ inhibit_lid_switch (manager);
|
|
+
|
|
/* track the active session */
|
|
manager->priv->session = cinnamon_settings_session_new ();
|
|
g_signal_connect (manager->priv->session, "notify::state",
|
|
@@ -3856,6 +4037,22 @@ csd_power_manager_stop (CsdPowerManager *manager)
|
|
manager->priv->up_client = NULL;
|
|
}
|
|
|
|
+ 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;
|
|
+ }
|
|
+
|
|
+ if (manager->priv->logind_proxy != NULL) {
|
|
+ g_object_unref (manager->priv->logind_proxy);
|
|
+ manager->priv->logind_proxy = NULL;
|
|
+ }
|
|
+
|
|
if (manager->priv->x11_screen != NULL) {
|
|
g_object_unref (manager->priv->x11_screen);
|
|
manager->priv->x11_screen = NULL;
|
|
@@ -3928,6 +4125,8 @@ static void
|
|
csd_power_manager_init (CsdPowerManager *manager)
|
|
{
|
|
manager->priv = CSD_POWER_MANAGER_GET_PRIVATE (manager);
|
|
+ manager->priv->inhibit_lid_switch_fd = -1;
|
|
+ manager->priv->inhibit_suspend_fd = -1;
|
|
}
|
|
|
|
static void
|