mirror of
https://gitlab.freedesktop.org/upower/upower.git
synced 2026-05-23 09:18:15 +02:00
Defaulting to true, it controls whether we want the powersave commands to be run when running on battery/plugging ac. Signed-off-by: Richard Hughes <richard@hughsie.com>
1432 lines
38 KiB
C
1432 lines
38 KiB
C
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
|
*
|
|
* Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
|
|
* Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
|
|
*
|
|
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <glib.h>
|
|
#include <glib/gi18n-lib.h>
|
|
#include <glib-object.h>
|
|
#include <dbus/dbus-glib.h>
|
|
#include <dbus/dbus-glib-lowlevel.h>
|
|
|
|
#include "up-config.h"
|
|
#include "up-polkit.h"
|
|
#include "up-device-list.h"
|
|
#include "up-device.h"
|
|
#include "up-backend.h"
|
|
#include "up-daemon.h"
|
|
|
|
#include "up-daemon-glue.h"
|
|
#include "up-marshal.h"
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_DAEMON_VERSION,
|
|
PROP_CAN_SUSPEND,
|
|
PROP_CAN_HIBERNATE,
|
|
PROP_ON_BATTERY,
|
|
PROP_ON_LOW_BATTERY,
|
|
PROP_LID_IS_CLOSED,
|
|
PROP_LID_IS_PRESENT,
|
|
PROP_LID_FORCE_SLEEP,
|
|
PROP_IS_DOCKED,
|
|
PROP_LAST
|
|
};
|
|
|
|
enum
|
|
{
|
|
SIGNAL_DEVICE_ADDED,
|
|
SIGNAL_DEVICE_REMOVED,
|
|
SIGNAL_DEVICE_CHANGED,
|
|
SIGNAL_CHANGED,
|
|
SIGNAL_SLEEPING,
|
|
SIGNAL_RESUMING,
|
|
SIGNAL_NOTIFY_SLEEP,
|
|
SIGNAL_NOTIFY_RESUME,
|
|
SIGNAL_LAST,
|
|
};
|
|
|
|
static guint signals[SIGNAL_LAST] = { 0 };
|
|
|
|
struct UpDaemonPrivate
|
|
{
|
|
DBusGConnection *connection;
|
|
DBusGProxy *proxy;
|
|
UpConfig *config;
|
|
UpPolkit *polkit;
|
|
UpBackend *backend;
|
|
UpDeviceList *power_devices;
|
|
gboolean on_battery;
|
|
gboolean on_low_battery;
|
|
gboolean lid_is_closed;
|
|
gboolean lid_is_present;
|
|
gboolean lid_force_sleep;
|
|
gboolean is_docked;
|
|
gboolean kernel_can_suspend;
|
|
gboolean kernel_can_hibernate;
|
|
gboolean hibernate_has_encrypted_swap;
|
|
gboolean during_coldplug;
|
|
gboolean sent_sleeping_signal;
|
|
guint battery_poll_id;
|
|
guint battery_poll_count;
|
|
GTimer *about_to_sleep_timer;
|
|
guint about_to_sleep_id;
|
|
guint conf_sleep_timeout;
|
|
gboolean conf_allow_hibernate_encrypted_swap;
|
|
gboolean conf_run_powersave_command;
|
|
const gchar *sleep_kind;
|
|
};
|
|
|
|
static void up_daemon_finalize (GObject *object);
|
|
static gboolean up_daemon_get_on_battery_local (UpDaemon *daemon);
|
|
static gboolean up_daemon_get_on_low_battery_local (UpDaemon *daemon);
|
|
static gboolean up_daemon_get_on_ac_local (UpDaemon *daemon);
|
|
|
|
G_DEFINE_TYPE (UpDaemon, up_daemon, G_TYPE_OBJECT)
|
|
|
|
#define UP_DAEMON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), UP_TYPE_DAEMON, UpDaemonPrivate))
|
|
|
|
/* if using more memory compared to usable swap, disable hibernate */
|
|
/* Native Linux suspend-to-disk does not use compression, and needs 2 KB of
|
|
* page meta information for each MB of active memory. Add some error margin
|
|
* here, though. */
|
|
#define UP_DAEMON_SWAP_WATERLINE 98.f /* % */
|
|
|
|
/* refresh all the devices after this much time when on-battery has changed */
|
|
#define UP_DAEMON_ON_BATTERY_REFRESH_DEVICES_DELAY 1 /* seconds */
|
|
#define UP_DAEMON_POLL_BATTERY_NUMBER_TIMES 5
|
|
|
|
/* D-BUS to connect to. Can be set to session bus for testing */
|
|
static DBusBusType daemon_bus_type = DBUS_BUS_SYSTEM;
|
|
|
|
DBusBusType
|
|
up_daemon_get_bus_type (void)
|
|
{
|
|
return daemon_bus_type;
|
|
}
|
|
|
|
void
|
|
up_daemon_set_bus_type (DBusBusType type)
|
|
{
|
|
daemon_bus_type = type;
|
|
}
|
|
|
|
/**
|
|
* up_daemon_get_on_battery_local:
|
|
*
|
|
* As soon as _any_ battery goes discharging, this is true
|
|
**/
|
|
static gboolean
|
|
up_daemon_get_on_battery_local (UpDaemon *daemon)
|
|
{
|
|
guint i;
|
|
gboolean ret;
|
|
gboolean result = FALSE;
|
|
gboolean on_battery;
|
|
UpDevice *device;
|
|
GPtrArray *array;
|
|
|
|
/* ask each device */
|
|
array = up_device_list_get_array (daemon->priv->power_devices);
|
|
for (i=0; i<array->len; i++) {
|
|
device = (UpDevice *) g_ptr_array_index (array, i);
|
|
ret = up_device_get_on_battery (device, &on_battery);
|
|
if (ret && on_battery) {
|
|
result = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
g_ptr_array_unref (array);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* up_daemon_get_number_devices_of_type:
|
|
**/
|
|
guint
|
|
up_daemon_get_number_devices_of_type (UpDaemon *daemon, UpDeviceKind type)
|
|
{
|
|
guint i;
|
|
UpDevice *device;
|
|
GPtrArray *array;
|
|
UpDeviceKind type_tmp;
|
|
guint count = 0;
|
|
|
|
/* ask each device */
|
|
array = up_device_list_get_array (daemon->priv->power_devices);
|
|
for (i=0; i<array->len; i++) {
|
|
device = (UpDevice *) g_ptr_array_index (array, i);
|
|
g_object_get (device,
|
|
"type", &type_tmp,
|
|
NULL);
|
|
if (type == type_tmp)
|
|
count++;
|
|
}
|
|
g_ptr_array_unref (array);
|
|
return count;
|
|
}
|
|
|
|
/**
|
|
* up_daemon_get_on_low_battery_local:
|
|
*
|
|
* As soon as _all_ batteries are low, this is true
|
|
**/
|
|
static gboolean
|
|
up_daemon_get_on_low_battery_local (UpDaemon *daemon)
|
|
{
|
|
guint i;
|
|
gboolean ret;
|
|
gboolean result = TRUE;
|
|
gboolean on_low_battery;
|
|
UpDevice *device;
|
|
GPtrArray *array;
|
|
|
|
/* ask each device */
|
|
array = up_device_list_get_array (daemon->priv->power_devices);
|
|
for (i=0; i<array->len; i++) {
|
|
device = (UpDevice *) g_ptr_array_index (array, i);
|
|
ret = up_device_get_low_battery (device, &on_low_battery);
|
|
if (ret && !on_low_battery) {
|
|
result = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
g_ptr_array_unref (array);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* up_daemon_get_on_ac_local:
|
|
*
|
|
* As soon as _any_ ac supply goes online, this is true
|
|
**/
|
|
static gboolean
|
|
up_daemon_get_on_ac_local (UpDaemon *daemon)
|
|
{
|
|
guint i;
|
|
gboolean ret;
|
|
gboolean result = FALSE;
|
|
gboolean online;
|
|
UpDevice *device;
|
|
GPtrArray *array;
|
|
|
|
/* ask each device */
|
|
array = up_device_list_get_array (daemon->priv->power_devices);
|
|
for (i=0; i<array->len; i++) {
|
|
device = (UpDevice *) g_ptr_array_index (array, i);
|
|
ret = up_device_get_online (device, &online);
|
|
if (ret && online) {
|
|
result = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
g_ptr_array_unref (array);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* up_daemon_set_powersave:
|
|
**/
|
|
static gboolean
|
|
up_daemon_set_powersave (UpDaemon *daemon, gboolean powersave)
|
|
{
|
|
gboolean ret = FALSE;
|
|
const gchar *command;
|
|
GError *error = NULL;
|
|
|
|
/* run script */
|
|
command = up_backend_get_powersave_command (daemon->priv->backend, powersave);
|
|
if (command == NULL) {
|
|
g_warning ("no powersave command set");
|
|
goto out;
|
|
}
|
|
g_debug ("excuting command: %s", command);
|
|
ret = g_spawn_command_line_async (command, &error);
|
|
if (!ret) {
|
|
g_warning ("failed to run script: %s", error->message);
|
|
g_error_free (error);
|
|
goto out;
|
|
}
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* up_daemon_refresh_battery_devices:
|
|
**/
|
|
static gboolean
|
|
up_daemon_refresh_battery_devices (UpDaemon *daemon)
|
|
{
|
|
guint i;
|
|
GPtrArray *array;
|
|
UpDevice *device;
|
|
UpDeviceKind type;
|
|
|
|
/* refresh all devices in array */
|
|
array = up_device_list_get_array (daemon->priv->power_devices);
|
|
for (i=0; i<array->len; i++) {
|
|
device = (UpDevice *) g_ptr_array_index (array, i);
|
|
/* only refresh battery devices */
|
|
g_object_get (device,
|
|
"type", &type,
|
|
NULL);
|
|
if (type == UP_DEVICE_KIND_BATTERY)
|
|
up_device_refresh_internal (device);
|
|
}
|
|
g_ptr_array_unref (array);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* up_daemon_enumerate_devices:
|
|
**/
|
|
gboolean
|
|
up_daemon_enumerate_devices (UpDaemon *daemon, DBusGMethodInvocation *context)
|
|
{
|
|
guint i;
|
|
GPtrArray *array;
|
|
GPtrArray *object_paths;
|
|
UpDevice *device;
|
|
|
|
/* build a pointer array of the object paths */
|
|
object_paths = g_ptr_array_new_with_free_func (g_free);
|
|
array = up_device_list_get_array (daemon->priv->power_devices);
|
|
for (i=0; i<array->len; i++) {
|
|
device = (UpDevice *) g_ptr_array_index (array, i);
|
|
g_ptr_array_add (object_paths, g_strdup (up_device_get_object_path (device)));
|
|
}
|
|
g_ptr_array_unref (array);
|
|
|
|
/* return it on the bus */
|
|
dbus_g_method_return (context, object_paths);
|
|
|
|
/* free */
|
|
g_ptr_array_unref (object_paths);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* up_daemon_about_to_sleep:
|
|
**/
|
|
gboolean
|
|
up_daemon_about_to_sleep (UpDaemon *daemon,
|
|
const gchar *sleep_kind,
|
|
DBusGMethodInvocation *context)
|
|
{
|
|
PolkitSubject *subject = NULL;
|
|
GError *error;
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
|
|
/* already requested */
|
|
if (priv->about_to_sleep_id != 0) {
|
|
error = g_error_new (UP_DAEMON_ERROR,
|
|
UP_DAEMON_ERROR_GENERAL,
|
|
"Sleep has already been requested and is pending");
|
|
dbus_g_method_return_error (context, error);
|
|
g_error_free (error);
|
|
goto out;
|
|
}
|
|
|
|
subject = up_polkit_get_subject (priv->polkit, context);
|
|
if (subject == NULL)
|
|
goto out;
|
|
|
|
/* TODO: use another PolicyKit context? */
|
|
if (!up_polkit_check_auth (priv->polkit, subject, "org.freedesktop.upower.suspend", context))
|
|
goto out;
|
|
|
|
/* we've told the clients we're going down */
|
|
g_debug ("emitting sleeping");
|
|
g_signal_emit (daemon, signals[SIGNAL_SLEEPING], 0);
|
|
g_signal_emit (daemon, signals[SIGNAL_NOTIFY_SLEEP], 0,
|
|
sleep_kind);
|
|
g_timer_start (priv->about_to_sleep_timer);
|
|
daemon->priv->sent_sleeping_signal = TRUE;
|
|
|
|
dbus_g_method_return (context, NULL);
|
|
out:
|
|
if (subject != NULL)
|
|
g_object_unref (subject);
|
|
return TRUE;
|
|
}
|
|
|
|
/* temp object for deferred callback */
|
|
typedef struct {
|
|
UpDaemon *daemon;
|
|
DBusGMethodInvocation *context;
|
|
gchar *command;
|
|
} UpDaemonDeferredSleep;
|
|
|
|
/**
|
|
* up_daemon_deferred_sleep_cb:
|
|
**/
|
|
static gboolean
|
|
up_daemon_deferred_sleep_cb (UpDaemonDeferredSleep *sleep)
|
|
{
|
|
GError *error;
|
|
GError *error_local = NULL;
|
|
gchar *stdout = NULL;
|
|
gchar *stderr = NULL;
|
|
gboolean ret;
|
|
UpDaemon *daemon = sleep->daemon;
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
|
|
/* run the command */
|
|
ret = g_spawn_command_line_sync (sleep->command, &stdout, &stderr, NULL, &error_local);
|
|
if (!ret) {
|
|
error = g_error_new (UP_DAEMON_ERROR,
|
|
UP_DAEMON_ERROR_GENERAL,
|
|
"Failed to spawn: %s, stdout:%s, stderr:%s", error_local->message, stdout, stderr);
|
|
g_error_free (error_local);
|
|
dbus_g_method_return_error (sleep->context, error);
|
|
g_error_free (error);
|
|
goto out;
|
|
}
|
|
|
|
/* emit signal for session components */
|
|
g_debug ("emitting resuming");
|
|
g_signal_emit (daemon, signals[SIGNAL_RESUMING], 0);
|
|
g_signal_emit (daemon, signals[SIGNAL_NOTIFY_RESUME], 0,
|
|
priv->sleep_kind);
|
|
|
|
/* reset the about-to-sleep logic */
|
|
g_timer_reset (priv->about_to_sleep_timer);
|
|
g_timer_stop (priv->about_to_sleep_timer);
|
|
|
|
/* actually return from the DBus call now */
|
|
dbus_g_method_return (sleep->context, NULL);
|
|
|
|
out:
|
|
/* clear timer */
|
|
priv->about_to_sleep_id = 0;
|
|
priv->sent_sleeping_signal = FALSE;
|
|
|
|
g_free (stdout);
|
|
g_free (stderr);
|
|
|
|
/* delete temp object */
|
|
g_object_unref (sleep->daemon);
|
|
g_free (sleep->command);
|
|
g_free (sleep);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* up_daemon_deferred_sleep:
|
|
**/
|
|
static void
|
|
up_daemon_deferred_sleep (UpDaemon *daemon, const gchar *command, DBusGMethodInvocation *context)
|
|
{
|
|
UpDaemonDeferredSleep *sleep;
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
gfloat elapsed;
|
|
|
|
/* create callback object */
|
|
sleep = g_new0 (UpDaemonDeferredSleep, 1);
|
|
sleep->daemon = g_object_ref (daemon);
|
|
sleep->context = context;
|
|
sleep->command = g_strdup (command);
|
|
|
|
/* we didn't use AboutToSleep() so send the signal for clients now */
|
|
if (!priv->sent_sleeping_signal) {
|
|
g_debug ("no AboutToSleep(), so emitting ::Sleeping()");
|
|
g_signal_emit (daemon, signals[SIGNAL_SLEEPING], 0);
|
|
g_signal_emit (daemon, signals[SIGNAL_NOTIFY_SLEEP], 0,
|
|
priv->sleep_kind);
|
|
priv->about_to_sleep_id = g_timeout_add (priv->conf_sleep_timeout,
|
|
(GSourceFunc) up_daemon_deferred_sleep_cb, sleep);
|
|
#if GLIB_CHECK_VERSION(2,25,8)
|
|
g_source_set_name_by_id (priv->about_to_sleep_id, "[UpDaemon] about-to-sleep no signal");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
/* about to sleep */
|
|
elapsed = 1000.0f * g_timer_elapsed (priv->about_to_sleep_timer, NULL);
|
|
g_debug ("between AboutToSleep() and %s was %fms", sleep->command, elapsed);
|
|
if (elapsed < priv->conf_sleep_timeout) {
|
|
/* we have to wait for the difference in time */
|
|
priv->about_to_sleep_id = g_timeout_add (priv->conf_sleep_timeout - elapsed,
|
|
(GSourceFunc) up_daemon_deferred_sleep_cb, sleep);
|
|
#if GLIB_CHECK_VERSION(2,25,8)
|
|
g_source_set_name_by_id (priv->about_to_sleep_id, "[UpDaemon] about-to-sleep less");
|
|
#endif
|
|
} else {
|
|
/* we can do this straight away */
|
|
priv->about_to_sleep_id = g_idle_add ((GSourceFunc) up_daemon_deferred_sleep_cb, sleep);
|
|
#if GLIB_CHECK_VERSION(2,25,8)
|
|
g_source_set_name_by_id (priv->about_to_sleep_id, "[UpDaemon] about-to-sleep more");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/**
|
|
* up_daemon_suspend:
|
|
**/
|
|
gboolean
|
|
up_daemon_suspend (UpDaemon *daemon, DBusGMethodInvocation *context)
|
|
{
|
|
GError *error;
|
|
PolkitSubject *subject = NULL;
|
|
const gchar *command;
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
|
|
/* no kernel support */
|
|
if (!priv->kernel_can_suspend) {
|
|
error = g_error_new (UP_DAEMON_ERROR,
|
|
UP_DAEMON_ERROR_GENERAL,
|
|
"No kernel support");
|
|
dbus_g_method_return_error (context, error);
|
|
g_error_free (error);
|
|
goto out;
|
|
}
|
|
|
|
subject = up_polkit_get_subject (priv->polkit, context);
|
|
if (subject == NULL)
|
|
goto out;
|
|
|
|
if (!up_polkit_check_auth (priv->polkit, subject, "org.freedesktop.upower.suspend", context))
|
|
goto out;
|
|
|
|
/* already requested */
|
|
if (priv->about_to_sleep_id != 0) {
|
|
error = g_error_new (UP_DAEMON_ERROR,
|
|
UP_DAEMON_ERROR_GENERAL,
|
|
"Sleep has already been requested and is pending");
|
|
dbus_g_method_return_error (context, error);
|
|
g_error_free (error);
|
|
goto out;
|
|
}
|
|
|
|
/* do this deferred action */
|
|
priv->sleep_kind = "suspend";
|
|
command = up_backend_get_suspend_command (priv->backend);
|
|
up_daemon_deferred_sleep (daemon, command, context);
|
|
out:
|
|
if (subject != NULL)
|
|
g_object_unref (subject);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* up_daemon_suspend_allowed:
|
|
**/
|
|
gboolean
|
|
up_daemon_suspend_allowed (UpDaemon *daemon, DBusGMethodInvocation *context)
|
|
{
|
|
gboolean ret;
|
|
PolkitSubject *subject = NULL;
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
GError *error;
|
|
|
|
subject = up_polkit_get_subject (priv->polkit, context);
|
|
if (subject == NULL)
|
|
goto out;
|
|
|
|
error = NULL;
|
|
ret = up_polkit_is_allowed (priv->polkit, subject, "org.freedesktop.upower.suspend", &error);
|
|
if (error) {
|
|
dbus_g_method_return_error (context, error);
|
|
g_error_free (error);
|
|
}
|
|
else {
|
|
dbus_g_method_return (context, ret);
|
|
}
|
|
|
|
out:
|
|
if (subject != NULL)
|
|
g_object_unref (subject);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* up_daemon_check_hibernate_swap:
|
|
*
|
|
* Check current memory usage whether we have enough swap space for
|
|
* hibernate.
|
|
**/
|
|
static gboolean
|
|
up_daemon_check_hibernate_swap (UpDaemon *daemon)
|
|
{
|
|
gfloat waterline;
|
|
|
|
if (daemon->priv->kernel_can_hibernate) {
|
|
waterline = up_backend_get_used_swap (daemon->priv->backend);
|
|
if (waterline < UP_DAEMON_SWAP_WATERLINE) {
|
|
g_debug ("enough swap to for hibernate");
|
|
return TRUE;
|
|
} else {
|
|
g_debug ("not enough swap to hibernate");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* up_daemon_hibernate:
|
|
**/
|
|
gboolean
|
|
up_daemon_hibernate (UpDaemon *daemon, DBusGMethodInvocation *context)
|
|
{
|
|
GError *error;
|
|
PolkitSubject *subject = NULL;
|
|
const gchar *command;
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
|
|
/* no kernel support */
|
|
if (!priv->kernel_can_hibernate) {
|
|
error = g_error_new (UP_DAEMON_ERROR,
|
|
UP_DAEMON_ERROR_GENERAL,
|
|
"No kernel support");
|
|
dbus_g_method_return_error (context, error);
|
|
g_error_free (error);
|
|
goto out;
|
|
}
|
|
|
|
/* enough swap? */
|
|
if (!up_daemon_check_hibernate_swap (daemon)) {
|
|
error = g_error_new (UP_DAEMON_ERROR,
|
|
UP_DAEMON_ERROR_GENERAL,
|
|
"Not enough swap space");
|
|
dbus_g_method_return_error (context, error);
|
|
g_error_free (error);
|
|
goto out;
|
|
}
|
|
|
|
/* encrypted swap and no override? */
|
|
if (priv->hibernate_has_encrypted_swap &&
|
|
!priv->conf_allow_hibernate_encrypted_swap) {
|
|
error = g_error_new (UP_DAEMON_ERROR,
|
|
UP_DAEMON_ERROR_GENERAL,
|
|
"Swap space is encrypted, use AllowHibernateEncryptedSwap to override");
|
|
dbus_g_method_return_error (context, error);
|
|
g_error_free (error);
|
|
goto out;
|
|
}
|
|
|
|
subject = up_polkit_get_subject (priv->polkit, context);
|
|
if (subject == NULL)
|
|
goto out;
|
|
|
|
if (!up_polkit_check_auth (priv->polkit, subject, "org.freedesktop.upower.hibernate", context))
|
|
goto out;
|
|
|
|
/* already requested */
|
|
if (priv->about_to_sleep_id != 0) {
|
|
error = g_error_new (UP_DAEMON_ERROR,
|
|
UP_DAEMON_ERROR_GENERAL,
|
|
"Sleep has already been requested and is pending");
|
|
dbus_g_method_return_error (context, error);
|
|
g_error_free (error);
|
|
goto out;
|
|
}
|
|
|
|
/* do this deferred action */
|
|
priv->sleep_kind = "hibernate";
|
|
command = up_backend_get_hibernate_command (priv->backend);
|
|
up_daemon_deferred_sleep (daemon, command, context);
|
|
out:
|
|
if (subject != NULL)
|
|
g_object_unref (subject);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* up_daemon_hibernate_allowed:
|
|
**/
|
|
gboolean
|
|
up_daemon_hibernate_allowed (UpDaemon *daemon, DBusGMethodInvocation *context)
|
|
{
|
|
gboolean ret;
|
|
PolkitSubject *subject = NULL;
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
GError *error;
|
|
|
|
subject = up_polkit_get_subject (priv->polkit, context);
|
|
if (subject == NULL)
|
|
goto out;
|
|
|
|
error = NULL;
|
|
ret = up_polkit_is_allowed (priv->polkit, subject, "org.freedesktop.upower.hibernate", &error);
|
|
if (error) {
|
|
dbus_g_method_return_error (context, error);
|
|
g_error_free (error);
|
|
}
|
|
else {
|
|
dbus_g_method_return (context, ret);
|
|
}
|
|
|
|
out:
|
|
if (subject != NULL)
|
|
g_object_unref (subject);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* up_daemon_register_power_daemon:
|
|
**/
|
|
static gboolean
|
|
up_daemon_register_power_daemon (UpDaemon *daemon)
|
|
{
|
|
GError *error = NULL;
|
|
gboolean ret = FALSE;
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
|
|
priv->connection = dbus_g_bus_get (up_daemon_get_bus_type (), &error);
|
|
if (priv->connection == NULL) {
|
|
if (error != NULL) {
|
|
g_critical ("error getting system bus: %s", error->message);
|
|
g_error_free (error);
|
|
}
|
|
goto out;
|
|
}
|
|
|
|
/* connect to DBUS */
|
|
priv->proxy = dbus_g_proxy_new_for_name (priv->connection,
|
|
DBUS_SERVICE_DBUS,
|
|
DBUS_PATH_DBUS,
|
|
DBUS_INTERFACE_DBUS);
|
|
|
|
/* register GObject */
|
|
dbus_g_connection_register_g_object (priv->connection,
|
|
"/org/freedesktop/UPower",
|
|
G_OBJECT (daemon));
|
|
|
|
/* success */
|
|
ret = TRUE;
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* up_daemon_startup:
|
|
**/
|
|
gboolean
|
|
up_daemon_startup (UpDaemon *daemon)
|
|
{
|
|
gboolean ret;
|
|
gboolean on_battery;
|
|
gboolean on_low_battery;
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
|
|
/* register on bus */
|
|
ret = up_daemon_register_power_daemon (daemon);
|
|
if (!ret) {
|
|
g_warning ("failed to register");
|
|
goto out;
|
|
}
|
|
|
|
/* stop signals and callbacks */
|
|
g_debug ("daemon now coldplug");
|
|
g_object_freeze_notify (G_OBJECT(daemon));
|
|
priv->during_coldplug = TRUE;
|
|
|
|
/* coldplug backend backend */
|
|
ret = up_backend_coldplug (priv->backend, daemon);
|
|
if (!ret) {
|
|
g_warning ("failed to coldplug backend");
|
|
goto out;
|
|
}
|
|
|
|
/* get battery state */
|
|
on_battery = (up_daemon_get_on_battery_local (daemon) &&
|
|
!up_daemon_get_on_ac_local (daemon));
|
|
on_low_battery = up_daemon_get_on_low_battery_local (daemon);
|
|
up_daemon_set_on_battery (daemon, on_battery);
|
|
up_daemon_set_on_low_battery (daemon, on_low_battery);
|
|
|
|
/* start signals and callbacks */
|
|
g_object_thaw_notify (G_OBJECT(daemon));
|
|
priv->during_coldplug = FALSE;
|
|
g_debug ("daemon now not coldplug");
|
|
|
|
/* set power policy */
|
|
if (priv->conf_run_powersave_command)
|
|
up_daemon_set_powersave (daemon, priv->on_battery);
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* up_daemon_get_device_list:
|
|
**/
|
|
UpDeviceList *
|
|
up_daemon_get_device_list (UpDaemon *daemon)
|
|
{
|
|
return g_object_ref (daemon->priv->power_devices);
|
|
}
|
|
|
|
/**
|
|
* up_daemon_set_lid_is_closed:
|
|
**/
|
|
void
|
|
up_daemon_set_lid_is_closed (UpDaemon *daemon, gboolean lid_is_closed)
|
|
{
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
|
|
/* check if we are ignoring the lid */
|
|
if (up_config_get_boolean (priv->config, "IgnoreLid")) {
|
|
g_debug ("ignoring lid state");
|
|
return;
|
|
}
|
|
|
|
g_debug ("lid_is_closed = %s", lid_is_closed ? "yes" : "no");
|
|
priv->lid_is_closed = lid_is_closed;
|
|
g_object_notify (G_OBJECT (daemon), "lid-is-closed");
|
|
}
|
|
|
|
/**
|
|
* up_daemon_set_lid_force_sleep:
|
|
**/
|
|
void
|
|
up_daemon_set_lid_force_sleep (UpDaemon *daemon, gboolean lid_force_sleep)
|
|
{
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
g_debug ("lid_force_sleep = %s", lid_force_sleep ? "yes" : "no");
|
|
priv->lid_force_sleep = lid_force_sleep;
|
|
g_object_notify (G_OBJECT (daemon), "lid-enforce-sleep");
|
|
}
|
|
|
|
/**
|
|
* up_daemon_set_lid_is_present:
|
|
**/
|
|
void
|
|
up_daemon_set_lid_is_present (UpDaemon *daemon, gboolean lid_is_present)
|
|
{
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
|
|
/* check if we are ignoring the lid */
|
|
if (up_config_get_boolean (priv->config, "IgnoreLid")) {
|
|
g_debug ("ignoring lid state");
|
|
return;
|
|
}
|
|
|
|
g_debug ("lid_is_present = %s", lid_is_present ? "yes" : "no");
|
|
priv->lid_is_present = lid_is_present;
|
|
g_object_notify (G_OBJECT (daemon), "lid-is-present");
|
|
}
|
|
|
|
/**
|
|
* up_daemon_set_is_docked:
|
|
**/
|
|
void
|
|
up_daemon_set_is_docked (UpDaemon *daemon, gboolean is_docked)
|
|
{
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
g_debug ("is_docked = %s", is_docked ? "yes" : "no");
|
|
priv->is_docked = is_docked;
|
|
g_object_notify (G_OBJECT (daemon), "is-docked");
|
|
}
|
|
|
|
/**
|
|
* up_daemon_set_on_battery:
|
|
**/
|
|
void
|
|
up_daemon_set_on_battery (UpDaemon *daemon, gboolean on_battery)
|
|
{
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
g_debug ("on_battery = %s", on_battery ? "yes" : "no");
|
|
priv->on_battery = on_battery;
|
|
g_object_notify (G_OBJECT (daemon), "on-battery");
|
|
}
|
|
|
|
/**
|
|
* up_daemon_set_on_low_battery:
|
|
**/
|
|
void
|
|
up_daemon_set_on_low_battery (UpDaemon *daemon, gboolean on_low_battery)
|
|
{
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
g_debug ("on_low_battery = %s", on_low_battery ? "yes" : "no");
|
|
priv->on_low_battery = on_low_battery;
|
|
g_object_notify (G_OBJECT (daemon), "on-low-battery");
|
|
}
|
|
|
|
/**
|
|
* up_daemon_refresh_battery_devices_cb:
|
|
**/
|
|
static gboolean
|
|
up_daemon_refresh_battery_devices_cb (UpDaemon *daemon)
|
|
{
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
|
|
/* no more left to do? */
|
|
if (priv->battery_poll_count-- == 0) {
|
|
priv->battery_poll_id = 0;
|
|
return FALSE;
|
|
}
|
|
|
|
g_debug ("doing the delayed refresh (%i)", priv->battery_poll_count);
|
|
up_daemon_refresh_battery_devices (daemon);
|
|
|
|
/* keep going until none left to do */
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* up_daemon_poll_battery_devices_for_a_little_bit:
|
|
**/
|
|
static void
|
|
up_daemon_poll_battery_devices_for_a_little_bit (UpDaemon *daemon)
|
|
{
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
|
|
priv->battery_poll_count = UP_DAEMON_POLL_BATTERY_NUMBER_TIMES;
|
|
|
|
/* already polling */
|
|
if (priv->battery_poll_id != 0)
|
|
return;
|
|
priv->battery_poll_id =
|
|
g_timeout_add_seconds (UP_DAEMON_ON_BATTERY_REFRESH_DEVICES_DELAY,
|
|
(GSourceFunc) up_daemon_refresh_battery_devices_cb, daemon);
|
|
#if GLIB_CHECK_VERSION(2,25,8)
|
|
g_source_set_name_by_id (priv->battery_poll_id, "[UpDaemon] poll batteries for AC event");
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* up_daemon_device_changed_cb:
|
|
**/
|
|
static void
|
|
up_daemon_device_changed_cb (UpDevice *device, UpDaemon *daemon)
|
|
{
|
|
const gchar *object_path;
|
|
UpDeviceKind type;
|
|
gboolean ret;
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
|
|
g_return_if_fail (UP_IS_DAEMON (daemon));
|
|
g_return_if_fail (UP_IS_DEVICE (device));
|
|
|
|
/* refresh battery devices when AC state changes */
|
|
g_object_get (device,
|
|
"type", &type,
|
|
NULL);
|
|
if (type == UP_DEVICE_KIND_LINE_POWER) {
|
|
/* refresh now, and again in a little while */
|
|
up_daemon_refresh_battery_devices (daemon);
|
|
up_daemon_poll_battery_devices_for_a_little_bit (daemon);
|
|
}
|
|
|
|
/* second, check if the on_battery and on_low_battery state has changed */
|
|
ret = (up_daemon_get_on_battery_local (daemon) && !up_daemon_get_on_ac_local (daemon));
|
|
if (ret != priv->on_battery) {
|
|
up_daemon_set_on_battery (daemon, ret);
|
|
|
|
/* set power policy */
|
|
if (priv->conf_run_powersave_command)
|
|
up_daemon_set_powersave (daemon, ret);
|
|
}
|
|
ret = up_daemon_get_on_low_battery_local (daemon);
|
|
if (ret != priv->on_low_battery)
|
|
up_daemon_set_on_low_battery (daemon, ret);
|
|
|
|
/* emit */
|
|
if (!priv->during_coldplug) {
|
|
object_path = up_device_get_object_path (device);
|
|
g_debug ("emitting device-changed: %s", object_path);
|
|
|
|
/* don't crash the session */
|
|
if (object_path == NULL) {
|
|
g_warning ("INTERNAL STATE CORRUPT: not sending NULL, device:%p", device);
|
|
return;
|
|
}
|
|
g_signal_emit (daemon, signals[SIGNAL_DEVICE_CHANGED], 0, object_path);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* up_daemon_device_added_cb:
|
|
**/
|
|
static void
|
|
up_daemon_device_added_cb (UpBackend *backend, GObject *native, UpDevice *device, UpDaemon *daemon)
|
|
{
|
|
UpDeviceKind type;
|
|
const gchar *object_path;
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
|
|
g_return_if_fail (UP_IS_DAEMON (daemon));
|
|
g_return_if_fail (UP_IS_DEVICE (device));
|
|
g_return_if_fail (G_IS_OBJECT (native));
|
|
|
|
/* add to device list */
|
|
up_device_list_insert (priv->power_devices, native, G_OBJECT (device));
|
|
|
|
/* connect, so we get changes */
|
|
g_signal_connect (device, "changed",
|
|
G_CALLBACK (up_daemon_device_changed_cb), daemon);
|
|
|
|
/* refresh after a short delay */
|
|
g_object_get (device,
|
|
"type", &type,
|
|
NULL);
|
|
if (type == UP_DEVICE_KIND_BATTERY)
|
|
up_daemon_poll_battery_devices_for_a_little_bit (daemon);
|
|
|
|
/* emit */
|
|
if (!priv->during_coldplug) {
|
|
object_path = up_device_get_object_path (device);
|
|
g_debug ("emitting added: %s (during coldplug %i)", object_path, priv->during_coldplug);
|
|
|
|
/* don't crash the session */
|
|
if (object_path == NULL) {
|
|
g_warning ("INTERNAL STATE CORRUPT: not sending NULL, native:%p, device:%p", native, device);
|
|
return;
|
|
}
|
|
g_signal_emit (daemon, signals[SIGNAL_DEVICE_ADDED], 0, object_path);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* up_daemon_device_removed_cb:
|
|
**/
|
|
static void
|
|
up_daemon_device_removed_cb (UpBackend *backend, GObject *native, UpDevice *device, UpDaemon *daemon)
|
|
{
|
|
UpDeviceKind type;
|
|
const gchar *object_path;
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
|
|
g_return_if_fail (UP_IS_DAEMON (daemon));
|
|
g_return_if_fail (UP_IS_DEVICE (device));
|
|
g_return_if_fail (G_IS_OBJECT (native));
|
|
|
|
/* remove from list */
|
|
up_device_list_remove (priv->power_devices, G_OBJECT(device));
|
|
|
|
/* refresh after a short delay */
|
|
g_object_get (device,
|
|
"type", &type,
|
|
NULL);
|
|
if (type == UP_DEVICE_KIND_BATTERY)
|
|
up_daemon_poll_battery_devices_for_a_little_bit (daemon);
|
|
|
|
/* emit */
|
|
if (!priv->during_coldplug) {
|
|
object_path = up_device_get_object_path (device);
|
|
g_debug ("emitting device-removed: %s", object_path);
|
|
|
|
/* don't crash the session */
|
|
if (object_path == NULL) {
|
|
g_warning ("INTERNAL STATE CORRUPT: not sending NULL, native:%p, device:%p", native, device);
|
|
return;
|
|
}
|
|
g_signal_emit (daemon, signals[SIGNAL_DEVICE_REMOVED], 0, object_path);
|
|
}
|
|
|
|
/* finalise the object */
|
|
g_object_unref (device);
|
|
}
|
|
|
|
/**
|
|
* up_daemon_properties_changed_cb:
|
|
**/
|
|
static void
|
|
up_daemon_properties_changed_cb (GObject *object, GParamSpec *pspec, UpDaemon *daemon)
|
|
{
|
|
g_return_if_fail (UP_IS_DAEMON (daemon));
|
|
|
|
/* emit */
|
|
if (!daemon->priv->during_coldplug) {
|
|
g_debug ("emitting changed");
|
|
g_signal_emit (daemon, signals[SIGNAL_CHANGED], 0);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* up_daemon_init:
|
|
**/
|
|
static void
|
|
up_daemon_init (UpDaemon *daemon)
|
|
{
|
|
gboolean ret;
|
|
GError *error = NULL;
|
|
GKeyFile *file;
|
|
const gchar *filename_self_test;
|
|
gchar *filename;
|
|
|
|
daemon->priv = UP_DAEMON_GET_PRIVATE (daemon);
|
|
daemon->priv->polkit = up_polkit_new ();
|
|
daemon->priv->config = up_config_new ();
|
|
daemon->priv->lid_is_present = FALSE;
|
|
daemon->priv->is_docked = FALSE;
|
|
daemon->priv->lid_is_closed = FALSE;
|
|
daemon->priv->kernel_can_suspend = FALSE;
|
|
daemon->priv->kernel_can_hibernate = FALSE;
|
|
daemon->priv->hibernate_has_encrypted_swap = FALSE;
|
|
daemon->priv->power_devices = up_device_list_new ();
|
|
daemon->priv->on_battery = FALSE;
|
|
daemon->priv->on_low_battery = FALSE;
|
|
daemon->priv->during_coldplug = FALSE;
|
|
daemon->priv->sent_sleeping_signal = FALSE;
|
|
daemon->priv->battery_poll_id = 0;
|
|
daemon->priv->battery_poll_count = 0;
|
|
daemon->priv->about_to_sleep_id = 0;
|
|
daemon->priv->conf_sleep_timeout = 1000;
|
|
daemon->priv->conf_allow_hibernate_encrypted_swap = FALSE;
|
|
daemon->priv->conf_run_powersave_command = TRUE;
|
|
|
|
/* load some values from the config file */
|
|
file = g_key_file_new ();
|
|
filename_self_test = g_getenv ("UPOWER_CONF_FILE_NAME");
|
|
if (filename_self_test != NULL) {
|
|
g_debug ("using %s as the self test conf file", filename_self_test);
|
|
filename = g_strdup (filename_self_test);
|
|
} else {
|
|
filename = g_build_filename (PACKAGE_SYSCONF_DIR,"UPower", "UPower.conf", NULL);
|
|
}
|
|
ret = g_key_file_load_from_file (file, filename, G_KEY_FILE_NONE, &error);
|
|
if (ret) {
|
|
daemon->priv->conf_sleep_timeout =
|
|
g_key_file_get_integer (file, "UPower", "SleepTimeout", NULL);
|
|
daemon->priv->conf_allow_hibernate_encrypted_swap =
|
|
g_key_file_get_boolean (file, "UPower", "AllowHibernateEncryptedSwap", NULL);
|
|
daemon->priv->conf_run_powersave_command =
|
|
g_key_file_get_boolean (file, "UPower", "RunPowersaveCommand", NULL);
|
|
} else {
|
|
g_warning ("failed to load config file %s: %s", filename, error->message);
|
|
g_error_free (error);
|
|
}
|
|
g_key_file_free (file);
|
|
g_free (filename);
|
|
|
|
daemon->priv->backend = up_backend_new ();
|
|
g_signal_connect (daemon->priv->backend, "device-added",
|
|
G_CALLBACK (up_daemon_device_added_cb), daemon);
|
|
g_signal_connect (daemon->priv->backend, "device-removed",
|
|
G_CALLBACK (up_daemon_device_removed_cb), daemon);
|
|
|
|
/* use a timer for the about-to-sleep logic */
|
|
daemon->priv->about_to_sleep_timer = g_timer_new ();
|
|
g_timer_stop (daemon->priv->about_to_sleep_timer);
|
|
|
|
/* watch when these properties change */
|
|
g_signal_connect (daemon, "notify::lid-is-present",
|
|
G_CALLBACK (up_daemon_properties_changed_cb), daemon);
|
|
g_signal_connect (daemon, "notify::lid-is-closed",
|
|
G_CALLBACK (up_daemon_properties_changed_cb), daemon);
|
|
g_signal_connect (daemon, "notify::on-battery",
|
|
G_CALLBACK (up_daemon_properties_changed_cb), daemon);
|
|
g_signal_connect (daemon, "notify::on-low-battery",
|
|
G_CALLBACK (up_daemon_properties_changed_cb), daemon);
|
|
|
|
/* check if we have support */
|
|
daemon->priv->kernel_can_suspend = up_backend_kernel_can_suspend (daemon->priv->backend);
|
|
daemon->priv->kernel_can_hibernate = up_backend_kernel_can_hibernate (daemon->priv->backend);
|
|
|
|
/* is the swap usable? */
|
|
if (daemon->priv->kernel_can_hibernate)
|
|
daemon->priv->hibernate_has_encrypted_swap = up_backend_has_encrypted_swap (daemon->priv->backend);
|
|
}
|
|
|
|
/**
|
|
* up_daemon_error_quark:
|
|
**/
|
|
GQuark
|
|
up_daemon_error_quark (void)
|
|
{
|
|
static GQuark ret = 0;
|
|
if (ret == 0)
|
|
ret = g_quark_from_static_string ("up_daemon_error");
|
|
return ret;
|
|
}
|
|
|
|
#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
|
|
/**
|
|
* up_daemon_error_get_type:
|
|
**/
|
|
GType
|
|
up_daemon_error_get_type (void)
|
|
{
|
|
static GType etype = 0;
|
|
|
|
if (etype == 0) {
|
|
static const GEnumValue values[] = {
|
|
ENUM_ENTRY (UP_DAEMON_ERROR_GENERAL, "GeneralError"),
|
|
ENUM_ENTRY (UP_DAEMON_ERROR_NOT_SUPPORTED, "NotSupported"),
|
|
ENUM_ENTRY (UP_DAEMON_ERROR_NO_SUCH_DEVICE, "NoSuchDevice"),
|
|
{ 0, 0, 0 }
|
|
};
|
|
g_assert (UP_DAEMON_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
|
|
etype = g_enum_register_static ("UpDaemonError", values);
|
|
}
|
|
return etype;
|
|
}
|
|
|
|
/**
|
|
* up_daemon_get_property:
|
|
**/
|
|
static void
|
|
up_daemon_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
|
{
|
|
UpDaemon *daemon = UP_DAEMON (object);
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
|
|
switch (prop_id) {
|
|
case PROP_DAEMON_VERSION:
|
|
g_value_set_string (value, PACKAGE_VERSION);
|
|
break;
|
|
case PROP_CAN_SUSPEND:
|
|
g_value_set_boolean (value, priv->kernel_can_suspend);
|
|
break;
|
|
case PROP_CAN_HIBERNATE:
|
|
g_value_set_boolean (value, (priv->kernel_can_hibernate &&
|
|
up_daemon_check_hibernate_swap (daemon) &&
|
|
(!priv->hibernate_has_encrypted_swap ||
|
|
priv->conf_allow_hibernate_encrypted_swap)));
|
|
break;
|
|
case PROP_ON_BATTERY:
|
|
g_value_set_boolean (value, priv->on_battery);
|
|
break;
|
|
case PROP_ON_LOW_BATTERY:
|
|
g_value_set_boolean (value, priv->on_battery && priv->on_low_battery);
|
|
break;
|
|
case PROP_LID_IS_CLOSED:
|
|
g_value_set_boolean (value, priv->lid_is_closed);
|
|
break;
|
|
case PROP_LID_IS_PRESENT:
|
|
g_value_set_boolean (value, priv->lid_is_present);
|
|
break;
|
|
case PROP_LID_FORCE_SLEEP:
|
|
g_value_set_boolean (value, priv->lid_force_sleep);
|
|
break;
|
|
case PROP_IS_DOCKED:
|
|
g_value_set_boolean (value, priv->is_docked);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* up_daemon_set_property:
|
|
**/
|
|
static void
|
|
up_daemon_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
|
|
{
|
|
switch (prop_id) {
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* up_daemon_class_init:
|
|
**/
|
|
static void
|
|
up_daemon_class_init (UpDaemonClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
object_class->finalize = up_daemon_finalize;
|
|
object_class->get_property = up_daemon_get_property;
|
|
object_class->set_property = up_daemon_set_property;
|
|
|
|
g_type_class_add_private (klass, sizeof (UpDaemonPrivate));
|
|
|
|
signals[SIGNAL_DEVICE_ADDED] =
|
|
g_signal_new ("device-added",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
|
|
0, NULL, NULL,
|
|
g_cclosure_marshal_VOID__STRING,
|
|
G_TYPE_NONE, 1, G_TYPE_STRING);
|
|
|
|
signals[SIGNAL_DEVICE_REMOVED] =
|
|
g_signal_new ("device-removed",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
|
|
0, NULL, NULL,
|
|
g_cclosure_marshal_VOID__STRING,
|
|
G_TYPE_NONE, 1, G_TYPE_STRING);
|
|
|
|
signals[SIGNAL_DEVICE_CHANGED] =
|
|
g_signal_new ("device-changed",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
|
|
0, NULL, NULL,
|
|
g_cclosure_marshal_VOID__STRING,
|
|
G_TYPE_NONE, 1, G_TYPE_STRING);
|
|
|
|
signals[SIGNAL_CHANGED] =
|
|
g_signal_new ("changed",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
|
|
0, NULL, NULL,
|
|
g_cclosure_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
|
|
signals[SIGNAL_SLEEPING] =
|
|
g_signal_new ("sleeping",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
|
|
0, NULL, NULL,
|
|
g_cclosure_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
|
|
signals[SIGNAL_NOTIFY_SLEEP] =
|
|
g_signal_new ("notify-sleep",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
|
|
0, NULL, NULL,
|
|
g_cclosure_marshal_VOID__STRING,
|
|
G_TYPE_NONE, 1, G_TYPE_STRING);
|
|
|
|
signals[SIGNAL_RESUMING] =
|
|
g_signal_new ("resuming",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
|
|
0, NULL, NULL,
|
|
g_cclosure_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
|
|
signals[SIGNAL_NOTIFY_RESUME] =
|
|
g_signal_new ("notify-resume",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
|
|
0, NULL, NULL,
|
|
g_cclosure_marshal_VOID__STRING,
|
|
G_TYPE_NONE, 1, G_TYPE_STRING);
|
|
|
|
g_object_class_install_property (object_class,
|
|
PROP_DAEMON_VERSION,
|
|
g_param_spec_string ("daemon-version",
|
|
"Daemon Version",
|
|
"The version of the running daemon",
|
|
NULL,
|
|
G_PARAM_READABLE));
|
|
|
|
g_object_class_install_property (object_class,
|
|
PROP_LID_IS_PRESENT,
|
|
g_param_spec_boolean ("lid-is-present",
|
|
"Is a laptop",
|
|
"If this computer is probably a laptop",
|
|
FALSE,
|
|
G_PARAM_READABLE));
|
|
|
|
g_object_class_install_property (object_class,
|
|
PROP_LID_FORCE_SLEEP,
|
|
g_param_spec_boolean ("lid-force-sleep",
|
|
"Enforce sleep on lid close",
|
|
"If this computer has to sleep on lid close",
|
|
FALSE,
|
|
G_PARAM_READABLE));
|
|
|
|
g_object_class_install_property (object_class,
|
|
PROP_IS_DOCKED,
|
|
g_param_spec_boolean ("is-docked",
|
|
"Is docked",
|
|
"If this computer is docked",
|
|
FALSE,
|
|
G_PARAM_READABLE));
|
|
|
|
g_object_class_install_property (object_class,
|
|
PROP_CAN_SUSPEND,
|
|
g_param_spec_boolean ("can-suspend",
|
|
"Can Suspend",
|
|
"Whether the system can suspend",
|
|
FALSE,
|
|
G_PARAM_READABLE));
|
|
|
|
g_object_class_install_property (object_class,
|
|
PROP_CAN_HIBERNATE,
|
|
g_param_spec_boolean ("can-hibernate",
|
|
"Can Hibernate",
|
|
"Whether the system can hibernate",
|
|
FALSE,
|
|
G_PARAM_READABLE));
|
|
|
|
g_object_class_install_property (object_class,
|
|
PROP_ON_BATTERY,
|
|
g_param_spec_boolean ("on-battery",
|
|
"On Battery",
|
|
"Whether the system is running on battery",
|
|
FALSE,
|
|
G_PARAM_READABLE));
|
|
|
|
g_object_class_install_property (object_class,
|
|
PROP_ON_LOW_BATTERY,
|
|
g_param_spec_boolean ("on-low-battery",
|
|
"On Low Battery",
|
|
"Whether the system is running on battery and if the battery is critically low",
|
|
FALSE,
|
|
G_PARAM_READABLE));
|
|
|
|
g_object_class_install_property (object_class,
|
|
PROP_LID_IS_CLOSED,
|
|
g_param_spec_boolean ("lid-is-closed",
|
|
"Laptop lid is closed",
|
|
"If the laptop lid is closed",
|
|
FALSE,
|
|
G_PARAM_READABLE));
|
|
|
|
dbus_g_object_type_install_info (UP_TYPE_DAEMON, &dbus_glib_up_daemon_object_info);
|
|
|
|
dbus_g_error_domain_register (UP_DAEMON_ERROR, NULL, UP_DAEMON_TYPE_ERROR);
|
|
}
|
|
|
|
/**
|
|
* up_daemon_finalize:
|
|
**/
|
|
static void
|
|
up_daemon_finalize (GObject *object)
|
|
{
|
|
UpDaemon *daemon = UP_DAEMON (object);
|
|
UpDaemonPrivate *priv = daemon->priv;
|
|
|
|
if (priv->battery_poll_id != 0)
|
|
g_source_remove (priv->battery_poll_id);
|
|
|
|
if (priv->proxy != NULL)
|
|
g_object_unref (priv->proxy);
|
|
if (priv->connection != NULL)
|
|
dbus_g_connection_unref (priv->connection);
|
|
g_object_unref (priv->power_devices);
|
|
g_object_unref (priv->polkit);
|
|
g_object_unref (priv->config);
|
|
g_object_unref (priv->backend);
|
|
g_timer_destroy (priv->about_to_sleep_timer);
|
|
|
|
G_OBJECT_CLASS (up_daemon_parent_class)->finalize (object);
|
|
}
|
|
|
|
/**
|
|
* up_daemon_new:
|
|
**/
|
|
UpDaemon *
|
|
up_daemon_new (void)
|
|
{
|
|
UpDaemon *daemon;
|
|
daemon = UP_DAEMON (g_object_new (UP_TYPE_DAEMON, NULL));
|
|
return daemon;
|
|
}
|
|
|