Dominique Leuenberger
37f747727c
Integrate some wanted patches... OBS-URL: https://build.opensuse.org/request/show/149460 OBS-URL: https://build.opensuse.org/package/show/GNOME:Factory/gnome-settings-daemon?expand=0&rev=153
1469 lines
56 KiB
Diff
1469 lines
56 KiB
Diff
From 6defe42c31b18ad8dbb2fff3869b0fccbd821e97 Mon Sep 17 00:00:00 2001
|
|
From: Richard Hughes <richard@hughsie.com>
|
|
Date: Fri, 21 Sep 2012 11:56:53 +0100
|
|
Subject: [PATCH] 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(-)
|
|
delete mode 100644 plugins/common/gsd-power-helper.c
|
|
delete mode 100644 plugins/common/gsd-power-helper.h
|
|
|
|
Index: gnome-settings-daemon-3.6.3/plugins/common/Makefile.am
|
|
===================================================================
|
|
--- gnome-settings-daemon-3.6.3.orig/plugins/common/Makefile.am
|
|
+++ gnome-settings-daemon-3.6.3/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)
|
|
Index: gnome-settings-daemon-3.6.3/plugins/common/gsd-power-helper.c
|
|
===================================================================
|
|
--- gnome-settings-daemon-3.6.3.orig/plugins/common/gsd-power-helper.c
|
|
+++ /dev/null
|
|
@@ -1,203 +0,0 @@
|
|
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
|
|
- *
|
|
- * Copyright (C) 2012 Bastien Nocera <hadess@hadess.net>
|
|
- *
|
|
- * This program is free software; you can redistribute it and/or modify
|
|
- * it under the terms of the GNU General Public License as published by
|
|
- * the Free Software Foundation; either version 2 of the License, or
|
|
- * (at your option) any later version.
|
|
- *
|
|
- * This program is distributed in the hope that it will be useful,
|
|
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
- * GNU General Public License for more details.
|
|
- *
|
|
- * You should have received a copy of the GNU General Public License
|
|
- * along with this program; if not, write to the Free Software
|
|
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
- *
|
|
- */
|
|
-
|
|
-#include "config.h"
|
|
-
|
|
-#include "gsd-power-helper.h"
|
|
-
|
|
-#define SYSTEMD_DBUS_NAME "org.freedesktop.login1"
|
|
-#define SYSTEMD_DBUS_PATH "/org/freedesktop/login1"
|
|
-#define SYSTEMD_DBUS_INTERFACE "org.freedesktop.login1.Manager"
|
|
-
|
|
-#define CONSOLEKIT_DBUS_NAME "org.freedesktop.ConsoleKit"
|
|
-#define CONSOLEKIT_DBUS_PATH_MANAGER "/org/freedesktop/ConsoleKit/Manager"
|
|
-#define CONSOLEKIT_DBUS_INTERFACE_MANAGER "org.freedesktop.ConsoleKit.Manager"
|
|
-
|
|
-#ifdef HAVE_SYSTEMD
|
|
-static void
|
|
-systemd_stop (void)
|
|
-{
|
|
- GDBusConnection *bus;
|
|
-
|
|
- bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
|
|
- g_dbus_connection_call (bus,
|
|
- SYSTEMD_DBUS_NAME,
|
|
- SYSTEMD_DBUS_PATH,
|
|
- SYSTEMD_DBUS_INTERFACE,
|
|
- "PowerOff",
|
|
- g_variant_new ("(b)", FALSE),
|
|
- NULL, 0, G_MAXINT, NULL, NULL, NULL);
|
|
- g_object_unref (bus);
|
|
-}
|
|
-
|
|
-static void
|
|
-systemd_suspend (void)
|
|
-{
|
|
- GDBusConnection *bus;
|
|
-
|
|
- bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
|
|
- g_dbus_connection_call (bus,
|
|
- SYSTEMD_DBUS_NAME,
|
|
- SYSTEMD_DBUS_PATH,
|
|
- SYSTEMD_DBUS_INTERFACE,
|
|
- "Suspend",
|
|
- g_variant_new ("(b)", TRUE),
|
|
- NULL, 0, G_MAXINT, NULL, NULL, NULL);
|
|
- g_object_unref (bus);
|
|
-}
|
|
-
|
|
-static void
|
|
-systemd_hibernate (void)
|
|
-{
|
|
- GDBusConnection *bus;
|
|
-
|
|
- bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
|
|
- g_dbus_connection_call (bus,
|
|
- SYSTEMD_DBUS_NAME,
|
|
- SYSTEMD_DBUS_PATH,
|
|
- SYSTEMD_DBUS_INTERFACE,
|
|
- "Hibernate",
|
|
- g_variant_new ("(b)", TRUE),
|
|
- NULL, 0, G_MAXINT, NULL, NULL, NULL);
|
|
- g_object_unref (bus);
|
|
-}
|
|
-
|
|
-#else /* HAVE_SYSTEMD */
|
|
-
|
|
-static void
|
|
-consolekit_stop_cb (GObject *source_object,
|
|
- GAsyncResult *res,
|
|
- gpointer user_data)
|
|
-{
|
|
- GVariant *result;
|
|
- GError *error = NULL;
|
|
-
|
|
- result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
|
|
- res,
|
|
- &error);
|
|
- if (result == NULL) {
|
|
- g_warning ("couldn't stop using ConsoleKit: %s",
|
|
- error->message);
|
|
- g_error_free (error);
|
|
- } else {
|
|
- g_variant_unref (result);
|
|
- }
|
|
-}
|
|
-
|
|
-static void
|
|
-consolekit_stop (void)
|
|
-{
|
|
- GError *error = NULL;
|
|
- GDBusProxy *proxy;
|
|
-
|
|
- /* power down the machine in a safe way */
|
|
- proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
|
|
- G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
|
|
- NULL,
|
|
- CONSOLEKIT_DBUS_NAME,
|
|
- CONSOLEKIT_DBUS_PATH_MANAGER,
|
|
- CONSOLEKIT_DBUS_INTERFACE_MANAGER,
|
|
- NULL, &error);
|
|
- if (proxy == NULL) {
|
|
- g_warning ("cannot connect to ConsoleKit: %s",
|
|
- error->message);
|
|
- g_error_free (error);
|
|
- return;
|
|
- }
|
|
- g_dbus_proxy_call (proxy,
|
|
- "Stop",
|
|
- NULL,
|
|
- G_DBUS_CALL_FLAGS_NONE,
|
|
- -1, NULL,
|
|
- consolekit_stop_cb, NULL);
|
|
- g_object_unref (proxy);
|
|
-}
|
|
-static void
|
|
-upower_sleep_cb (GObject *source_object,
|
|
- GAsyncResult *res,
|
|
- gpointer user_data)
|
|
-{
|
|
- GVariant *result;
|
|
- GError *error = NULL;
|
|
-
|
|
- result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
|
|
- res,
|
|
- &error);
|
|
- if (result == NULL) {
|
|
- g_warning ("couldn't sleep using UPower: %s",
|
|
- error->message);
|
|
- g_error_free (error);
|
|
- } else {
|
|
- g_variant_unref (result);
|
|
- }
|
|
-}
|
|
-
|
|
-static void
|
|
-upower_suspend (GDBusProxy *upower_proxy)
|
|
-{
|
|
- g_dbus_proxy_call (upower_proxy,
|
|
- "Suspend",
|
|
- NULL,
|
|
- G_DBUS_CALL_FLAGS_NONE,
|
|
- -1, NULL,
|
|
- upower_sleep_cb, NULL);
|
|
-}
|
|
-
|
|
-static void
|
|
-upower_hibernate (GDBusProxy *upower_proxy)
|
|
-{
|
|
- g_dbus_proxy_call (upower_proxy,
|
|
- "Hibernate",
|
|
- NULL,
|
|
- G_DBUS_CALL_FLAGS_NONE,
|
|
- -1, NULL,
|
|
- upower_sleep_cb, NULL);
|
|
-}
|
|
-#endif /* HAVE_SYSTEMD */
|
|
-
|
|
-void
|
|
-gsd_power_suspend (GDBusProxy *upower_proxy)
|
|
-{
|
|
-#ifdef HAVE_SYSTEMD
|
|
- systemd_suspend ();
|
|
-#else
|
|
- upower_suspend (upower_proxy);
|
|
-#endif
|
|
-}
|
|
-
|
|
-void
|
|
-gsd_power_poweroff (void)
|
|
-{
|
|
-#ifdef HAVE_SYSTEMD
|
|
- systemd_stop ();
|
|
-#else
|
|
- consolekit_stop ();
|
|
-#endif
|
|
-}
|
|
-
|
|
-void
|
|
-gsd_power_hibernate (GDBusProxy *upower_proxy)
|
|
-{
|
|
-#ifdef HAVE_SYSTEMD
|
|
- systemd_hibernate ();
|
|
-#else
|
|
- upower_hibernate (upower_proxy);
|
|
-#endif
|
|
-}
|
|
Index: gnome-settings-daemon-3.6.3/plugins/common/gsd-power-helper.h
|
|
===================================================================
|
|
--- gnome-settings-daemon-3.6.3.orig/plugins/common/gsd-power-helper.h
|
|
+++ /dev/null
|
|
@@ -1,35 +0,0 @@
|
|
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
|
|
- *
|
|
- * Copyright (C) 2012 Bastien Nocera <hadess@hadess.net>
|
|
- *
|
|
- * This program is free software; you can redistribute it and/or modify
|
|
- * it under the terms of the GNU General Public License as published by
|
|
- * the Free Software Foundation; either version 2 of the License, or
|
|
- * (at your option) any later version.
|
|
- *
|
|
- * This program is distributed in the hope that it will be useful,
|
|
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
- * GNU General Public License for more details.
|
|
- *
|
|
- * You should have received a copy of the GNU General Public License
|
|
- * along with this program; if not, write to the Free Software
|
|
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
- */
|
|
-
|
|
-#ifndef __GSD_POWER_HELPER_H
|
|
-#define __GSD_POWER_HELPER_H
|
|
-
|
|
-#include <glib.h>
|
|
-
|
|
-G_BEGIN_DECLS
|
|
-
|
|
-#include <gio/gio.h>
|
|
-
|
|
-void gsd_power_suspend (GDBusProxy *upower_proxy);
|
|
-void gsd_power_hibernate (GDBusProxy *upower_proxy);
|
|
-void gsd_power_poweroff (void);
|
|
-
|
|
-G_END_DECLS
|
|
-
|
|
-#endif /* __GSD_POWER_HELPER_H */
|
|
Index: gnome-settings-daemon-3.6.3/plugins/media-keys/gsd-media-keys-manager.c
|
|
===================================================================
|
|
--- gnome-settings-daemon-3.6.3.orig/plugins/media-keys/gsd-media-keys-manager.c
|
|
+++ gnome-settings-daemon-3.6.3/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>
|
|
@@ -51,7 +52,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>
|
|
@@ -105,6 +105,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 {
|
|
@@ -148,10 +152,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;
|
|
@@ -1623,6 +1630,38 @@ do_toggle_contrast_action (GsdMediaKeysM
|
|
}
|
|
|
|
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)
|
|
{
|
|
@@ -1632,14 +1671,14 @@ do_config_power_action (GsdMediaKeysMana
|
|
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:
|
|
@@ -2253,6 +2292,7 @@ gsd_media_keys_manager_stop (GsdMediaKey
|
|
}
|
|
#endif /* HAVE_GUDEV */
|
|
|
|
+ g_clear_object (&priv->logind_proxy);
|
|
if (priv->settings) {
|
|
g_object_unref (priv->settings);
|
|
priv->settings = NULL;
|
|
@@ -2273,11 +2313,6 @@ gsd_media_keys_manager_stop (GsdMediaKey
|
|
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);
|
|
@@ -2368,9 +2403,85 @@ gsd_media_keys_manager_class_init (GsdMe
|
|
}
|
|
|
|
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
|
|
@@ -2387,6 +2498,8 @@ gsd_media_keys_manager_finalize (GObject
|
|
|
|
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);
|
|
}
|
|
@@ -2406,21 +2519,6 @@ xrandr_ready_cb (GObject *so
|
|
}
|
|
|
|
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)
|
|
@@ -2522,16 +2620,6 @@ register_manager (GsdMediaKeysManager *m
|
|
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 *
|
|
Index: gnome-settings-daemon-3.6.3/plugins/power/gsd-power-manager.c
|
|
===================================================================
|
|
--- gnome-settings-daemon-3.6.3.orig/plugins/power/gsd-power-manager.c
|
|
+++ gnome-settings-daemon-3.6.3/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 "/org/gnome/SessionManager"
|
|
@@ -78,6 +78,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 */
|
|
|
|
@@ -193,15 +197,21 @@ 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;
|
|
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;
|
|
+ guint inhibit_lid_switch_timer_id;
|
|
};
|
|
|
|
enum {
|
|
@@ -218,8 +228,8 @@ static GIcon *engine_get_icon (GsdPow
|
|
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)
|
|
|
|
@@ -2049,6 +2059,57 @@ gnome_session_shutdown (void)
|
|
}
|
|
|
|
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)
|
|
{
|
|
@@ -2057,19 +2118,19 @@ do_power_action_type (GsdPowerManager *m
|
|
|
|
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 ();
|
|
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,
|
|
@@ -2141,85 +2202,20 @@ upower_kbd_toggle (GsdPowerManager *mana
|
|
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)
|
|
+inhibit_lid_switch_timer_cb (GsdPowerManager *manager)
|
|
{
|
|
- 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)
|
|
-{
|
|
- 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
|
|
@@ -2227,82 +2223,73 @@ lid_close_safety_timer_cb (GsdPowerManag
|
|
* 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;
|
|
+ }
|
|
+
|
|
+ g_debug ("setting up lid close safety timer");
|
|
|
|
- manager->priv->lid_close_safety_timer_id = g_timeout_add_seconds (GSD_POWER_MANAGER_LID_CLOSE_SAFETY_TIMEOUT,
|
|
- (GSourceFunc) lid_close_safety_timer_cb,
|
|
+ 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",
|
|
@@ -2310,21 +2297,22 @@ do_lid_closed_action (GsdPowerManager *m
|
|
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)
|
|
{
|
|
@@ -2344,6 +2332,7 @@ up_client_changed_cb (UpClient *client,
|
|
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)
|
|
@@ -3302,30 +3291,6 @@ gsd_power_manager_class_init (GsdPowerMa
|
|
}
|
|
|
|
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,
|
|
@@ -3479,75 +3444,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
|
|
@@ -3757,6 +3685,287 @@ out:
|
|
return ret;
|
|
}
|
|
|
|
+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)
|
|
@@ -3766,6 +3975,25 @@ gsd_power_manager_start (GsdPowerManager
|
|
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",
|
|
@@ -3780,10 +4008,6 @@ gsd_power_manager_start (GsdPowerManager
|
|
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);
|
|
@@ -3897,6 +4121,9 @@ gsd_power_manager_start (GsdPowerManager
|
|
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,
|
|
@@ -3928,6 +4155,11 @@ gsd_power_manager_stop (GsdPowerManager
|
|
{
|
|
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);
|
|
@@ -3939,8 +4171,6 @@ gsd_power_manager_stop (GsdPowerManager
|
|
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);
|
|
@@ -3948,6 +4178,19 @@ gsd_power_manager_stop (GsdPowerManager
|
|
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);
|
|
@@ -3981,6 +4224,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
|