1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
4 * Copyright (C) 2011 Richard Hughes <richard@hughsie.com>
5 * Copyright (C) 2011 Ritesh Khadgaray <khadgaray@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA.
20 *
21 */
22
23 #include "config.h"
24
25 #include <fcntl.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <sys/wait.h>
31 #include <glib/gi18n.h>
32 #include <gdk/gdkx.h>
33 #include <gtk/gtk.h>
34 #include <libupower-glib/upower.h>
35 #include <libnotify/notify.h>
36 #include <canberra-gtk.h>
37 #include <gio/gunixfdlist.h>
38
39 #include <X11/extensions/dpms.h>
40
41 #define GNOME_DESKTOP_USE_UNSTABLE_API
42 #include <libcinnamon-desktop/gnome-rr.h>
43
44 #include "gpm-common.h"
45 #include "gpm-phone.h"
46 #include "gpm-idletime.h"
47 #include "cinnamon-settings-profile.h"
48 #include "cinnamon-settings-session.h"
49 #include "csd-enums.h"
50 #include "csd-power-manager.h"
51 #include "csd-power-helper.h"
52 #include "csd-power-proxy.h"
53 #include "csd-power-screen-proxy.h"
54 #include "csd-power-keyboard-proxy.h"
55
56 #define GNOME_SESSION_DBUS_NAME "org.gnome.SessionManager"
57 #define GNOME_SESSION_DBUS_PATH "/org/gnome/SessionManager"
58 #define GNOME_SESSION_DBUS_PATH_PRESENCE "/org/gnome/SessionManager/Presence"
59 #define GNOME_SESSION_DBUS_INTERFACE "org.gnome.SessionManager"
60 #define GNOME_SESSION_DBUS_INTERFACE_PRESENCE "org.gnome.SessionManager.Presence"
61
62 #define UPOWER_DBUS_NAME "org.freedesktop.UPower"
63 #define UPOWER_DBUS_PATH_KBDBACKLIGHT "/org/freedesktop/UPower/KbdBacklight"
64 #define UPOWER_DBUS_INTERFACE_KBDBACKLIGHT "org.freedesktop.UPower.KbdBacklight"
65
66 #define CSD_POWER_SETTINGS_SCHEMA "org.cinnamon.settings-daemon.plugins.power"
67 #define CSD_XRANDR_SETTINGS_SCHEMA "org.cinnamon.settings-daemon.plugins.xrandr"
68 #define CSD_SAVER_SETTINGS_SCHEMA "org.cinnamon.desktop.screensaver"
69 #define CSD_SESSION_SETTINGS_SCHEMA "org.cinnamon.desktop.session"
70 #define CSD_CINNAMON_SESSION_SCHEMA "org.cinnamon.SessionManager"
71
72 #define CSD_POWER_DBUS_PATH "/org/cinnamon/SettingsDaemon/Power"
73 #define CSD_POWER_DBUS_INTERFACE "org.cinnamon.SettingsDaemon.Power"
74 #define CSD_POWER_DBUS_INTERFACE_SCREEN "org.cinnamon.SettingsDaemon.Power.Screen"
75 #define CSD_POWER_DBUS_INTERFACE_KEYBOARD "org.cinnamon.SettingsDaemon.Power.Keyboard"
76
77 #define GS_DBUS_NAME "org.cinnamon.ScreenSaver"
78 #define GS_DBUS_PATH "/org/cinnamon/ScreenSaver"
79 #define GS_DBUS_INTERFACE "org.cinnamon.ScreenSaver"
80
81 #define CSD_POWER_MANAGER_NOTIFY_TIMEOUT_NEVER 0 /* ms */
82 #define CSD_POWER_MANAGER_NOTIFY_TIMEOUT_SHORT 10 * 1000 /* ms */
83 #define CSD_POWER_MANAGER_NOTIFY_TIMEOUT_LONG 30 * 1000 /* ms */
84
85 #define CSD_POWER_MANAGER_CRITICAL_ALERT_TIMEOUT 5 /* seconds */
86 #define CSD_POWER_MANAGER_LID_CLOSE_SAFETY_TIMEOUT 30 /* seconds */
87
88 #define LOGIND_DBUS_NAME "org.freedesktop.login1"
89 #define LOGIND_DBUS_PATH "/org/freedesktop/login1"
90 #define LOGIND_DBUS_INTERFACE "org.freedesktop.login1.Manager"
91
92 /* Keep this in sync with gnome-shell */
93 #define SCREENSAVER_FADE_TIME 10 /* seconds */
94
95 #define XSCREENSAVER_WATCHDOG_TIMEOUT 120 /* seconds */
96
97 enum {
98 CSD_POWER_IDLETIME_NULL_ID,
99 CSD_POWER_IDLETIME_DIM_ID,
100 CSD_POWER_IDLETIME_LOCK_ID,
101 CSD_POWER_IDLETIME_BLANK_ID,
102 CSD_POWER_IDLETIME_SLEEP_ID
103 };
104
105 /* on ACPI machines we have 4-16 levels, on others it's ~150 */
106 #define BRIGHTNESS_STEP_AMOUNT(max) ((max) < 20 ? 1 : (max) / 20)
107
108 /* take a discrete value with offset and convert to percentage */
109 static int
abs_to_percentage(int min,int max,int value)110 abs_to_percentage (int min, int max, int value)
111 {
112 g_return_val_if_fail (max > min, -1);
113 g_return_val_if_fail (value >= min, -1);
114 g_return_val_if_fail (value <= max, -1);
115 return (((value - min) * 100) / (max - min));
116 }
117 #define ABS_TO_PERCENTAGE(min, max, value) abs_to_percentage(min, max, value)
118 #define PERCENTAGE_TO_ABS(min, max, value) (min + (((max - min) * value) / 100))
119
120 #define CSD_POWER_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_POWER_MANAGER, CsdPowerManagerPrivate))
121
122 typedef enum {
123 CSD_POWER_IDLE_MODE_NORMAL,
124 CSD_POWER_IDLE_MODE_DIM,
125 CSD_POWER_IDLE_MODE_BLANK,
126 CSD_POWER_IDLE_MODE_SLEEP
127 } CsdPowerIdleMode;
128
129 struct CsdPowerManagerPrivate
130 {
131 CinnamonSettingsSession *session;
132 guint p_name_id;
133 guint s_name_id;
134 guint k_name_id;
135 CsdPower *power_iface;
136 CsdScreen *screen_iface;
137 CsdKeyboard *keyboard_iface;
138 gboolean lid_is_closed;
139 gboolean on_battery;
140 GSettings *settings;
141 GSettings *settings_screensaver;
142 GSettings *settings_xrandr;
143 GSettings *settings_desktop_session;
144 GSettings *settings_cinnamon_session;
145 UpClient *up_client;
146 GDBusConnection *connection;
147 GCancellable *bus_cancellable;
148 GDBusProxy *upower_kbd_proxy;
149 gboolean backlight_helper_force;
150 gchar* backlight_helper_preference_args;
151 gint kbd_brightness_now;
152 gint kbd_brightness_max;
153 gint kbd_brightness_old;
154 gint kbd_brightness_pre_dim;
155 GnomeRRScreen *x11_screen;
156 gboolean use_time_primary;
157 gchar *previous_summary;
158 GIcon *previous_icon;
159 GpmPhone *phone;
160 GPtrArray *devices_array;
161 guint action_percentage;
162 guint action_time;
163 guint critical_percentage;
164 guint critical_time;
165 guint low_percentage;
166 guint low_time;
167 gint pre_dim_brightness; /* level, not percentage */
168 UpDevice *device_composite;
169 NotifyNotification *notification_discharging;
170 NotifyNotification *notification_low;
171 ca_context *canberra_context;
172 ca_proplist *critical_alert_loop_props;
173 guint32 critical_alert_timeout_id;
174 GDBusProxy *screensaver_proxy;
175 GDBusProxy *session_proxy;
176 GDBusProxy *session_presence_proxy;
177 GpmIdletime *idletime;
178 CsdPowerIdleMode current_idle_mode;
179 guint lid_close_safety_timer_id;
180 GtkStatusIcon *status_icon;
181 guint xscreensaver_watchdog_timer_id;
182 gboolean is_virtual_machine;
183 gint fd_close_loop_end;
184
185 /* logind stuff */
186 GDBusProxy *logind_proxy;
187 gboolean inhibit_lid_switch_enabled;
188 gint inhibit_lid_switch_fd;
189 gboolean inhibit_lid_switch_taken;
190 gint inhibit_suspend_fd;
191 gboolean inhibit_suspend_taken;
192 guint inhibit_lid_switch_timer_id;
193 };
194
195 enum {
196 PROP_0,
197 };
198
199 static void csd_power_manager_finalize (GObject *object);
200
201 static UpDevice *engine_get_composite_device (CsdPowerManager *manager, UpDevice *original_device);
202 static UpDevice *engine_update_composite_device (CsdPowerManager *manager, UpDevice *original_device);
203 static GIcon *engine_get_icon (CsdPowerManager *manager);
204 static gchar *engine_get_summary (CsdPowerManager *manager);
205
206 static gboolean external_monitor_is_connected (GnomeRRScreen *screen);
207 static void do_power_action_type (CsdPowerManager *manager, CsdPowerActionType action_type);
208 static void do_lid_closed_action (CsdPowerManager *manager);
209 static void inhibit_lid_switch (CsdPowerManager *manager);
210 static void uninhibit_lid_switch (CsdPowerManager *manager);
211 static void setup_locker_process (gpointer user_data);
212 static void lock_screen_with_custom_saver (CsdPowerManager *manager, gchar *custom_saver, gboolean idle_lock);
213 static void lock_screensaver (CsdPowerManager *manager);
214 static void kill_lid_close_safety_timer (CsdPowerManager *manager);
215
216 int backlight_get_output_id (CsdPowerManager *manager);
217
218 #if UP_CHECK_VERSION(0,99,0)
219 static void device_properties_changed_cb (UpDevice *device, GParamSpec *pspec, CsdPowerManager *manager);
220 #endif
221
222 G_DEFINE_TYPE (CsdPowerManager, csd_power_manager, G_TYPE_OBJECT)
223
224 static gpointer manager_object = NULL;
225
226 GQuark
csd_power_manager_error_quark(void)227 csd_power_manager_error_quark (void)
228 {
229 static GQuark quark = 0;
230 if (!quark)
231 quark = g_quark_from_static_string ("csd_power_manager_error");
232 return quark;
233 }
234
235 static gboolean
play_loop_timeout_cb(CsdPowerManager * manager)236 play_loop_timeout_cb (CsdPowerManager *manager)
237 {
238 ca_context *context;
239 context = ca_gtk_context_get_for_screen (gdk_screen_get_default ());
240 ca_context_play_full (context, 0,
241 manager->priv->critical_alert_loop_props,
242 NULL,
243 NULL);
244 return TRUE;
245 }
246
247 static gboolean
play_loop_stop(CsdPowerManager * manager)248 play_loop_stop (CsdPowerManager *manager)
249 {
250 if (manager->priv->critical_alert_timeout_id == 0) {
251 g_warning ("no sound loop present to stop");
252 return FALSE;
253 }
254
255 if (manager->priv->critical_alert_timeout_id) {
256 g_source_remove (manager->priv->critical_alert_timeout_id);
257 manager->priv->critical_alert_timeout_id = 0;
258 }
259
260 ca_proplist_destroy (manager->priv->critical_alert_loop_props);
261
262 manager->priv->critical_alert_loop_props = NULL;
263 manager->priv->critical_alert_timeout_id = 0;
264
265 return TRUE;
266 }
267
268 static gboolean
play_loop_start(CsdPowerManager * manager,const gchar * id,const gchar * desc,gboolean force,guint timeout)269 play_loop_start (CsdPowerManager *manager,
270 const gchar *id,
271 const gchar *desc,
272 gboolean force,
273 guint timeout)
274 {
275 ca_context *context;
276
277 if (timeout == 0) {
278 g_warning ("received invalid timeout");
279 return FALSE;
280 }
281
282 /* if a sound loop is already running, stop the existing loop */
283 if (manager->priv->critical_alert_timeout_id != 0) {
284 g_warning ("was instructed to play a sound loop with one already playing");
285 play_loop_stop (manager);
286 }
287
288 ca_proplist_create (&(manager->priv->critical_alert_loop_props));
289 ca_proplist_sets (manager->priv->critical_alert_loop_props,
290 CA_PROP_EVENT_ID, id);
291 ca_proplist_sets (manager->priv->critical_alert_loop_props,
292 CA_PROP_EVENT_DESCRIPTION, desc);
293
294 manager->priv->critical_alert_timeout_id = g_timeout_add_seconds (timeout,
295 (GSourceFunc) play_loop_timeout_cb,
296 manager);
297 g_source_set_name_by_id (manager->priv->critical_alert_timeout_id,
298 "[CsdPowerManager] play-loop");
299
300 /* play the sound, using sounds from the naming spec */
301 context = ca_gtk_context_get_for_screen (gdk_screen_get_default ());
302 ca_context_play (context, 0,
303 CA_PROP_EVENT_ID, id,
304 CA_PROP_EVENT_DESCRIPTION, desc, NULL);
305 return TRUE;
306 }
307
308 static gboolean
should_lock_on_suspend(CsdPowerManager * manager)309 should_lock_on_suspend (CsdPowerManager *manager)
310 {
311 gboolean lock;
312
313 lock = g_settings_get_boolean (manager->priv->settings,
314 "lock-on-suspend");
315
316 return lock;
317 }
318
319 static void
notify_close_if_showing(NotifyNotification * notification)320 notify_close_if_showing (NotifyNotification *notification)
321 {
322 gboolean ret;
323 GError *error = NULL;
324
325 if (notification == NULL)
326 return;
327 ret = notify_notification_close (notification, &error);
328 if (!ret) {
329 g_warning ("failed to close notification: %s",
330 error->message);
331 g_error_free (error);
332 }
333 }
334
335 static const gchar *
get_first_themed_icon_name(GIcon * icon)336 get_first_themed_icon_name (GIcon *icon)
337 {
338 const gchar* const *icon_names;
339 const gchar *icon_name = NULL;
340
341 /* no icon */
342 if (icon == NULL)
343 goto out;
344
345 /* just use the first icon */
346 icon_names = g_themed_icon_get_names (G_THEMED_ICON (icon));
347 if (icon_names != NULL)
348 icon_name = icon_names[0];
349 out:
350 return icon_name;
351 }
352
353 typedef enum {
354 WARNING_NONE = 0,
355 WARNING_DISCHARGING = 1,
356 WARNING_LOW = 2,
357 WARNING_CRITICAL = 3,
358 WARNING_ACTION = 4
359 } CsdPowerManagerWarning;
360
361 static void
engine_emit_changed(CsdPowerManager * manager,gboolean icon_changed,gboolean state_changed)362 engine_emit_changed (CsdPowerManager *manager,
363 gboolean icon_changed,
364 gboolean state_changed)
365 {
366 /* not yet connected to the bus */
367 if (manager->priv->power_iface == NULL)
368 return;
369
370 if (icon_changed) {
371 GIcon *gicon;
372 gchar *gicon_str;
373
374 gicon = engine_get_icon (manager);
375 gicon_str = g_icon_to_string (gicon);
376
377 csd_power_set_icon (manager->priv->power_iface, gicon_str);
378
379 g_free (gicon_str);
380 g_object_unref (gicon);
381 }
382
383 if (state_changed) {
384 gchar *tooltip;
385
386 tooltip = engine_get_summary (manager);
387
388 csd_power_set_tooltip (manager->priv->power_iface, tooltip);
389
390 g_free (tooltip);
391 }
392 }
393
394 static CsdPowerManagerWarning
engine_get_warning_csr(CsdPowerManager * manager,UpDevice * device)395 engine_get_warning_csr (CsdPowerManager *manager, UpDevice *device)
396 {
397 gdouble percentage;
398
399 /* get device properties */
400 g_object_get (device, "percentage", &percentage, NULL);
401
402 if (percentage < 26.0f)
403 return WARNING_LOW;
404 else if (percentage < 13.0f)
405 return WARNING_CRITICAL;
406 return WARNING_NONE;
407 }
408
409 static CsdPowerManagerWarning
engine_get_warning_percentage(CsdPowerManager * manager,UpDevice * device)410 engine_get_warning_percentage (CsdPowerManager *manager, UpDevice *device)
411 {
412 gdouble percentage;
413
414 /* get device properties */
415 g_object_get (device, "percentage", &percentage, NULL);
416
417 if (percentage <= manager->priv->action_percentage)
418 return WARNING_ACTION;
419 if (percentage <= manager->priv->critical_percentage)
420 return WARNING_CRITICAL;
421 if (percentage <= manager->priv->low_percentage)
422 return WARNING_LOW;
423 return WARNING_NONE;
424 }
425
426 static CsdPowerManagerWarning
engine_get_warning_time(CsdPowerManager * manager,UpDevice * device)427 engine_get_warning_time (CsdPowerManager *manager, UpDevice *device)
428 {
429 UpDeviceKind kind;
430 gint64 time_to_empty;
431
432 /* get device properties */
433 g_object_get (device,
434 "kind", &kind,
435 "time-to-empty", &time_to_empty,
436 NULL);
437
438 /* this is probably an error condition */
439 if (time_to_empty == 0) {
440 g_debug ("time zero, falling back to percentage for %s",
441 up_device_kind_to_string (kind));
442 return engine_get_warning_percentage (manager, device);
443 }
444
445 if (time_to_empty <= manager->priv->action_time)
446 return WARNING_ACTION;
447 if (time_to_empty <= manager->priv->critical_time)
448 return WARNING_CRITICAL;
449 if (time_to_empty <= manager->priv->low_time)
450 return WARNING_LOW;
451 return WARNING_NONE;
452 }
453
454 /**
455 * This gets the possible engine state for the device according to the
456 * policy, which could be per-percent, or per-time.
457 **/
458 static CsdPowerManagerWarning
engine_get_warning(CsdPowerManager * manager,UpDevice * device)459 engine_get_warning (CsdPowerManager *manager, UpDevice *device)
460 {
461 UpDeviceKind kind;
462 UpDeviceState state;
463 CsdPowerManagerWarning warning_type;
464
465 /* get device properties */
466 g_object_get (device,
467 "kind", &kind,
468 "state", &state,
469 NULL);
470
471 /* default to no engine */
472 warning_type = WARNING_NONE;
473
474 /* if the device in question is on ac, don't give a warning */
475 if (state == UP_DEVICE_STATE_CHARGING)
476 goto out;
477
478 if (kind == UP_DEVICE_KIND_MOUSE ||
479 kind == UP_DEVICE_KIND_KEYBOARD) {
480
481 warning_type = engine_get_warning_csr (manager, device);
482
483 } else if (kind == UP_DEVICE_KIND_UPS ||
484 kind == UP_DEVICE_KIND_MEDIA_PLAYER ||
485 kind == UP_DEVICE_KIND_TABLET ||
486 kind == UP_DEVICE_KIND_COMPUTER ||
487 kind == UP_DEVICE_KIND_PDA) {
488
489 warning_type = engine_get_warning_percentage (manager, device);
490
491 } else if (kind == UP_DEVICE_KIND_PHONE) {
492
493 warning_type = engine_get_warning_percentage (manager, device);
494
495 } else if (kind == UP_DEVICE_KIND_BATTERY) {
496 /* only use the time when it is accurate, and settings is not disabled */
497 if (manager->priv->use_time_primary)
498 warning_type = engine_get_warning_time (manager, device);
499 else
500 warning_type = engine_get_warning_percentage (manager, device);
501 }
502
503 /* If we have no important engines, we should test for discharging */
504 if (warning_type == WARNING_NONE) {
505 if (state == UP_DEVICE_STATE_DISCHARGING)
506 warning_type = WARNING_DISCHARGING;
507 }
508
509 out:
510 return warning_type;
511 }
512
513 static gchar *
engine_get_summary(CsdPowerManager * manager)514 engine_get_summary (CsdPowerManager *manager)
515 {
516 guint i;
517 GPtrArray *array;
518 UpDevice *device;
519 UpDeviceState state;
520 GString *tooltip = NULL;
521 gchar *part;
522 gboolean is_present;
523
524
525 /* need to get AC state */
526 tooltip = g_string_new ("");
527
528 /* do we have specific device types? */
529 array = manager->priv->devices_array;
530 for (i=0;i<array->len;i++) {
531 device = g_ptr_array_index (array, i);
532 g_object_get (device,
533 "is-present", &is_present,
534 "state", &state,
535 NULL);
536 if (!is_present)
537 continue;
538 if (state == UP_DEVICE_STATE_EMPTY)
539 continue;
540 part = gpm_upower_get_device_summary (device);
541 if (part != NULL)
542 g_string_append_printf (tooltip, "%s\n", part);
543 g_free (part);
544 }
545
546 /* remove the last \n */
547 g_string_truncate (tooltip, tooltip->len-1);
548
549 g_debug ("tooltip: %s", tooltip->str);
550
551 return g_string_free (tooltip, FALSE);
552 }
553
554 static GIcon *
engine_get_icon_priv(CsdPowerManager * manager,UpDeviceKind device_kind,CsdPowerManagerWarning warning,gboolean use_state)555 engine_get_icon_priv (CsdPowerManager *manager,
556 UpDeviceKind device_kind,
557 CsdPowerManagerWarning warning,
558 gboolean use_state)
559 {
560 guint i;
561 GPtrArray *array;
562 UpDevice *device;
563 CsdPowerManagerWarning warning_temp;
564 UpDeviceKind kind;
565 UpDeviceState state;
566 gboolean is_present;
567
568 /* do we have specific device types? */
569 array = manager->priv->devices_array;
570 for (i=0;i<array->len;i++) {
571 device = g_ptr_array_index (array, i);
572
573 /* get device properties */
574 g_object_get (device,
575 "kind", &kind,
576 "state", &state,
577 "is-present", &is_present,
578 NULL);
579
580 /* if battery then use composite device to cope with multiple batteries */
581 if (kind == UP_DEVICE_KIND_BATTERY)
582 device = engine_get_composite_device (manager, device);
583
584 warning_temp = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(device),
585 "engine-warning-old"));
586 if (kind == device_kind && is_present) {
587 if (warning != WARNING_NONE) {
588 if (warning_temp == warning)
589 return gpm_upower_get_device_icon (device, TRUE);
590 continue;
591 }
592 if (use_state) {
593 if (state == UP_DEVICE_STATE_CHARGING ||
594 state == UP_DEVICE_STATE_DISCHARGING)
595 return gpm_upower_get_device_icon (device, TRUE);
596 continue;
597 }
598 return gpm_upower_get_device_icon (device, TRUE);
599 }
600 }
601 return NULL;
602 }
603
604 static GIcon *
engine_get_icon(CsdPowerManager * manager)605 engine_get_icon (CsdPowerManager *manager)
606 {
607 GIcon *icon = NULL;
608
609
610 /* we try CRITICAL: BATTERY, UPS, MOUSE, KEYBOARD */
611 icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_BATTERY, WARNING_CRITICAL, FALSE);
612 if (icon != NULL)
613 return icon;
614 icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_UPS, WARNING_CRITICAL, FALSE);
615 if (icon != NULL)
616 return icon;
617 icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_MOUSE, WARNING_CRITICAL, FALSE);
618 if (icon != NULL)
619 return icon;
620 icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_KEYBOARD, WARNING_CRITICAL, FALSE);
621 if (icon != NULL)
622 return icon;
623
624 /* we try CRITICAL: BATTERY, UPS, MOUSE, KEYBOARD */
625 icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_BATTERY, WARNING_LOW, FALSE);
626 if (icon != NULL)
627 return icon;
628 icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_UPS, WARNING_LOW, FALSE);
629 if (icon != NULL)
630 return icon;
631 icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_MOUSE, WARNING_LOW, FALSE);
632 if (icon != NULL)
633 return icon;
634 icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_KEYBOARD, WARNING_LOW, FALSE);
635 if (icon != NULL)
636 return icon;
637
638 /* we try (DIS)CHARGING: BATTERY, UPS */
639 icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_BATTERY, WARNING_NONE, TRUE);
640 if (icon != NULL)
641 return icon;
642 icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_UPS, WARNING_NONE, TRUE);
643 if (icon != NULL)
644 return icon;
645
646 /* we try PRESENT: BATTERY, UPS */
647 icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_BATTERY, WARNING_NONE, FALSE);
648 if (icon != NULL)
649 return icon;
650 icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_UPS, WARNING_NONE, FALSE);
651 if (icon != NULL)
652 return icon;
653
654 /* do not show an icon */
655 return NULL;
656 }
657
658 static gboolean
engine_recalculate_state_icon(CsdPowerManager * manager)659 engine_recalculate_state_icon (CsdPowerManager *manager)
660 {
661 GIcon *icon;
662
663 /* show a different icon if we are disconnected */
664 icon = engine_get_icon (manager);
665 gtk_status_icon_set_visible (manager->priv->status_icon, FALSE);
666
667 if (icon == NULL) {
668 /* none before, now none */
669 if (manager->priv->previous_icon == NULL)
670 return FALSE;
671
672 g_object_unref (manager->priv->previous_icon);
673 manager->priv->previous_icon = NULL;
674 return TRUE;
675 }
676
677 /* no icon before, now icon */
678 if (manager->priv->previous_icon == NULL) {
679
680 /* set fallback icon */
681 gtk_status_icon_set_visible (manager->priv->status_icon, FALSE);
682 gtk_status_icon_set_from_gicon (manager->priv->status_icon, icon);
683 manager->priv->previous_icon = icon;
684 return TRUE;
685 }
686
687 /* icon before, now different */
688 if (!g_icon_equal (manager->priv->previous_icon, icon)) {
689
690 /* set fallback icon */
691 gtk_status_icon_set_from_gicon (manager->priv->status_icon, icon);
692
693 g_object_unref (manager->priv->previous_icon);
694 manager->priv->previous_icon = icon;
695 return TRUE;
696 }
697
698 g_debug ("no change");
699 /* nothing to do */
700 g_object_unref (icon);
701 return FALSE;
702 }
703
704 static gboolean
engine_recalculate_state_summary(CsdPowerManager * manager)705 engine_recalculate_state_summary (CsdPowerManager *manager)
706 {
707 gchar *summary;
708
709 summary = engine_get_summary (manager);
710 if (manager->priv->previous_summary == NULL) {
711 manager->priv->previous_summary = summary;
712
713 /* set fallback tooltip */
714 gtk_status_icon_set_tooltip_text (manager->priv->status_icon,
715 summary);
716
717 return TRUE;
718 }
719
720 if (strcmp (manager->priv->previous_summary, summary) != 0) {
721 g_free (manager->priv->previous_summary);
722 manager->priv->previous_summary = summary;
723
724 /* set fallback tooltip */
725 gtk_status_icon_set_tooltip_text (manager->priv->status_icon,
726 summary);
727
728 return TRUE;
729 }
730 g_debug ("no change");
731 /* nothing to do */
732 g_free (summary);
733 return FALSE;
734 }
735
736 static void
engine_recalculate_state(CsdPowerManager * manager)737 engine_recalculate_state (CsdPowerManager *manager)
738 {
739 gboolean icon_changed = FALSE;
740 gboolean state_changed = FALSE;
741
742 icon_changed = engine_recalculate_state_icon (manager);
743 state_changed = engine_recalculate_state_summary (manager);
744
745 /* only emit if the icon or summary has changed */
746 if (icon_changed || state_changed)
747 engine_emit_changed (manager, icon_changed, state_changed);
748 }
749
750 static UpDevice *
engine_get_composite_device(CsdPowerManager * manager,UpDevice * original_device)751 engine_get_composite_device (CsdPowerManager *manager,
752 UpDevice *original_device)
753 {
754 guint battery_devices = 0;
755 GPtrArray *array;
756 UpDevice *device;
757 UpDeviceKind kind;
758 UpDeviceKind original_kind;
759 guint i;
760
761 /* get the type of the original device */
762 g_object_get (original_device,
763 "kind", &original_kind,
764 NULL);
765
766 /* find out how many batteries in the system */
767 array = manager->priv->devices_array;
768 for (i=0;i<array->len;i++) {
769 device = g_ptr_array_index (array, i);
770 g_object_get (device,
771 "kind", &kind,
772 NULL);
773 if (kind == original_kind)
774 battery_devices++;
775 }
776
777 /* just use the original device if only one primary battery */
778 if (battery_devices <= 1) {
779 g_debug ("using original device as only one primary battery");
780 device = original_device;
781 goto out;
782 }
783
784 /* use the composite device */
785 device = manager->priv->device_composite;
786 out:
787 /* return composite device or original device */
788 return device;
789 }
790
791 static UpDevice *
engine_update_composite_device(CsdPowerManager * manager,UpDevice * original_device)792 engine_update_composite_device (CsdPowerManager *manager,
793 UpDevice *original_device)
794 {
795 guint i;
796 gdouble percentage = 0.0;
797 gdouble energy = 0.0;
798 gdouble energy_full = 0.0;
799 gdouble energy_rate = 0.0;
800 gdouble energy_total = 0.0;
801 gdouble energy_full_total = 0.0;
802 gdouble energy_rate_total = 0.0;
803 gint64 time_to_empty = 0;
804 gint64 time_to_full = 0;
805 guint battery_devices = 0;
806 gboolean is_charging = FALSE;
807 gboolean is_discharging = FALSE;
808 gboolean is_fully_charged = TRUE;
809 GPtrArray *array;
810 UpDevice *device;
811 UpDeviceState state;
812 UpDeviceKind kind;
813 UpDeviceKind original_kind;
814
815 /* get the type of the original device */
816 g_object_get (original_device,
817 "kind", &original_kind,
818 NULL);
819
820 /* update the composite device */
821 array = manager->priv->devices_array;
822 for (i=0;i<array->len;i++) {
823 device = g_ptr_array_index (array, i);
824 g_object_get (device,
825 "kind", &kind,
826 "state", &state,
827 "energy", &energy,
828 "energy-full", &energy_full,
829 "energy-rate", &energy_rate,
830 NULL);
831 if (kind != original_kind)
832 continue;
833
834 /* one of these will be charging or discharging */
835 if (state == UP_DEVICE_STATE_CHARGING)
836 is_charging = TRUE;
837 if (state == UP_DEVICE_STATE_DISCHARGING)
838 is_discharging = TRUE;
839 if (state != UP_DEVICE_STATE_FULLY_CHARGED)
840 is_fully_charged = FALSE;
841
842 /* sum up composite */
843 energy_total += energy;
844 energy_full_total += energy_full;
845 energy_rate_total += energy_rate;
846 battery_devices++;
847 }
848
849 /* just use the original device if only one primary battery */
850 if (battery_devices == 1) {
851 g_debug ("using original device as only one primary battery");
852 device = original_device;
853 goto out;
854 }
855
856 /* use percentage weighted for each battery capacity */
857 if (energy_full_total > 0.0)
858 percentage = 100.0 * energy_total / energy_full_total;
859
860 /* set composite state */
861 if (is_charging)
862 state = UP_DEVICE_STATE_CHARGING;
863 else if (is_discharging)
864 state = UP_DEVICE_STATE_DISCHARGING;
865 else if (is_fully_charged)
866 state = UP_DEVICE_STATE_FULLY_CHARGED;
867 else
868 state = UP_DEVICE_STATE_UNKNOWN;
869
870 /* calculate a quick and dirty time remaining value */
871 if (energy_rate_total > 0) {
872 if (state == UP_DEVICE_STATE_DISCHARGING)
873 time_to_empty = 3600 * (energy_total / energy_rate_total);
874 else if (state == UP_DEVICE_STATE_CHARGING)
875 time_to_full = 3600 * ((energy_full_total - energy_total) / energy_rate_total);
876 }
877
878 /* okay, we can use the composite device */
879 device = manager->priv->device_composite;
880
881 g_debug ("printing composite device");
882 g_object_set (device,
883 "energy", energy,
884 "energy-full", energy_full,
885 "energy-rate", energy_rate,
886 "time-to-empty", time_to_empty,
887 "time-to-full", time_to_full,
888 "percentage", percentage,
889 "state", state,
890 NULL);
891
892 /* force update of icon */
893 if (engine_recalculate_state_icon (manager))
894 engine_emit_changed (manager, TRUE, FALSE);
895 out:
896 /* return composite device or original device */
897 return device;
898 }
899
900 static void
engine_device_add(CsdPowerManager * manager,UpDevice * device)901 engine_device_add (CsdPowerManager *manager, UpDevice *device)
902 {
903 CsdPowerManagerWarning warning;
904 UpDeviceState state;
905 UpDeviceKind kind;
906 UpDevice *composite;
907
908 /* assign warning */
909 warning = engine_get_warning (manager, device);
910 g_object_set_data (G_OBJECT(device),
911 "engine-warning-old",
912 GUINT_TO_POINTER(warning));
913
914 /* get device properties */
915 g_object_get (device,
916 "kind", &kind,
917 "state", &state,
918 NULL);
919
920 /* add old state for transitions */
921 g_debug ("adding %s with state %s",
922 up_device_get_object_path (device), up_device_state_to_string (state));
923 g_object_set_data (G_OBJECT(device),
924 "engine-state-old",
925 GUINT_TO_POINTER(state));
926
927 if (kind == UP_DEVICE_KIND_BATTERY) {
928 g_debug ("updating because we added a device");
929 composite = engine_update_composite_device (manager, device);
930
931 /* get the same values for the composite device */
932 warning = engine_get_warning (manager, composite);
933 g_object_set_data (G_OBJECT(composite),
934 "engine-warning-old",
935 GUINT_TO_POINTER(warning));
936 g_object_get (composite, "state", &state, NULL);
937 g_object_set_data (G_OBJECT(composite),
938 "engine-state-old",
939 GUINT_TO_POINTER(state));
940 }
941
942 #if UP_CHECK_VERSION(0,99,0)
943 g_ptr_array_add (manager->priv->devices_array, g_object_ref(device));
944
945 g_signal_connect (device, "notify",
946 G_CALLBACK (device_properties_changed_cb), manager);
947 #endif
948
949 }
950
951 static gboolean
engine_coldplug(CsdPowerManager * manager)952 engine_coldplug (CsdPowerManager *manager)
953 {
954 guint i;
955 GPtrArray *array = NULL;
956 UpDevice *device;
957 #if ! UP_CHECK_VERSION(0,99,0)
958 gboolean ret;
959 GError *error = NULL;
960
961 /* get devices from UPower */
962 ret = up_client_enumerate_devices_sync (manager->priv->up_client, NULL, &error);
963 if (!ret) {
964 g_warning ("failed to get device list: %s", error->message);
965 g_error_free (error);
966 goto out;
967 }
968 #endif
969
970 /* connected mobile phones */
971 gpm_phone_coldplug (manager->priv->phone);
972
973 engine_recalculate_state (manager);
974
975 /* add to database */
976 array = up_client_get_devices (manager->priv->up_client);
977 for (i = 0; array != NULL && i < array->len; i++) {
978 device = g_ptr_array_index (array, i);
979 engine_device_add (manager, device);
980 }
981 #if ! UP_CHECK_VERSION(0,99,0)
982 out:
983 #endif
984 if (array != NULL)
985 g_ptr_array_unref (array);
986 /* never repeat */
987 return FALSE;
988 }
989
990 static void
engine_device_added_cb(UpClient * client,UpDevice * device,CsdPowerManager * manager)991 engine_device_added_cb (UpClient *client, UpDevice *device, CsdPowerManager *manager)
992 {
993 /* add to list */
994 g_ptr_array_add (manager->priv->devices_array, g_object_ref (device));
995 engine_recalculate_state (manager);
996 }
997
998 static void
999 #if UP_CHECK_VERSION(0,99,0)
engine_device_removed_cb(UpClient * client,const char * object_path,CsdPowerManager * manager)1000 engine_device_removed_cb (UpClient *client, const char *object_path, CsdPowerManager *manager)
1001 {
1002 guint i;
1003
1004 for (i = 0; i < manager->priv->devices_array->len; i++) {
1005 UpDevice *device = g_ptr_array_index (manager->priv->devices_array, i);
1006
1007 if (g_strcmp0 (object_path, up_device_get_object_path (device)) == 0) {
1008 g_ptr_array_remove_index (manager->priv->devices_array, i);
1009 break;
1010 }
1011 }
1012 engine_recalculate_state (manager);
1013 }
1014
1015 #else
1016
1017 engine_device_removed_cb (UpClient *client, UpDevice *device, CsdPowerManager *manager)
1018 {
1019 gboolean ret;
1020 ret = g_ptr_array_remove (manager->priv->devices_array, device);
1021 if (!ret)
1022 return;
1023 engine_recalculate_state (manager);
1024 }
1025 #endif
1026
1027 static void
on_notification_closed(NotifyNotification * notification,gpointer data)1028 on_notification_closed (NotifyNotification *notification, gpointer data)
1029 {
1030 g_object_unref (notification);
1031 }
1032
1033 static void
create_notification(const char * summary,const char * body,const char * icon,NotifyNotification ** weak_pointer_location)1034 create_notification (const char *summary,
1035 const char *body,
1036 const char *icon,
1037 NotifyNotification **weak_pointer_location)
1038 {
1039 NotifyNotification *notification;
1040
1041 notification = notify_notification_new (summary, body, icon);
1042 *weak_pointer_location = notification;
1043 g_object_add_weak_pointer (G_OBJECT (notification),
1044 (gpointer *) weak_pointer_location);
1045 g_signal_connect (notification, "closed",
1046 G_CALLBACK (on_notification_closed), NULL);
1047 }
1048
1049 static void
engine_ups_discharging(CsdPowerManager * manager,UpDevice * device)1050 engine_ups_discharging (CsdPowerManager *manager, UpDevice *device)
1051 {
1052 const gchar *title;
1053 gboolean ret;
1054 gchar *remaining_text = NULL;
1055 gdouble percentage;
1056 GError *error = NULL;
1057 GIcon *icon = NULL;
1058 gint64 time_to_empty;
1059 GString *message;
1060 UpDeviceKind kind;
1061
1062 /* get device properties */
1063 g_object_get (device,
1064 "kind", &kind,
1065 "percentage", &percentage,
1066 "time-to-empty", &time_to_empty,
1067 NULL);
1068
1069 if (kind != UP_DEVICE_KIND_UPS)
1070 return;
1071
1072 /* only show text if there is a valid time */
1073 if (time_to_empty > 0)
1074 remaining_text = gpm_get_timestring (time_to_empty);
1075
1076 /* TRANSLATORS: UPS is now discharging */
1077 title = _("UPS Discharging");
1078
1079 message = g_string_new ("");
1080 if (remaining_text != NULL) {
1081 /* TRANSLATORS: tell the user how much time they have got */
1082 g_string_append_printf (message, _("%s of UPS backup power remaining"),
1083 remaining_text);
1084 } else {
1085 g_string_append (message, gpm_device_to_localised_string (device));
1086 }
1087 g_string_append_printf (message, " (%.0f%%)", percentage);
1088
1089 icon = gpm_upower_get_device_icon (device, TRUE);
1090
1091 /* close any existing notification of this class */
1092 notify_close_if_showing (manager->priv->notification_discharging);
1093
1094 /* create a new notification */
1095 create_notification (title, message->str,
1096 get_first_themed_icon_name (icon),
1097 &manager->priv->notification_discharging);
1098 notify_notification_set_timeout (manager->priv->notification_discharging,
1099 CSD_POWER_MANAGER_NOTIFY_TIMEOUT_LONG);
1100 notify_notification_set_urgency (manager->priv->notification_discharging,
1101 NOTIFY_URGENCY_NORMAL);
1102 /* TRANSLATORS: this is the notification application name */
1103 notify_notification_set_app_name (manager->priv->notification_discharging, _("Power"));
1104 notify_notification_set_hint (manager->priv->notification_discharging,
1105 "transient", g_variant_new_boolean (TRUE));
1106
1107 /* try to show */
1108 ret = notify_notification_show (manager->priv->notification_discharging,
1109 &error);
1110 if (!ret) {
1111 g_warning ("failed to show notification: %s", error->message);
1112 g_error_free (error);
1113 g_object_unref (manager->priv->notification_discharging);
1114 }
1115 g_string_free (message, TRUE);
1116 if (icon != NULL)
1117 g_object_unref (icon);
1118 g_free (remaining_text);
1119 }
1120
1121 static CsdPowerActionType
manager_critical_action_get(CsdPowerManager * manager,gboolean is_ups)1122 manager_critical_action_get (CsdPowerManager *manager,
1123 gboolean is_ups)
1124 {
1125 CsdPowerActionType policy;
1126
1127 policy = g_settings_get_enum (manager->priv->settings, "critical-battery-action");
1128 if (policy == CSD_POWER_ACTION_SUSPEND) {
1129 if (is_ups == FALSE
1130 #if ! UP_CHECK_VERSION(0,99,0)
1131 && up_client_get_can_suspend (manager->priv->up_client)
1132 #endif
1133 )
1134 return policy;
1135 return CSD_POWER_ACTION_SHUTDOWN;
1136 } else if (policy == CSD_POWER_ACTION_HIBERNATE) {
1137 #if ! UP_CHECK_VERSION(0,99,0)
1138 if (up_client_get_can_hibernate (manager->priv->up_client))
1139 #endif
1140 return policy;
1141 return CSD_POWER_ACTION_SHUTDOWN;
1142 }
1143
1144 return policy;
1145 }
1146
1147 static gboolean
manager_critical_action_do(CsdPowerManager * manager,gboolean is_ups)1148 manager_critical_action_do (CsdPowerManager *manager,
1149 gboolean is_ups)
1150 {
1151 CsdPowerActionType action_type;
1152
1153 /* stop playing the alert as it's too late to do anything now */
1154 if (manager->priv->critical_alert_timeout_id > 0)
1155 play_loop_stop (manager);
1156
1157 action_type = manager_critical_action_get (manager, is_ups);
1158 do_power_action_type (manager, action_type);
1159
1160 return FALSE;
1161 }
1162
1163 static gboolean
manager_critical_action_do_cb(CsdPowerManager * manager)1164 manager_critical_action_do_cb (CsdPowerManager *manager)
1165 {
1166 manager_critical_action_do (manager, FALSE);
1167 return FALSE;
1168 }
1169
1170 static gboolean
manager_critical_ups_action_do_cb(CsdPowerManager * manager)1171 manager_critical_ups_action_do_cb (CsdPowerManager *manager)
1172 {
1173 manager_critical_action_do (manager, TRUE);
1174 return FALSE;
1175 }
1176
1177 static gboolean
engine_just_laptop_battery(CsdPowerManager * manager)1178 engine_just_laptop_battery (CsdPowerManager *manager)
1179 {
1180 UpDevice *device;
1181 UpDeviceKind kind;
1182 GPtrArray *array;
1183 gboolean ret = TRUE;
1184 guint i;
1185
1186 /* find if there are any other device types that mean we have to
1187 * be more specific in our wording */
1188 array = manager->priv->devices_array;
1189 for (i=0; i<array->len; i++) {
1190 device = g_ptr_array_index (array, i);
1191 g_object_get (device, "kind", &kind, NULL);
1192 if (kind != UP_DEVICE_KIND_BATTERY) {
1193 ret = FALSE;
1194 break;
1195 }
1196 }
1197 return ret;
1198 }
1199
1200 static void
engine_charge_low(CsdPowerManager * manager,UpDevice * device)1201 engine_charge_low (CsdPowerManager *manager, UpDevice *device)
1202 {
1203 const gchar *title = NULL;
1204 gboolean ret;
1205 gchar *message = NULL;
1206 gchar *tmp;
1207 gchar *remaining_text;
1208 gdouble percentage;
1209 GIcon *icon = NULL;
1210 gint64 time_to_empty;
1211 UpDeviceKind kind;
1212 GError *error = NULL;
1213
1214 /* get device properties */
1215 g_object_get (device,
1216 "kind", &kind,
1217 "percentage", &percentage,
1218 "time-to-empty", &time_to_empty,
1219 NULL);
1220
1221 /* check to see if the batteries have not noticed we are on AC */
1222 if (kind == UP_DEVICE_KIND_BATTERY) {
1223 if (!up_client_get_on_battery (manager->priv->up_client)) {
1224 g_warning ("ignoring low message as we are not on battery power");
1225 goto out;
1226 }
1227 }
1228
1229 if (kind == UP_DEVICE_KIND_BATTERY) {
1230
1231 /* if the user has no other batteries, drop the "Laptop" wording */
1232 ret = engine_just_laptop_battery (manager);
1233 if (ret) {
1234 /* TRANSLATORS: laptop battery low, and we only have one battery */
1235 title = _("Battery low");
1236 } else {
1237 /* TRANSLATORS: laptop battery low, and we have more than one kind of battery */
1238 title = _("Laptop battery low");
1239 }
1240 tmp = gpm_get_timestring (time_to_empty);
1241 remaining_text = g_strconcat ("<b>", tmp, "</b>", NULL);
1242 g_free (tmp);
1243
1244 /* TRANSLATORS: tell the user how much time they have got */
1245 message = g_strdup_printf (_("Approximately %s remaining (%.0f%%)"), remaining_text, percentage);
1246 g_free (remaining_text);
1247
1248 } else if (kind == UP_DEVICE_KIND_UPS) {
1249 /* TRANSLATORS: UPS is starting to get a little low */
1250 title = _("UPS low");
1251 tmp = gpm_get_timestring (time_to_empty);
1252 remaining_text = g_strconcat ("<b>", tmp, "</b>", NULL);
1253 g_free (tmp);
1254
1255 /* TRANSLATORS: tell the user how much time they have got */
1256 message = g_strdup_printf (_("Approximately %s of remaining UPS backup power (%.0f%%)"),
1257 remaining_text, percentage);
1258 g_free (remaining_text);
1259 } else if (kind == UP_DEVICE_KIND_MOUSE) {
1260 /* TRANSLATORS: mouse is getting a little low */
1261 title = _("Mouse battery low");
1262
1263 /* TRANSLATORS: tell user more details */
1264 message = g_strdup_printf (_("Wireless mouse is low in power (%.0f%%)"), percentage);
1265
1266 } else if (kind == UP_DEVICE_KIND_KEYBOARD) {
1267 /* TRANSLATORS: keyboard is getting a little low */
1268 title = _("Keyboard battery low");
1269
1270 /* TRANSLATORS: tell user more details */
1271 message = g_strdup_printf (_("Wireless keyboard is low in power (%.0f%%)"), percentage);
1272
1273 } else if (kind == UP_DEVICE_KIND_PDA) {
1274 /* TRANSLATORS: PDA is getting a little low */
1275 title = _("PDA battery low");
1276
1277 /* TRANSLATORS: tell user more details */
1278 message = g_strdup_printf (_("PDA is low in power (%.0f%%)"), percentage);
1279
1280 } else if (kind == UP_DEVICE_KIND_PHONE) {
1281 /* TRANSLATORS: cell phone (mobile) is getting a little low */
1282 title = _("Cell phone battery low");
1283
1284 /* TRANSLATORS: tell user more details */
1285 message = g_strdup_printf (_("Cell phone is low in power (%.0f%%)"), percentage);
1286
1287 } else if (kind == UP_DEVICE_KIND_MEDIA_PLAYER) {
1288 /* TRANSLATORS: media player, e.g. mp3 is getting a little low */
1289 title = _("Media player battery low");
1290
1291 /* TRANSLATORS: tell user more details */
1292 message = g_strdup_printf (_("Media player is low in power (%.0f%%)"), percentage);
1293
1294 } else if (kind == UP_DEVICE_KIND_TABLET) {
1295 /* TRANSLATORS: graphics tablet, e.g. wacom is getting a little low */
1296 title = _("Tablet battery low");
1297
1298 /* TRANSLATORS: tell user more details */
1299 message = g_strdup_printf (_("Tablet is low in power (%.0f%%)"), percentage);
1300
1301 } else if (kind == UP_DEVICE_KIND_COMPUTER) {
1302 /* TRANSLATORS: computer, e.g. ipad is getting a little low */
1303 title = _("Attached computer battery low");
1304
1305 /* TRANSLATORS: tell user more details */
1306 message = g_strdup_printf (_("Attached computer is low in power (%.0f%%)"), percentage);
1307 }
1308
1309 /* get correct icon */
1310 icon = gpm_upower_get_device_icon (device, TRUE);
1311
1312 /* close any existing notification of this class */
1313 notify_close_if_showing (manager->priv->notification_low);
1314
1315 /* create a new notification */
1316 create_notification (title, message,
1317 get_first_themed_icon_name (icon),
1318 &manager->priv->notification_low);
1319 notify_notification_set_timeout (manager->priv->notification_low,
1320 CSD_POWER_MANAGER_NOTIFY_TIMEOUT_LONG);
1321 notify_notification_set_urgency (manager->priv->notification_low,
1322 NOTIFY_URGENCY_NORMAL);
1323 notify_notification_set_app_name (manager->priv->notification_low, _("Power"));
1324 notify_notification_set_hint (manager->priv->notification_low,
1325 "transient", g_variant_new_boolean (TRUE));
1326
1327 /* try to show */
1328 ret = notify_notification_show (manager->priv->notification_low,
1329 &error);
1330 if (!ret) {
1331 g_warning ("failed to show notification: %s", error->message);
1332 g_error_free (error);
1333 g_object_unref (manager->priv->notification_low);
1334 }
1335
1336 /* play the sound, using sounds from the naming spec */
1337 ca_context_play (manager->priv->canberra_context, 0,
1338 CA_PROP_EVENT_ID, "battery-low",
1339 /* TRANSLATORS: this is the sound description */
1340 CA_PROP_EVENT_DESCRIPTION, _("Battery is low"), NULL);
1341
1342 out:
1343 if (icon != NULL)
1344 g_object_unref (icon);
1345 g_free (message);
1346 }
1347
1348 static void
engine_charge_critical(CsdPowerManager * manager,UpDevice * device)1349 engine_charge_critical (CsdPowerManager *manager, UpDevice *device)
1350 {
1351 const gchar *title = NULL;
1352 gboolean ret;
1353 gchar *message = NULL;
1354 gdouble percentage;
1355 GIcon *icon = NULL;
1356 gint64 time_to_empty;
1357 CsdPowerActionType policy;
1358 UpDeviceKind kind;
1359 GError *error = NULL;
1360
1361 /* get device properties */
1362 g_object_get (device,
1363 "kind", &kind,
1364 "percentage", &percentage,
1365 "time-to-empty", &time_to_empty,
1366 NULL);
1367
1368 /* check to see if the batteries have not noticed we are on AC */
1369 if (kind == UP_DEVICE_KIND_BATTERY) {
1370 if (!up_client_get_on_battery (manager->priv->up_client)) {
1371 g_warning ("ignoring critically low message as we are not on battery power");
1372 goto out;
1373 }
1374 }
1375
1376 if (kind == UP_DEVICE_KIND_BATTERY) {
1377
1378 /* if the user has no other batteries, drop the "Laptop" wording */
1379 ret = engine_just_laptop_battery (manager);
1380 if (ret) {
1381 /* TRANSLATORS: laptop battery critically low, and only have one kind of battery */
1382 title = _("Battery critically low");
1383 } else {
1384 /* TRANSLATORS: laptop battery critically low, and we have more than one type of battery */
1385 title = _("Laptop battery critically low");
1386 }
1387
1388 /* we have to do different warnings depending on the policy */
1389 policy = manager_critical_action_get (manager, FALSE);
1390
1391 /* use different text for different actions */
1392 if (policy == CSD_POWER_ACTION_NOTHING) {
1393 /* TRANSLATORS: tell the use to insert the plug, as we're not going to do anything */
1394 message = g_strdup (_("Plug in your AC adapter to avoid losing data."));
1395
1396 } else if (policy == CSD_POWER_ACTION_SUSPEND) {
1397 /* TRANSLATORS: give the user a ultimatum */
1398 message = g_strdup_printf (_("Computer will suspend very soon unless it is plugged in."));
1399
1400 } else if (policy == CSD_POWER_ACTION_HIBERNATE) {
1401 /* TRANSLATORS: give the user a ultimatum */
1402 message = g_strdup_printf (_("Computer will hibernate very soon unless it is plugged in."));
1403
1404 } else if (policy == CSD_POWER_ACTION_SHUTDOWN) {
1405 /* TRANSLATORS: give the user a ultimatum */
1406 message = g_strdup_printf (_("Computer will shutdown very soon unless it is plugged in."));
1407 }
1408
1409 } else if (kind == UP_DEVICE_KIND_UPS) {
1410 gchar *remaining_text;
1411 gchar *tmp;
1412
1413 /* TRANSLATORS: the UPS is very low */
1414 title = _("UPS critically low");
1415 tmp = gpm_get_timestring (time_to_empty);
1416 remaining_text = g_strconcat ("<b>", tmp, "</b>", NULL);
1417 g_free (tmp);
1418
1419 /* TRANSLATORS: give the user a ultimatum */
1420 message = g_strdup_printf (_("Approximately %s of remaining UPS power (%.0f%%). "
1421 "Restore AC power to your computer to avoid losing data."),
1422 remaining_text, percentage);
1423 g_free (remaining_text);
1424 } else if (kind == UP_DEVICE_KIND_MOUSE) {
1425 /* TRANSLATORS: the mouse battery is very low */
1426 title = _("Mouse battery low");
1427
1428 /* TRANSLATORS: the device is just going to stop working */
1429 message = g_strdup_printf (_("Wireless mouse is very low in power (%.0f%%). "
1430 "This device will soon stop functioning if not charged."),
1431 percentage);
1432 } else if (kind == UP_DEVICE_KIND_KEYBOARD) {
1433 /* TRANSLATORS: the keyboard battery is very low */
1434 title = _("Keyboard battery low");
1435
1436 /* TRANSLATORS: the device is just going to stop working */
1437 message = g_strdup_printf (_("Wireless keyboard is very low in power (%.0f%%). "
1438 "This device will soon stop functioning if not charged."),
1439 percentage);
1440 } else if (kind == UP_DEVICE_KIND_PDA) {
1441
1442 /* TRANSLATORS: the PDA battery is very low */
1443 title = _("PDA battery low");
1444
1445 /* TRANSLATORS: the device is just going to stop working */
1446 message = g_strdup_printf (_("PDA is very low in power (%.0f%%). "
1447 "This device will soon stop functioning if not charged."),
1448 percentage);
1449
1450 } else if (kind == UP_DEVICE_KIND_PHONE) {
1451
1452 /* TRANSLATORS: the cell battery is very low */
1453 title = _("Cell phone battery low");
1454
1455 /* TRANSLATORS: the device is just going to stop working */
1456 message = g_strdup_printf (_("Cell phone is very low in power (%.0f%%). "
1457 "This device will soon stop functioning if not charged."),
1458 percentage);
1459
1460 } else if (kind == UP_DEVICE_KIND_MEDIA_PLAYER) {
1461
1462 /* TRANSLATORS: the cell battery is very low */
1463 title = _("Cell phone battery low");
1464
1465 /* TRANSLATORS: the device is just going to stop working */
1466 message = g_strdup_printf (_("Media player is very low in power (%.0f%%). "
1467 "This device will soon stop functioning if not charged."),
1468 percentage);
1469 } else if (kind == UP_DEVICE_KIND_TABLET) {
1470
1471 /* TRANSLATORS: the cell battery is very low */
1472 title = _("Tablet battery low");
1473
1474 /* TRANSLATORS: the device is just going to stop working */
1475 message = g_strdup_printf (_("Tablet is very low in power (%.0f%%). "
1476 "This device will soon stop functioning if not charged."),
1477 percentage);
1478 } else if (kind == UP_DEVICE_KIND_COMPUTER) {
1479
1480 /* TRANSLATORS: the cell battery is very low */
1481 title = _("Attached computer battery low");
1482
1483 /* TRANSLATORS: the device is just going to stop working */
1484 message = g_strdup_printf (_("Attached computer is very low in power (%.0f%%). "
1485 "The device will soon shutdown if not charged."),
1486 percentage);
1487 }
1488
1489 /* get correct icon */
1490 icon = gpm_upower_get_device_icon (device, TRUE);
1491
1492 /* close any existing notification of this class */
1493 notify_close_if_showing (manager->priv->notification_low);
1494
1495 /* create a new notification */
1496 create_notification (title, message,
1497 get_first_themed_icon_name (icon),
1498 &manager->priv->notification_low);
1499 notify_notification_set_timeout (manager->priv->notification_low,
1500 CSD_POWER_MANAGER_NOTIFY_TIMEOUT_LONG);
1501 notify_notification_set_urgency (manager->priv->notification_low,
1502 NOTIFY_URGENCY_CRITICAL);
1503 notify_notification_set_app_name (manager->priv->notification_low, _("Power"));
1504
1505 /* try to show */
1506 ret = notify_notification_show (manager->priv->notification_low,
1507 &error);
1508 if (!ret) {
1509 g_warning ("failed to show notification: %s", error->message);
1510 g_error_free (error);
1511 g_object_unref (manager->priv->notification_low);
1512 }
1513
1514 switch (kind) {
1515
1516 case UP_DEVICE_KIND_BATTERY:
1517 case UP_DEVICE_KIND_UPS:
1518 g_debug ("critical charge level reached, starting sound loop");
1519 play_loop_start (manager,
1520 "battery-caution",
1521 _("Battery is critically low"),
1522 TRUE,
1523 CSD_POWER_MANAGER_CRITICAL_ALERT_TIMEOUT);
1524 break;
1525
1526 default:
1527 /* play the sound, using sounds from the naming spec */
1528 ca_context_play (manager->priv->canberra_context, 0,
1529 CA_PROP_EVENT_ID, "battery-caution",
1530 /* TRANSLATORS: this is the sound description */
1531 CA_PROP_EVENT_DESCRIPTION, _("Battery is critically low"), NULL);
1532 break;
1533 }
1534 out:
1535 if (icon != NULL)
1536 g_object_unref (icon);
1537 g_free (message);
1538 }
1539
1540 static void
engine_charge_action(CsdPowerManager * manager,UpDevice * device)1541 engine_charge_action (CsdPowerManager *manager, UpDevice *device)
1542 {
1543 const gchar *title = NULL;
1544 gboolean ret;
1545 gchar *message = NULL;
1546 GError *error = NULL;
1547 GIcon *icon = NULL;
1548 CsdPowerActionType policy;
1549 guint timer_id;
1550 UpDeviceKind kind;
1551
1552 /* get device properties */
1553 g_object_get (device,
1554 "kind", &kind,
1555 NULL);
1556
1557 /* check to see if the batteries have not noticed we are on AC */
1558 if (kind == UP_DEVICE_KIND_BATTERY) {
1559 if (!up_client_get_on_battery (manager->priv->up_client)) {
1560 g_warning ("ignoring critically low message as we are not on battery power");
1561 goto out;
1562 }
1563 }
1564
1565 if (kind == UP_DEVICE_KIND_BATTERY) {
1566
1567 /* TRANSLATORS: laptop battery is really, really, low */
1568 title = _("Laptop battery critically low");
1569
1570 /* we have to do different warnings depending on the policy */
1571 policy = manager_critical_action_get (manager, FALSE);
1572
1573 /* use different text for different actions */
1574 if (policy == CSD_POWER_ACTION_NOTHING) {
1575 /* TRANSLATORS: computer will shutdown without saving data */
1576 message = g_strdup (_("The battery is below the critical level and "
1577 "this computer will <b>power-off</b> when the "
1578 "battery becomes completely empty."));
1579
1580 } else if (policy == CSD_POWER_ACTION_SUSPEND) {
1581 /* TRANSLATORS: computer will suspend */
1582 message = g_strdup (_("The battery is below the critical level and "
1583 "this computer is about to suspend.\n"
1584 "<b>NOTE:</b> A small amount of power is required "
1585 "to keep your computer in a suspended state."));
1586
1587 } else if (policy == CSD_POWER_ACTION_HIBERNATE) {
1588 /* TRANSLATORS: computer will hibernate */
1589 message = g_strdup (_("The battery is below the critical level and "
1590 "this computer is about to hibernate."));
1591
1592 } else if (policy == CSD_POWER_ACTION_SHUTDOWN) {
1593 /* TRANSLATORS: computer will just shutdown */
1594 message = g_strdup (_("The battery is below the critical level and "
1595 "this computer is about to shutdown."));
1596 }
1597
1598 /* wait 20 seconds for user-panic */
1599 timer_id = g_timeout_add_seconds (20, (GSourceFunc) manager_critical_action_do_cb, manager);
1600 g_source_set_name_by_id (timer_id, "[CsdPowerManager] battery critical-action");
1601
1602 } else if (kind == UP_DEVICE_KIND_UPS) {
1603 /* TRANSLATORS: UPS is really, really, low */
1604 title = _("UPS critically low");
1605
1606 /* we have to do different warnings depending on the policy */
1607 policy = manager_critical_action_get (manager, TRUE);
1608
1609 /* use different text for different actions */
1610 if (policy == CSD_POWER_ACTION_NOTHING) {
1611 /* TRANSLATORS: computer will shutdown without saving data */
1612 message = g_strdup (_("UPS is below the critical level and "
1613 "this computer will <b>power-off</b> when the "
1614 "UPS becomes completely empty."));
1615
1616 } else if (policy == CSD_POWER_ACTION_HIBERNATE) {
1617 /* TRANSLATORS: computer will hibernate */
1618 message = g_strdup (_("UPS is below the critical level and "
1619 "this computer is about to hibernate."));
1620
1621 } else if (policy == CSD_POWER_ACTION_SHUTDOWN) {
1622 /* TRANSLATORS: computer will just shutdown */
1623 message = g_strdup (_("UPS is below the critical level and "
1624 "this computer is about to shutdown."));
1625 }
1626
1627 /* wait 20 seconds for user-panic */
1628 timer_id = g_timeout_add_seconds (20, (GSourceFunc) manager_critical_ups_action_do_cb, manager);
1629 g_source_set_name_by_id (timer_id, "[CsdPowerManager] ups critical-action");
1630 }
1631
1632 /* not all types have actions */
1633 if (title == NULL) {
1634 g_free (message);
1635 return;
1636 }
1637
1638 /* get correct icon */
1639 icon = gpm_upower_get_device_icon (device, TRUE);
1640
1641 /* close any existing notification of this class */
1642 notify_close_if_showing (manager->priv->notification_low);
1643
1644 /* create a new notification */
1645 create_notification (title, message,
1646 get_first_themed_icon_name (icon),
1647 &manager->priv->notification_low);
1648 notify_notification_set_timeout (manager->priv->notification_low,
1649 CSD_POWER_MANAGER_NOTIFY_TIMEOUT_LONG);
1650 notify_notification_set_urgency (manager->priv->notification_low,
1651 NOTIFY_URGENCY_CRITICAL);
1652 notify_notification_set_app_name (manager->priv->notification_low, _("Power"));
1653
1654 /* try to show */
1655 ret = notify_notification_show (manager->priv->notification_low,
1656 &error);
1657 if (!ret) {
1658 g_warning ("failed to show notification: %s", error->message);
1659 g_error_free (error);
1660 g_object_unref (manager->priv->notification_low);
1661 }
1662
1663 /* play the sound, using sounds from the naming spec */
1664 ca_context_play (manager->priv->canberra_context, 0,
1665 CA_PROP_EVENT_ID, "battery-caution",
1666 /* TRANSLATORS: this is the sound description */
1667 CA_PROP_EVENT_DESCRIPTION, _("Battery is critically low"), NULL);
1668 out:
1669 if (icon != NULL)
1670 g_object_unref (icon);
1671 g_free (message);
1672 }
1673
1674 static void
1675 #if UP_CHECK_VERSION(0,99,0)
device_properties_changed_cb(UpDevice * device,GParamSpec * pspec,CsdPowerManager * manager)1676 device_properties_changed_cb (UpDevice *device, GParamSpec *pspec, CsdPowerManager *manager)
1677 #else
1678 engine_device_changed_cb (UpClient *client, UpDevice *device, CsdPowerManager *manager)
1679 #endif
1680 {
1681 UpDeviceKind kind;
1682 UpDeviceState state;
1683 UpDeviceState state_old;
1684 CsdPowerManagerWarning warning_old;
1685 CsdPowerManagerWarning warning;
1686
1687 /* get device properties */
1688 g_object_get (device,
1689 "kind", &kind,
1690 NULL);
1691
1692 /* if battery then use composite device to cope with multiple batteries */
1693 if (kind == UP_DEVICE_KIND_BATTERY) {
1694 g_debug ("updating because %s changed", up_device_get_object_path (device));
1695 device = engine_update_composite_device (manager, device);
1696 }
1697
1698 /* get device properties (may be composite) */
1699 g_object_get (device,
1700 "state", &state,
1701 NULL);
1702
1703 g_debug ("%s state is now %s", up_device_get_object_path (device), up_device_state_to_string (state));
1704
1705 /* see if any interesting state changes have happened */
1706 state_old = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(device), "engine-state-old"));
1707 if (state_old != state) {
1708 if (state == UP_DEVICE_STATE_DISCHARGING) {
1709 g_debug ("discharging");
1710 engine_ups_discharging (manager, device);
1711 } else if (state == UP_DEVICE_STATE_FULLY_CHARGED ||
1712 state == UP_DEVICE_STATE_CHARGING) {
1713 g_debug ("fully charged or charging, hiding notifications if any");
1714 notify_close_if_showing (manager->priv->notification_low);
1715 notify_close_if_showing (manager->priv->notification_discharging);
1716 }
1717
1718 /* save new state */
1719 g_object_set_data (G_OBJECT(device), "engine-state-old", GUINT_TO_POINTER(state));
1720 }
1721
1722 /* check the warning state has not changed */
1723 warning_old = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(device), "engine-warning-old"));
1724 warning = engine_get_warning (manager, device);
1725 if (warning != warning_old) {
1726 if (warning == WARNING_LOW) {
1727 g_debug ("** EMIT: charge-low");
1728 engine_charge_low (manager, device);
1729 } else if (warning == WARNING_CRITICAL) {
1730 g_debug ("** EMIT: charge-critical");
1731 engine_charge_critical (manager, device);
1732 } else if (warning == WARNING_ACTION) {
1733 g_debug ("charge-action");
1734 engine_charge_action (manager, device);
1735 }
1736 /* save new state */
1737 g_object_set_data (G_OBJECT(device), "engine-warning-old", GUINT_TO_POINTER(warning));
1738 }
1739
1740 engine_recalculate_state (manager);
1741 }
1742
1743 static UpDevice *
engine_get_primary_device(CsdPowerManager * manager)1744 engine_get_primary_device (CsdPowerManager *manager)
1745 {
1746 guint i;
1747 UpDevice *device = NULL;
1748 UpDevice *device_tmp;
1749 UpDeviceKind kind;
1750 UpDeviceState state;
1751 gboolean is_present;
1752
1753 for (i=0; i<manager->priv->devices_array->len; i++) {
1754 device_tmp = g_ptr_array_index (manager->priv->devices_array, i);
1755
1756 /* get device properties */
1757 g_object_get (device_tmp,
1758 "kind", &kind,
1759 "state", &state,
1760 "is-present", &is_present,
1761 NULL);
1762
1763 /* not present */
1764 if (!is_present)
1765 continue;
1766
1767 /* not discharging */
1768 if (state != UP_DEVICE_STATE_DISCHARGING)
1769 continue;
1770
1771 /* not battery */
1772 if (kind != UP_DEVICE_KIND_BATTERY)
1773 continue;
1774
1775 /* use composite device to cope with multiple batteries */
1776 device = g_object_ref (engine_get_composite_device (manager, device_tmp));
1777 break;
1778 }
1779 return device;
1780 }
1781
1782 static void
phone_device_added_cb(GpmPhone * phone,guint idx,CsdPowerManager * manager)1783 phone_device_added_cb (GpmPhone *phone, guint idx, CsdPowerManager *manager)
1784 {
1785 UpDevice *device;
1786 device = up_device_new ();
1787
1788 g_debug ("phone added %i", idx);
1789
1790 /* get device properties */
1791 g_object_set (device,
1792 "kind", UP_DEVICE_KIND_PHONE,
1793 "is-rechargeable", TRUE,
1794 "native-path", g_strdup_printf ("dummy:phone_%i", idx),
1795 "is-present", TRUE,
1796 NULL);
1797
1798 /* state changed */
1799 engine_device_add (manager, device);
1800 g_ptr_array_add (manager->priv->devices_array, g_object_ref (device));
1801 engine_recalculate_state (manager);
1802 }
1803
1804 static void
phone_device_removed_cb(GpmPhone * phone,guint idx,CsdPowerManager * manager)1805 phone_device_removed_cb (GpmPhone *phone, guint idx, CsdPowerManager *manager)
1806 {
1807 guint i;
1808 UpDevice *device;
1809 UpDeviceKind kind;
1810
1811 g_debug ("phone removed %i", idx);
1812
1813 for (i=0; i<manager->priv->devices_array->len; i++) {
1814 device = g_ptr_array_index (manager->priv->devices_array, i);
1815
1816 /* get device properties */
1817 g_object_get (device,
1818 "kind", &kind,
1819 NULL);
1820
1821 if (kind == UP_DEVICE_KIND_PHONE) {
1822 g_ptr_array_remove_index (manager->priv->devices_array, i);
1823 break;
1824 }
1825 }
1826
1827 /* state changed */
1828 engine_recalculate_state (manager);
1829 }
1830
1831 static void
phone_device_refresh_cb(GpmPhone * phone,guint idx,CsdPowerManager * manager)1832 phone_device_refresh_cb (GpmPhone *phone, guint idx, CsdPowerManager *manager)
1833 {
1834 guint i;
1835 UpDevice *device;
1836 UpDeviceKind kind;
1837 UpDeviceState state;
1838 gboolean is_present;
1839 gdouble percentage;
1840
1841 g_debug ("phone refresh %i", idx);
1842
1843 for (i=0; i<manager->priv->devices_array->len; i++) {
1844 device = g_ptr_array_index (manager->priv->devices_array, i);
1845
1846 /* get device properties */
1847 g_object_get (device,
1848 "kind", &kind,
1849 "state", &state,
1850 "percentage", &percentage,
1851 "is-present", &is_present,
1852 NULL);
1853
1854 if (kind == UP_DEVICE_KIND_PHONE) {
1855 is_present = gpm_phone_get_present (phone, idx);
1856 state = gpm_phone_get_on_ac (phone, idx) ? UP_DEVICE_STATE_CHARGING : UP_DEVICE_STATE_DISCHARGING;
1857 percentage = gpm_phone_get_percentage (phone, idx);
1858 break;
1859 }
1860 }
1861
1862 /* state changed */
1863 engine_recalculate_state (manager);
1864 }
1865
1866 static void
cinnamon_session_shutdown_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1867 cinnamon_session_shutdown_cb (GObject *source_object,
1868 GAsyncResult *res,
1869 gpointer user_data)
1870 {
1871 GVariant *result;
1872 GError *error = NULL;
1873
1874 result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
1875 res,
1876 &error);
1877 if (result == NULL) {
1878 g_warning ("couldn't shutdown using cinnamon-session: %s",
1879 error->message);
1880 g_error_free (error);
1881 } else {
1882 g_variant_unref (result);
1883 }
1884 }
1885
1886 static void
cinnamon_session_shutdown(void)1887 cinnamon_session_shutdown (void)
1888 {
1889 GError *error = NULL;
1890 GDBusProxy *proxy;
1891
1892 /* ask cinnamon-session to show the shutdown dialog with a timeout */
1893 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
1894 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
1895 NULL,
1896 GNOME_SESSION_DBUS_NAME,
1897 GNOME_SESSION_DBUS_PATH,
1898 GNOME_SESSION_DBUS_INTERFACE,
1899 NULL, &error);
1900 if (proxy == NULL) {
1901 g_warning ("cannot connect to cinnamon-session: %s",
1902 error->message);
1903 g_error_free (error);
1904 return;
1905 }
1906 g_dbus_proxy_call (proxy,
1907 "Shutdown",
1908 NULL,
1909 G_DBUS_CALL_FLAGS_NONE,
1910 -1, NULL,
1911 cinnamon_session_shutdown_cb, NULL);
1912 g_object_unref (proxy);
1913 }
1914
1915 static void
turn_monitors_off(CsdPowerManager * manager)1916 turn_monitors_off (CsdPowerManager *manager)
1917 {
1918 gboolean ret;
1919 GError *error = NULL;
1920
1921 ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen,
1922 GNOME_RR_DPMS_OFF,
1923 &error);
1924 if (!ret) {
1925 g_warning ("failed to turn the panel off for policy action: %s",
1926 error->message);
1927 g_error_free (error);
1928 }
1929 }
1930
1931 static void
do_power_action_type(CsdPowerManager * manager,CsdPowerActionType action_type)1932 do_power_action_type (CsdPowerManager *manager,
1933 CsdPowerActionType action_type)
1934 {
1935 switch (action_type) {
1936 case CSD_POWER_ACTION_SUSPEND:
1937 if (should_lock_on_suspend (manager)) {
1938 lock_screensaver (manager);
1939 }
1940
1941 turn_monitors_off (manager);
1942
1943 gboolean hybrid = g_settings_get_boolean (manager->priv->settings_cinnamon_session,
1944 "prefer-hybrid-sleep");
1945 gboolean suspend_then_hibernate = g_settings_get_boolean (manager->priv->settings_cinnamon_session,
1946 "suspend-then-hibernate");
1947
1948 csd_power_suspend (hybrid, suspend_then_hibernate);
1949 break;
1950 case CSD_POWER_ACTION_INTERACTIVE:
1951 cinnamon_session_shutdown ();
1952 break;
1953 case CSD_POWER_ACTION_HIBERNATE:
1954 if (should_lock_on_suspend (manager)) {
1955 lock_screensaver (manager);
1956 }
1957
1958 turn_monitors_off (manager);
1959 csd_power_hibernate ();
1960 break;
1961 case CSD_POWER_ACTION_SHUTDOWN:
1962 /* this is only used on critically low battery where
1963 * hibernate is not available and is marginally better
1964 * than just powering down the computer mid-write */
1965 csd_power_poweroff ();
1966 break;
1967 case CSD_POWER_ACTION_BLANK:
1968 /* Lock first or else xrandr might reconfigure stuff and the ss's coverage
1969 * may be incorrect upon return. */
1970 lock_screensaver (manager);
1971 turn_monitors_off (manager);
1972 break;
1973 case CSD_POWER_ACTION_NOTHING:
1974 break;
1975 }
1976 }
1977
1978 static gboolean
upower_kbd_get_percentage(CsdPowerManager * manager,GError ** error)1979 upower_kbd_get_percentage (CsdPowerManager *manager, GError **error)
1980 {
1981 GVariant *k_now = NULL;
1982
1983 k_now = g_dbus_proxy_call_sync (manager->priv->upower_kbd_proxy,
1984 "GetBrightness",
1985 NULL,
1986 G_DBUS_CALL_FLAGS_NONE,
1987 -1,
1988 NULL,
1989 error);
1990 if (k_now != NULL) {
1991 g_variant_get (k_now, "(i)", &manager->priv->kbd_brightness_now);
1992 g_variant_unref (k_now);
1993 return TRUE;
1994 }
1995
1996 return FALSE;
1997 }
1998
1999 static void
upower_kbd_emit_changed(CsdPowerManager * manager)2000 upower_kbd_emit_changed (CsdPowerManager *manager)
2001 {
2002 /* not yet connected to the bus */
2003 if (manager->priv->keyboard_iface == NULL)
2004 return;
2005
2006 csd_keyboard_emit_changed (manager->priv->keyboard_iface);
2007 }
2008
2009 static gboolean
upower_kbd_set_brightness(CsdPowerManager * manager,guint value,GError ** error)2010 upower_kbd_set_brightness (CsdPowerManager *manager, guint value, GError **error)
2011 {
2012 GVariant *retval;
2013
2014 /* same as before */
2015 if (manager->priv->kbd_brightness_now == value)
2016 return TRUE;
2017
2018 /* update h/w value */
2019 retval = g_dbus_proxy_call_sync (manager->priv->upower_kbd_proxy,
2020 "SetBrightness",
2021 g_variant_new ("(i)", (gint) value),
2022 G_DBUS_CALL_FLAGS_NONE,
2023 -1,
2024 NULL,
2025 error);
2026 if (retval == NULL)
2027 return FALSE;
2028
2029 /* save new value */
2030 manager->priv->kbd_brightness_now = value;
2031 g_variant_unref (retval);
2032 upower_kbd_emit_changed(manager);
2033 return TRUE;
2034 }
2035
2036 static gboolean
upower_kbd_toggle(CsdPowerManager * manager,GError ** error)2037 upower_kbd_toggle (CsdPowerManager *manager,
2038 GError **error)
2039 {
2040 gboolean ret;
2041
2042 if (manager->priv->kbd_brightness_old >= 0) {
2043 g_debug ("keyboard toggle off");
2044 ret = upower_kbd_set_brightness (manager,
2045 manager->priv->kbd_brightness_old,
2046 error);
2047 if (ret) {
2048 /* succeeded, set to -1 since now no old value */
2049 manager->priv->kbd_brightness_old = -1;
2050 }
2051 } else {
2052 g_debug ("keyboard toggle on");
2053 /* save the current value to restore later when untoggling */
2054 manager->priv->kbd_brightness_old = manager->priv->kbd_brightness_now;
2055 ret = upower_kbd_set_brightness (manager, 0, error);
2056 if (!ret) {
2057 /* failed, reset back to -1 */
2058 manager->priv->kbd_brightness_old = -1;
2059 }
2060 }
2061
2062 upower_kbd_emit_changed(manager);
2063 return ret;
2064 }
2065
2066 static void
upower_kbd_handle_changed(GDBusProxy * proxy,gchar * sender_name,gchar * signal_name,GVariant * parameters,gpointer user_data)2067 upower_kbd_handle_changed (GDBusProxy *proxy,
2068 gchar *sender_name,
2069 gchar *signal_name,
2070 GVariant *parameters,
2071 gpointer user_data)
2072 {
2073 CsdPowerManager *manager = CSD_POWER_MANAGER (user_data);
2074
2075 g_debug("keyboard changed signal");
2076
2077 if (g_strcmp0 (signal_name, "BrightnessChangedWithSource") == 0) {
2078 g_debug ("Received upower kbdbacklight BrightnessChangedWithSource");
2079 const gchar *source;
2080 gint brightness;
2081
2082 g_variant_get (parameters, "(i&s)", &brightness, &source);
2083
2084 if (g_strcmp0 (source, "external") == 0) {
2085 return;
2086 }
2087
2088 manager->priv->kbd_brightness_now = brightness;
2089 upower_kbd_emit_changed(manager);
2090 }
2091
2092 }
2093
2094 static gboolean
suspend_on_lid_close(CsdPowerManager * manager)2095 suspend_on_lid_close (CsdPowerManager *manager)
2096 {
2097 CsdXrandrBootBehaviour val;
2098
2099 if (!external_monitor_is_connected (manager->priv->x11_screen))
2100 return TRUE;
2101
2102 val = g_settings_get_enum (manager->priv->settings_xrandr, "default-monitors-setup");
2103 return val == CSD_XRANDR_BOOT_BEHAVIOUR_DO_NOTHING;
2104 }
2105
2106 static gboolean
inhibit_lid_switch_timer_cb(CsdPowerManager * manager)2107 inhibit_lid_switch_timer_cb (CsdPowerManager *manager)
2108 {
2109 if (suspend_on_lid_close (manager)) {
2110 g_debug ("no external monitors for a while; uninhibiting lid close");
2111 uninhibit_lid_switch (manager);
2112 manager->priv->inhibit_lid_switch_timer_id = 0;
2113 return G_SOURCE_REMOVE;
2114 }
2115
2116 g_debug ("external monitor still there; trying again later");
2117 return G_SOURCE_CONTINUE;
2118 }
2119
2120 /* Sets up a timer to be triggered some seconds after closing the laptop lid
2121 * when the laptop is *not* suspended for some reason. We'll check conditions
2122 * again in the timeout handler to see if we can suspend then.
2123 */
2124 static void
setup_inhibit_lid_switch_timer(CsdPowerManager * manager)2125 setup_inhibit_lid_switch_timer (CsdPowerManager *manager)
2126 {
2127 if (manager->priv->inhibit_lid_switch_timer_id != 0) {
2128 g_debug ("lid close safety timer already set up");
2129 return;
2130 }
2131
2132 g_debug ("setting up lid close safety timer");
2133
2134 manager->priv->inhibit_lid_switch_timer_id = g_timeout_add_seconds (CSD_POWER_MANAGER_LID_CLOSE_SAFETY_TIMEOUT,
2135 (GSourceFunc) inhibit_lid_switch_timer_cb,
2136 manager);
2137 g_source_set_name_by_id (manager->priv->inhibit_lid_switch_timer_id, "[CsdPowerManager] lid close safety timer");
2138 }
2139
2140 static void
restart_inhibit_lid_switch_timer(CsdPowerManager * manager)2141 restart_inhibit_lid_switch_timer (CsdPowerManager *manager)
2142 {
2143 if (manager->priv->inhibit_lid_switch_timer_id != 0) {
2144 g_debug ("restarting lid close safety timer");
2145 g_source_remove (manager->priv->inhibit_lid_switch_timer_id);
2146 manager->priv->inhibit_lid_switch_timer_id = 0;
2147 setup_inhibit_lid_switch_timer (manager);
2148 }
2149 }
2150
2151
2152 static gboolean
randr_output_is_on(GnomeRROutput * output)2153 randr_output_is_on (GnomeRROutput *output)
2154 {
2155 GnomeRRCrtc *crtc;
2156
2157 crtc = gnome_rr_output_get_crtc (output);
2158 if (!crtc)
2159 return FALSE;
2160 return gnome_rr_crtc_get_current_mode (crtc) != NULL;
2161 }
2162
2163 static gboolean
external_monitor_is_connected(GnomeRRScreen * screen)2164 external_monitor_is_connected (GnomeRRScreen *screen)
2165 {
2166 GnomeRROutput **outputs;
2167 guint i;
2168
2169 /* see if we have more than one screen plugged in */
2170 outputs = gnome_rr_screen_list_outputs (screen);
2171 for (i = 0; outputs[i] != NULL; i++) {
2172 if (randr_output_is_on (outputs[i]) &&
2173 !gnome_rr_output_is_laptop (outputs[i]))
2174 return TRUE;
2175 }
2176
2177 return FALSE;
2178 }
2179
2180 static void
on_randr_event(GnomeRRScreen * screen,gpointer user_data)2181 on_randr_event (GnomeRRScreen *screen, gpointer user_data)
2182 {
2183 CsdPowerManager *manager = CSD_POWER_MANAGER (user_data);
2184
2185 if (suspend_on_lid_close (manager)) {
2186 restart_inhibit_lid_switch_timer (manager);
2187 return;
2188 }
2189
2190 /* when a second monitor is plugged in, we take the
2191 * handle-lid-switch inhibitor lock of logind to prevent
2192 * it from suspending.
2193 *
2194 * Uninhibiting is done in the inhibit_lid_switch_timer,
2195 * since we want to give users a few seconds when unplugging
2196 * and replugging an external monitor, not suspend right away.
2197 */
2198 inhibit_lid_switch (manager);
2199 setup_inhibit_lid_switch_timer (manager);
2200 }
2201
2202 static void
do_lid_open_action(CsdPowerManager * manager)2203 do_lid_open_action (CsdPowerManager *manager)
2204 {
2205 gboolean ret;
2206 GError *error = NULL;
2207
2208 /* play a sound, using sounds from the naming spec */
2209 ca_context_play (manager->priv->canberra_context, 0,
2210 CA_PROP_EVENT_ID, "lid-open",
2211 /* TRANSLATORS: this is the sound description */
2212 CA_PROP_EVENT_DESCRIPTION, _("Lid has been opened"),
2213 NULL);
2214
2215 /* ensure we turn the panel back on after lid open */
2216 ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen,
2217 GNOME_RR_DPMS_ON,
2218 &error);
2219 if (!ret) {
2220 g_warning ("failed to turn the panel on after lid open: %s",
2221 error->message);
2222 g_clear_error (&error);
2223 }
2224
2225 /* only toggle keyboard if present and already toggled off */
2226 if (manager->priv->upower_kbd_proxy != NULL &&
2227 manager->priv->kbd_brightness_old != -1) {
2228 ret = upower_kbd_toggle (manager, &error);
2229 if (!ret) {
2230 g_warning ("failed to turn the kbd backlight on: %s",
2231 error->message);
2232 g_error_free (error);
2233 }
2234 }
2235
2236 kill_lid_close_safety_timer (manager);
2237 }
2238
2239 static gboolean
is_on(GnomeRROutput * output)2240 is_on (GnomeRROutput *output)
2241 {
2242 GnomeRRCrtc *crtc;
2243
2244 crtc = gnome_rr_output_get_crtc (output);
2245 if (!crtc)
2246 return FALSE;
2247 return gnome_rr_crtc_get_current_mode (crtc) != NULL;
2248 }
2249
2250 static gboolean
non_laptop_outputs_are_all_off(GnomeRRScreen * screen)2251 non_laptop_outputs_are_all_off (GnomeRRScreen *screen)
2252 {
2253 GnomeRROutput **outputs;
2254 int i;
2255
2256 outputs = gnome_rr_screen_list_outputs (screen);
2257 for (i = 0; outputs[i] != NULL; i++) {
2258 if (gnome_rr_output_is_laptop (outputs[i]))
2259 continue;
2260
2261 if (is_on (outputs[i]))
2262 return FALSE;
2263 }
2264
2265 return TRUE;
2266 }
2267
2268 /* Timeout callback used to check conditions when the laptop's lid is closed but
2269 * the machine is not suspended yet. We try to suspend again, so that the laptop
2270 * won't overheat if placed in a backpack.
2271 */
2272 static gboolean
lid_close_safety_timer_cb(CsdPowerManager * manager)2273 lid_close_safety_timer_cb (CsdPowerManager *manager)
2274 {
2275 manager->priv->lid_close_safety_timer_id = 0;
2276
2277 g_debug ("lid has been closed for a while; trying to suspend again");
2278 do_lid_closed_action (manager);
2279
2280 return FALSE;
2281 }
2282
2283 /* Sets up a timer to be triggered some seconds after closing the laptop lid
2284 * when the laptop is *not* suspended for some reason. We'll check conditions
2285 * again in the timeout handler to see if we can suspend then.
2286 */
2287 static void
setup_lid_close_safety_timer(CsdPowerManager * manager)2288 setup_lid_close_safety_timer (CsdPowerManager *manager)
2289 {
2290 if (manager->priv->lid_close_safety_timer_id != 0)
2291 return;
2292
2293 manager->priv->lid_close_safety_timer_id = g_timeout_add_seconds (CSD_POWER_MANAGER_LID_CLOSE_SAFETY_TIMEOUT,
2294 (GSourceFunc) lid_close_safety_timer_cb,
2295 manager);
2296 g_source_set_name_by_id (manager->priv->lid_close_safety_timer_id, "[CsdPowerManager] lid close safety timer");
2297 }
2298
2299 static void
kill_lid_close_safety_timer(CsdPowerManager * manager)2300 kill_lid_close_safety_timer (CsdPowerManager *manager)
2301 {
2302 if (manager->priv->lid_close_safety_timer_id != 0) {
2303 g_source_remove (manager->priv->lid_close_safety_timer_id);
2304 manager->priv->lid_close_safety_timer_id = 0;
2305 }
2306 }
2307
2308 static void
suspend_with_lid_closed(CsdPowerManager * manager)2309 suspend_with_lid_closed (CsdPowerManager *manager)
2310 {
2311 gboolean ret;
2312 GError *error = NULL;
2313 CsdPowerActionType action_type;
2314
2315 /* we have different settings depending on AC state */
2316 if (up_client_get_on_battery (manager->priv->up_client)) {
2317 action_type = g_settings_get_enum (manager->priv->settings,
2318 "lid-close-battery-action");
2319 } else {
2320 action_type = g_settings_get_enum (manager->priv->settings,
2321 "lid-close-ac-action");
2322 }
2323
2324 /* check we won't melt when the lid is closed */
2325 if (action_type != CSD_POWER_ACTION_SUSPEND &&
2326 action_type != CSD_POWER_ACTION_HIBERNATE) {
2327 #if ! UP_CHECK_VERSION(0,99,0)
2328 if (up_client_get_lid_force_sleep (manager->priv->up_client)) {
2329 g_warning ("to prevent damage, now forcing suspend");
2330 do_power_action_type (manager, CSD_POWER_ACTION_SUSPEND);
2331 return;
2332 }
2333 #endif
2334 }
2335
2336 /* only toggle keyboard if present and not already toggled */
2337 if (manager->priv->upower_kbd_proxy &&
2338 manager->priv->kbd_brightness_old == -1) {
2339 ret = upower_kbd_toggle (manager, &error);
2340 if (!ret) {
2341 g_warning ("failed to turn the kbd backlight off: %s",
2342 error->message);
2343 g_error_free (error);
2344 }
2345 }
2346
2347 do_power_action_type (manager, action_type);
2348 }
2349
2350 static void
do_lid_closed_action(CsdPowerManager * manager)2351 do_lid_closed_action (CsdPowerManager *manager)
2352 {
2353 /* play a sound, using sounds from the naming spec */
2354 ca_context_play (manager->priv->canberra_context, 0,
2355 CA_PROP_EVENT_ID, "lid-close",
2356 /* TRANSLATORS: this is the sound description */
2357 CA_PROP_EVENT_DESCRIPTION, _("Lid has been closed"),
2358 NULL);
2359
2360 /* refresh RANDR so we get an accurate view of what monitors are plugged in when the lid is closed */
2361 gnome_rr_screen_refresh (manager->priv->x11_screen, NULL); /* NULL-GError */
2362
2363 /* perform policy action */
2364 if (g_settings_get_boolean (manager->priv->settings, "lid-close-suspend-with-external-monitor")
2365 || non_laptop_outputs_are_all_off (manager->priv->x11_screen)) {
2366 g_debug ("lid is closed; suspending or hibernating");
2367 suspend_with_lid_closed (manager);
2368 } else {
2369 g_debug ("lid is closed; not suspending nor hibernating since some external monitor outputs are still active");
2370 setup_lid_close_safety_timer (manager);
2371 }
2372 }
2373
2374
2375 static void
2376 #if UP_CHECK_VERSION(0,99,0)
lid_state_changed_cb(UpClient * client,GParamSpec * pspec,CsdPowerManager * manager)2377 lid_state_changed_cb (UpClient *client, GParamSpec *pspec, CsdPowerManager *manager)
2378 #else
2379 up_client_changed_cb (UpClient *client, CsdPowerManager *manager)
2380 #endif
2381 {
2382 gboolean lid_is_closed;
2383 gboolean on_battery;
2384
2385 on_battery = up_client_get_on_battery(client);
2386 if (!on_battery) {
2387 /* if we are playing a critical charge sound loop on AC, stop it */
2388 if (manager->priv->critical_alert_timeout_id > 0) {
2389 g_debug ("stopping alert loop due to ac being present");
2390 play_loop_stop (manager);
2391 }
2392 notify_close_if_showing (manager->priv->notification_low);
2393 }
2394
2395 /* same state */
2396 lid_is_closed = up_client_get_lid_is_closed (manager->priv->up_client);
2397
2398 if (manager->priv->lid_is_closed == lid_is_closed &&
2399 manager->priv->on_battery == on_battery)
2400 return;
2401
2402 manager->priv->lid_is_closed = lid_is_closed;
2403 manager->priv->on_battery = on_battery;
2404
2405 /* fake a keypress */
2406 if (lid_is_closed)
2407 do_lid_closed_action (manager);
2408 else
2409 do_lid_open_action (manager);
2410 }
2411
2412 typedef enum {
2413 SESSION_STATUS_CODE_AVAILABLE = 0,
2414 SESSION_STATUS_CODE_INVISIBLE,
2415 SESSION_STATUS_CODE_BUSY,
2416 SESSION_STATUS_CODE_IDLE,
2417 SESSION_STATUS_CODE_UNKNOWN
2418 } SessionStatusCode;
2419
2420 typedef enum {
2421 SESSION_INHIBIT_MASK_LOGOUT = 1,
2422 SESSION_INHIBIT_MASK_SWITCH = 2,
2423 SESSION_INHIBIT_MASK_SUSPEND = 4,
2424 SESSION_INHIBIT_MASK_IDLE = 8
2425 } SessionInhibitMask;
2426
2427 static const gchar *
idle_mode_to_string(CsdPowerIdleMode mode)2428 idle_mode_to_string (CsdPowerIdleMode mode)
2429 {
2430 if (mode == CSD_POWER_IDLE_MODE_NORMAL)
2431 return "normal";
2432 if (mode == CSD_POWER_IDLE_MODE_DIM)
2433 return "dim";
2434 if (mode == CSD_POWER_IDLE_MODE_BLANK)
2435 return "blank";
2436 if (mode == CSD_POWER_IDLE_MODE_SLEEP)
2437 return "sleep";
2438 return "unknown";
2439 }
2440
2441 static GnomeRROutput *
get_primary_output(CsdPowerManager * manager)2442 get_primary_output (CsdPowerManager *manager)
2443 {
2444 GnomeRROutput *output = NULL;
2445 GnomeRROutput **outputs;
2446 guint i;
2447
2448 /* search all X11 outputs for the device id */
2449 outputs = gnome_rr_screen_list_outputs (manager->priv->x11_screen);
2450 if (outputs == NULL)
2451 goto out;
2452
2453 for (i = 0; outputs[i] != NULL; i++) {
2454 if (gnome_rr_output_is_connected (outputs[i]) &&
2455 gnome_rr_output_is_laptop (outputs[i]) &&
2456 gnome_rr_output_get_backlight_min (outputs[i]) >= 0 &&
2457 gnome_rr_output_get_backlight_max (outputs[i]) > 0) {
2458 output = outputs[i];
2459 break;
2460 }
2461 }
2462 out:
2463 return output;
2464 }
2465
2466 static void
backlight_override_settings_refresh(CsdPowerManager * manager)2467 backlight_override_settings_refresh (CsdPowerManager *manager)
2468 {
2469 int i = 0;
2470 /* update all the stored backlight override properties
2471 * this is called on startup and by engine_settings_key_changed_cb */
2472 manager->priv->backlight_helper_force = g_settings_get_boolean
2473 (manager->priv->settings, "backlight-helper-force");
2474
2475 /* concatenate all the search preferences into a single argument string */
2476 gchar** backlight_preference_order = g_settings_get_strv
2477 (manager->priv->settings, "backlight-helper-preference-order");
2478
2479 gchar* tmp1 = NULL;
2480 gchar* tmp2 = NULL;
2481
2482 if (backlight_preference_order[0] != NULL) {
2483 tmp1 = g_strdup_printf("-b %s", backlight_preference_order[0]);
2484 }
2485
2486 for (i=1; backlight_preference_order[i] != NULL; i++ )
2487 {
2488 tmp2 = tmp1;
2489 tmp1 = g_strdup_printf("%s -b %s", tmp2,
2490 backlight_preference_order[i]);
2491 g_free(tmp2);
2492 }
2493
2494 tmp2 = manager->priv->backlight_helper_preference_args;
2495 manager->priv->backlight_helper_preference_args = tmp1;
2496 g_free(tmp2);
2497 tmp2 = NULL;
2498
2499 g_free(backlight_preference_order);
2500 backlight_preference_order = NULL;
2501 }
2502
2503 /**
2504 * backlight_helper_get_value:
2505 *
2506 * Gets a brightness value from the PolicyKit helper.
2507 *
2508 * Return value: the signed integer value from the helper, or -1
2509 * for failure. If -1 then @error is set.
2510 **/
2511 static gint64
backlight_helper_get_value(const gchar * argument,CsdPowerManager * manager,GError ** error)2512 backlight_helper_get_value (const gchar *argument, CsdPowerManager* manager,
2513 GError **error)
2514 {
2515 gboolean ret;
2516 gchar *stdout_data = NULL;
2517 gint exit_status = 0;
2518 gint64 value = -1;
2519 gchar *command = NULL;
2520 gchar *endptr = NULL;
2521
2522 #ifndef __linux__
2523 /* non-Linux platforms won't have /sys/class/backlight */
2524 g_set_error_literal (error,
2525 CSD_POWER_MANAGER_ERROR,
2526 CSD_POWER_MANAGER_ERROR_FAILED,
2527 "The sysfs backlight helper is only for Linux");
2528 goto out;
2529 #endif
2530
2531 /* get the data */
2532 command = g_strdup_printf (LIBEXECDIR "/csd-backlight-helper --%s %s",
2533 argument,
2534 manager->priv->backlight_helper_preference_args);
2535 ret = g_spawn_command_line_sync (command,
2536 &stdout_data,
2537 NULL,
2538 &exit_status,
2539 error);
2540 g_debug ("executed %s retval: %i", command, exit_status);
2541
2542 if (!ret)
2543 goto out;
2544
2545 if (WEXITSTATUS (exit_status) != 0) {
2546 g_set_error (error,
2547 CSD_POWER_MANAGER_ERROR,
2548 CSD_POWER_MANAGER_ERROR_FAILED,
2549 "csd-backlight-helper failed: %s",
2550 stdout_data ? stdout_data : "No reason");
2551 goto out;
2552 }
2553
2554 /* parse */
2555 value = g_ascii_strtoll (stdout_data, &endptr, 10);
2556
2557 /* parsing error */
2558 if (endptr == stdout_data) {
2559 value = -1;
2560 g_set_error (error,
2561 CSD_POWER_MANAGER_ERROR,
2562 CSD_POWER_MANAGER_ERROR_FAILED,
2563 "failed to parse value: %s",
2564 stdout_data);
2565 goto out;
2566 }
2567
2568 /* out of range */
2569 if (value > G_MAXINT) {
2570 value = -1;
2571 g_set_error (error,
2572 CSD_POWER_MANAGER_ERROR,
2573 CSD_POWER_MANAGER_ERROR_FAILED,
2574 "value out of range: %s",
2575 stdout_data);
2576 goto out;
2577 }
2578
2579 /* Fetching the value failed, for some other reason */
2580 if (value < 0) {
2581 g_set_error (error,
2582 CSD_POWER_MANAGER_ERROR,
2583 CSD_POWER_MANAGER_ERROR_FAILED,
2584 "value negative, but helper did not fail: %s",
2585 stdout_data);
2586 goto out;
2587 }
2588
2589 out:
2590 g_free (command);
2591 g_free (stdout_data);
2592 return value;
2593 }
2594
2595 /**
2596 * backlight_helper_set_value:
2597 *
2598 * Sets a brightness value using the PolicyKit helper.
2599 *
2600 * Return value: Success. If FALSE then @error is set.
2601 **/
2602 static gboolean
backlight_helper_set_value(const gchar * argument,gint value,CsdPowerManager * manager,GError ** error)2603 backlight_helper_set_value (const gchar *argument,
2604 gint value,
2605 CsdPowerManager* manager,
2606 GError **error)
2607 {
2608 gboolean ret;
2609 gint exit_status = 0;
2610 gchar *command = NULL;
2611
2612 #ifndef __linux__
2613 /* non-Linux platforms won't have /sys/class/backlight */
2614 g_set_error_literal (error,
2615 CSD_POWER_MANAGER_ERROR,
2616 CSD_POWER_MANAGER_ERROR_FAILED,
2617 "The sysfs backlight helper is only for Linux");
2618 goto out;
2619 #endif
2620
2621 /* get the data */
2622 command = g_strdup_printf ("pkexec " LIBEXECDIR "/csd-backlight-helper --%s %i %s",
2623 argument, value,
2624 manager->priv->backlight_helper_preference_args);
2625 ret = g_spawn_command_line_sync (command,
2626 NULL,
2627 NULL,
2628 &exit_status,
2629 error);
2630
2631 g_debug ("executed %s retval: %i", command, exit_status);
2632
2633 if (!ret || WEXITSTATUS (exit_status) != 0)
2634 goto out;
2635
2636 out:
2637 g_free (command);
2638 return ret;
2639 }
2640
2641 int
backlight_get_output_id(CsdPowerManager * manager)2642 backlight_get_output_id (CsdPowerManager *manager)
2643 {
2644 GnomeRROutput *output = NULL;
2645 GnomeRROutput **outputs;
2646 GnomeRRCrtc *crtc;
2647 GdkScreen *gdk_screen;
2648 gint x, y;
2649 guint i;
2650
2651 outputs = gnome_rr_screen_list_outputs (manager->priv->x11_screen);
2652 if (outputs == NULL)
2653 return -1;
2654
2655 for (i = 0; outputs[i] != NULL; i++) {
2656 if (gnome_rr_output_is_connected (outputs[i]) &&
2657 gnome_rr_output_is_laptop (outputs[i])) {
2658 output = outputs[i];
2659 break;
2660 }
2661 }
2662
2663 if (output == NULL)
2664 return -1;
2665
2666 crtc = gnome_rr_output_get_crtc (output);
2667 if (crtc == NULL)
2668 return -1;
2669
2670 gdk_screen = gdk_screen_get_default ();
2671 gnome_rr_crtc_get_position (crtc, &x, &y);
2672
2673 return gdk_screen_get_monitor_at_point (gdk_screen, x, y);
2674 }
2675
2676 static gint
backlight_get_abs(CsdPowerManager * manager,GError ** error)2677 backlight_get_abs (CsdPowerManager *manager, GError **error)
2678 {
2679 GnomeRROutput *output;
2680
2681 /* prioritize user override settings */
2682 if (!manager->priv->backlight_helper_force)
2683 {
2684 /* prefer xbacklight */
2685 output = get_primary_output (manager);
2686 if (output != NULL) {
2687 return gnome_rr_output_get_backlight (output,
2688 error);
2689 }
2690 }
2691
2692 /* fall back to the polkit helper */
2693 return backlight_helper_get_value ("get-brightness", manager, error);
2694 }
2695
2696 static gint
backlight_get_percentage(CsdPowerManager * manager,GError ** error)2697 backlight_get_percentage (CsdPowerManager *manager, GError **error)
2698 {
2699 GnomeRROutput *output;
2700 gint now;
2701 gint value = -1;
2702 gint min = 0;
2703 gint max;
2704
2705 /* prioritize user override settings */
2706 if (!manager->priv->backlight_helper_force)
2707 {
2708 /* prefer xbacklight */
2709 output = get_primary_output (manager);
2710 if (output != NULL) {
2711
2712 min = gnome_rr_output_get_backlight_min (output);
2713 max = gnome_rr_output_get_backlight_max (output);
2714 now = gnome_rr_output_get_backlight (output, error);
2715 if (now < 0)
2716 goto out;
2717 value = ABS_TO_PERCENTAGE (min, max, now);
2718 goto out;
2719 }
2720 }
2721
2722 /* fall back to the polkit helper */
2723 max = backlight_helper_get_value ("get-max-brightness", manager, error);
2724 if (max < 0)
2725 goto out;
2726 now = backlight_helper_get_value ("get-brightness", manager, error);
2727 if (now < 0)
2728 goto out;
2729 value = ABS_TO_PERCENTAGE (min, max, now);
2730 out:
2731 return value;
2732 }
2733
2734 static gint
backlight_get_min(CsdPowerManager * manager)2735 backlight_get_min (CsdPowerManager *manager)
2736 {
2737 /* if we have no xbacklight device, then hardcode zero as sysfs
2738 * offsets everything to 0 as min */
2739
2740 /* user override means we will be using sysfs */
2741 if (manager->priv->backlight_helper_force)
2742 return 0;
2743
2744 GnomeRROutput *output;
2745
2746 output = get_primary_output (manager);
2747 if (output == NULL)
2748 return 0;
2749
2750 /* get xbacklight value, which maybe non-zero */
2751 return gnome_rr_output_get_backlight_min (output);
2752 }
2753
2754 static gint
backlight_get_max(CsdPowerManager * manager,GError ** error)2755 backlight_get_max (CsdPowerManager *manager, GError **error)
2756 {
2757 gint value;
2758 GnomeRROutput *output;
2759
2760 /* prioritize user override settings */
2761 if (!manager->priv->backlight_helper_force)
2762 {
2763 /* prefer xbacklight */
2764 output = get_primary_output (manager);
2765 if (output != NULL) {
2766 value = gnome_rr_output_get_backlight_max (output);
2767 if (value < 0) {
2768 g_set_error (error,
2769 CSD_POWER_MANAGER_ERROR,
2770 CSD_POWER_MANAGER_ERROR_FAILED,
2771 "failed to get backlight max");
2772 }
2773 return value;
2774 }
2775 }
2776
2777 /* fall back to the polkit helper */
2778 return backlight_helper_get_value ("get-max-brightness", manager, error);
2779 }
2780
2781 static void
backlight_emit_changed(CsdPowerManager * manager)2782 backlight_emit_changed (CsdPowerManager *manager)
2783 {
2784 /* not yet connected to the bus */
2785 if (manager->priv->screen_iface == NULL)
2786 return;
2787
2788 csd_screen_emit_changed (manager->priv->screen_iface);
2789 }
2790
2791 static gboolean
backlight_set_percentage(CsdPowerManager * manager,guint value,gboolean emit_changed,GError ** error)2792 backlight_set_percentage (CsdPowerManager *manager,
2793 guint value,
2794 gboolean emit_changed,
2795 GError **error)
2796 {
2797 GnomeRROutput *output;
2798 gboolean ret = FALSE;
2799 gint min = 0;
2800 gint max;
2801 guint discrete;
2802
2803 /* prioritize user override settings */
2804 if (!manager->priv->backlight_helper_force)
2805 {
2806 /* prefer xbacklight */
2807 output = get_primary_output (manager);
2808 if (output != NULL) {
2809 min = gnome_rr_output_get_backlight_min (output);
2810 max = gnome_rr_output_get_backlight_max (output);
2811 if (min < 0 || max < 0) {
2812 g_warning ("no xrandr backlight capability");
2813 goto out;
2814 }
2815 discrete = PERCENTAGE_TO_ABS (min, max, value);
2816 ret = gnome_rr_output_set_backlight (output,
2817 discrete,
2818 error);
2819 goto out;
2820 }
2821 }
2822
2823 /* fall back to the polkit helper */
2824 max = backlight_helper_get_value ("get-max-brightness", manager, error);
2825 if (max < 0)
2826 goto out;
2827 discrete = PERCENTAGE_TO_ABS (min, max, value);
2828 ret = backlight_helper_set_value ("set-brightness",
2829 discrete,
2830 manager,
2831 error);
2832 out:
2833 if (ret && emit_changed)
2834 backlight_emit_changed (manager);
2835 return ret;
2836 }
2837
2838 static gint
backlight_step_up(CsdPowerManager * manager,GError ** error)2839 backlight_step_up (CsdPowerManager *manager, GError **error)
2840 {
2841 GnomeRROutput *output;
2842 gboolean ret = FALSE;
2843 gint percentage_value = -1;
2844 gint min = 0;
2845 gint max;
2846 gint now;
2847 gint step;
2848 guint discrete;
2849 GnomeRRCrtc *crtc;
2850
2851 /* prioritize user override settings */
2852 if (!manager->priv->backlight_helper_force)
2853 {
2854 /* prefer xbacklight */
2855 output = get_primary_output (manager);
2856 if (output != NULL) {
2857
2858 crtc = gnome_rr_output_get_crtc (output);
2859 if (crtc == NULL) {
2860 g_set_error (error,
2861 CSD_POWER_MANAGER_ERROR,
2862 CSD_POWER_MANAGER_ERROR_FAILED,
2863 "no crtc for %s",
2864 gnome_rr_output_get_name (output));
2865 goto out;
2866 }
2867 min = gnome_rr_output_get_backlight_min (output);
2868 max = gnome_rr_output_get_backlight_max (output);
2869 now = gnome_rr_output_get_backlight (output, error);
2870 if (now < 0)
2871 goto out;
2872 step = BRIGHTNESS_STEP_AMOUNT (max - min + 1);
2873 discrete = MIN (now + step, max);
2874 ret = gnome_rr_output_set_backlight (output,
2875 discrete,
2876 error);
2877 if (ret)
2878 percentage_value = ABS_TO_PERCENTAGE (min, max, discrete);
2879 goto out;
2880 }
2881 }
2882
2883 /* fall back to the polkit helper */
2884 now = backlight_helper_get_value ("get-brightness", manager, error);
2885 if (now < 0)
2886 goto out;
2887 max = backlight_helper_get_value ("get-max-brightness", manager, error);
2888 if (max < 0)
2889 goto out;
2890 step = BRIGHTNESS_STEP_AMOUNT (max - min + 1);
2891 discrete = MIN (now + step, max);
2892 ret = backlight_helper_set_value ("set-brightness",
2893 discrete,
2894 manager,
2895 error);
2896 if (ret)
2897 percentage_value = ABS_TO_PERCENTAGE (min, max, discrete);
2898 out:
2899 if (ret)
2900 backlight_emit_changed (manager);
2901 return percentage_value;
2902 }
2903
2904 static gint
backlight_step_down(CsdPowerManager * manager,GError ** error)2905 backlight_step_down (CsdPowerManager *manager, GError **error)
2906 {
2907 GnomeRROutput *output;
2908 gboolean ret = FALSE;
2909 gint percentage_value = -1;
2910 gint min = 0;
2911 gint max;
2912 gint now;
2913 gint step;
2914 guint discrete;
2915 GnomeRRCrtc *crtc;
2916
2917 /* prioritize user override settings */
2918 if (!manager->priv->backlight_helper_force)
2919 {
2920 /* prefer xbacklight */
2921 output = get_primary_output (manager);
2922 if (output != NULL) {
2923
2924 crtc = gnome_rr_output_get_crtc (output);
2925 if (crtc == NULL) {
2926 g_set_error (error,
2927 CSD_POWER_MANAGER_ERROR,
2928 CSD_POWER_MANAGER_ERROR_FAILED,
2929 "no crtc for %s",
2930 gnome_rr_output_get_name (output));
2931 goto out;
2932 }
2933 min = gnome_rr_output_get_backlight_min (output);
2934 max = gnome_rr_output_get_backlight_max (output);
2935 now = gnome_rr_output_get_backlight (output, error);
2936 if (now < 0)
2937 goto out;
2938 step = BRIGHTNESS_STEP_AMOUNT (max - min + 1);
2939 discrete = MAX (now - step, 0);
2940 ret = gnome_rr_output_set_backlight (output,
2941 discrete,
2942 error);
2943 if (ret)
2944 percentage_value = ABS_TO_PERCENTAGE (min, max, discrete);
2945 goto out;
2946 }
2947 }
2948
2949 /* fall back to the polkit helper */
2950 now = backlight_helper_get_value ("get-brightness", manager, error);
2951 if (now < 0)
2952 goto out;
2953 max = backlight_helper_get_value ("get-max-brightness", manager, error);
2954 if (max < 0)
2955 goto out;
2956 step = BRIGHTNESS_STEP_AMOUNT (max - min + 1);
2957 discrete = MAX (now - step, 0);
2958 ret = backlight_helper_set_value ("set-brightness",
2959 discrete,
2960 manager,
2961 error);
2962 if (ret)
2963 percentage_value = ABS_TO_PERCENTAGE (min, max, discrete);
2964 out:
2965 if (ret)
2966 backlight_emit_changed (manager);
2967 return percentage_value;
2968 }
2969
2970 static gint
backlight_set_abs(CsdPowerManager * manager,guint value,gboolean emit_changed,GError ** error)2971 backlight_set_abs (CsdPowerManager *manager,
2972 guint value,
2973 gboolean emit_changed,
2974 GError **error)
2975 {
2976 GnomeRROutput *output;
2977 gboolean ret = FALSE;
2978
2979 /* prioritize user override settings */
2980 if (!manager->priv->backlight_helper_force)
2981 {
2982 /* prefer xbacklight */
2983 output = get_primary_output (manager);
2984 if (output != NULL) {
2985 ret = gnome_rr_output_set_backlight (output,
2986 value,
2987 error);
2988 goto out;
2989 }
2990 }
2991 /* fall back to the polkit helper */
2992 ret = backlight_helper_set_value ("set-brightness",
2993 value,
2994 manager,
2995 error);
2996 out:
2997 if (ret && emit_changed)
2998 backlight_emit_changed (manager);
2999 return ret;
3000 }
3001
3002 static gboolean
display_backlight_dim(CsdPowerManager * manager,gint idle_percentage,GError ** error)3003 display_backlight_dim (CsdPowerManager *manager,
3004 gint idle_percentage,
3005 GError **error)
3006 {
3007 gint min;
3008 gint max;
3009 gint now;
3010 gint idle;
3011 gboolean ret = FALSE;
3012
3013 now = backlight_get_abs (manager, error);
3014 if (now < 0) {
3015 goto out;
3016 }
3017
3018 /* is the dim brightness actually *dimmer* than the
3019 * brightness we have now? */
3020 min = backlight_get_min (manager);
3021 max = backlight_get_max (manager, error);
3022 if (max < 0) {
3023 goto out;
3024 }
3025 idle = PERCENTAGE_TO_ABS (min, max, idle_percentage);
3026 if (idle > now) {
3027 g_debug ("brightness already now %i/%i, so "
3028 "ignoring dim to %i/%i",
3029 now, max, idle, max);
3030 ret = TRUE;
3031 goto out;
3032 }
3033 ret = backlight_set_abs (manager,
3034 idle,
3035 FALSE,
3036 error);
3037 if (!ret) {
3038 goto out;
3039 }
3040
3041 /* save for undim */
3042 manager->priv->pre_dim_brightness = now;
3043
3044 out:
3045 return ret;
3046 }
3047
3048 static gboolean
kbd_backlight_dim(CsdPowerManager * manager,gint idle_percentage,GError ** error)3049 kbd_backlight_dim (CsdPowerManager *manager,
3050 gint idle_percentage,
3051 GError **error)
3052 {
3053 gboolean ret;
3054 gint idle;
3055 gint max;
3056 gint now;
3057
3058 if (manager->priv->upower_kbd_proxy == NULL)
3059 return TRUE;
3060
3061 now = manager->priv->kbd_brightness_now;
3062 max = manager->priv->kbd_brightness_max;
3063 idle = PERCENTAGE_TO_ABS (0, max, idle_percentage);
3064 if (idle > now) {
3065 g_debug ("kbd brightness already now %i/%i, so "
3066 "ignoring dim to %i/%i",
3067 now, max, idle, max);
3068 return TRUE;
3069 }
3070 ret = upower_kbd_set_brightness (manager, idle, error);
3071 if (!ret)
3072 return FALSE;
3073
3074 /* save for undim */
3075 manager->priv->kbd_brightness_pre_dim = now;
3076 return TRUE;
3077 }
3078
3079 static void
idle_set_mode(CsdPowerManager * manager,CsdPowerIdleMode mode)3080 idle_set_mode (CsdPowerManager *manager, CsdPowerIdleMode mode)
3081 {
3082 gboolean ret = FALSE;
3083 GError *error = NULL;
3084 gint idle_percentage;
3085 CsdPowerActionType action_type;
3086 CinnamonSettingsSessionState state;
3087
3088 if (mode == manager->priv->current_idle_mode)
3089 return;
3090
3091 /* Ignore attempts to set "less idle" modes */
3092 if (mode < manager->priv->current_idle_mode &&
3093 mode != CSD_POWER_IDLE_MODE_NORMAL)
3094 return;
3095
3096 /* ensure we're still on an active console */
3097 state = cinnamon_settings_session_get_state (manager->priv->session);
3098 if (state == CINNAMON_SETTINGS_SESSION_STATE_INACTIVE) {
3099 g_debug ("ignoring state transition to %s as inactive",
3100 idle_mode_to_string (mode));
3101 return;
3102 }
3103
3104 manager->priv->current_idle_mode = mode;
3105 g_debug ("Doing a state transition: %s", idle_mode_to_string (mode));
3106
3107 /* don't do any power saving if we're a VM */
3108 if (manager->priv->is_virtual_machine) {
3109 g_debug ("ignoring state transition to %s as virtual machine",
3110 idle_mode_to_string (mode));
3111 return;
3112 }
3113
3114 /* save current brightness, and set dim level */
3115 if (mode == CSD_POWER_IDLE_MODE_DIM) {
3116
3117 /* have we disabled the action */
3118 if (up_client_get_on_battery (manager->priv->up_client)) {
3119 ret = g_settings_get_boolean (manager->priv->settings,
3120 "idle-dim-battery");
3121 } else {
3122 ret = g_settings_get_boolean (manager->priv->settings,
3123 "idle-dim-ac");
3124 }
3125 if (!ret) {
3126 g_debug ("not dimming due to policy");
3127 return;
3128 }
3129
3130 /* display backlight */
3131 idle_percentage = g_settings_get_int (manager->priv->settings,
3132 "idle-brightness");
3133 ret = display_backlight_dim (manager, idle_percentage, &error);
3134 if (!ret) {
3135 g_warning ("failed to set dim backlight to %i%%: %s",
3136 idle_percentage,
3137 error->message);
3138 g_clear_error (&error);
3139 }
3140
3141 /* keyboard backlight */
3142 ret = kbd_backlight_dim (manager, idle_percentage, &error);
3143 if (!ret) {
3144 g_warning ("failed to set dim kbd backlight to %i%%: %s",
3145 idle_percentage,
3146 error->message);
3147 g_clear_error (&error);
3148 }
3149
3150 /* turn off screen and kbd */
3151 } else if (mode == CSD_POWER_IDLE_MODE_BLANK) {
3152
3153 ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen,
3154 GNOME_RR_DPMS_OFF,
3155 &error);
3156 if (!ret) {
3157 g_warning ("failed to turn the panel off: %s",
3158 error->message);
3159 g_clear_error (&error);
3160 }
3161
3162 /* only toggle keyboard if present and not already toggled */
3163 if (manager->priv->upower_kbd_proxy &&
3164 manager->priv->kbd_brightness_old == -1) {
3165 ret = upower_kbd_toggle (manager, &error);
3166 if (!ret) {
3167 g_warning ("failed to turn the kbd backlight off: %s",
3168 error->message);
3169 g_error_free (error);
3170 }
3171 }
3172
3173 /* sleep */
3174 } else if (mode == CSD_POWER_IDLE_MODE_SLEEP) {
3175
3176 if (up_client_get_on_battery (manager->priv->up_client)) {
3177 action_type = g_settings_get_enum (manager->priv->settings,
3178 "sleep-inactive-battery-type");
3179 } else {
3180 action_type = g_settings_get_enum (manager->priv->settings,
3181 "sleep-inactive-ac-type");
3182 }
3183 do_power_action_type (manager, action_type);
3184
3185 /* turn on screen and restore user-selected brightness level */
3186 } else if (mode == CSD_POWER_IDLE_MODE_NORMAL) {
3187
3188 ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen,
3189 GNOME_RR_DPMS_ON,
3190 &error);
3191 if (!ret) {
3192 g_warning ("failed to turn the panel on: %s",
3193 error->message);
3194 g_clear_error (&error);
3195 }
3196
3197 /* reset brightness if we dimmed */
3198 if (manager->priv->pre_dim_brightness >= 0) {
3199 ret = backlight_set_abs (manager,
3200 manager->priv->pre_dim_brightness,
3201 FALSE,
3202 &error);
3203 if (!ret) {
3204 g_warning ("failed to restore backlight to %i: %s",
3205 manager->priv->pre_dim_brightness,
3206 error->message);
3207 g_clear_error (&error);
3208 } else {
3209 manager->priv->pre_dim_brightness = -1;
3210 }
3211 }
3212
3213 /* only toggle keyboard if present and already toggled off */
3214 if (manager->priv->upower_kbd_proxy &&
3215 manager->priv->kbd_brightness_old != -1) {
3216 ret = upower_kbd_toggle (manager, &error);
3217 if (!ret) {
3218 g_warning ("failed to turn the kbd backlight on: %s",
3219 error->message);
3220 g_clear_error (&error);
3221 }
3222 }
3223
3224 /* reset kbd brightness if we dimmed */
3225 if (manager->priv->kbd_brightness_pre_dim >= 0) {
3226 ret = upower_kbd_set_brightness (manager,
3227 manager->priv->kbd_brightness_pre_dim,
3228 &error);
3229 if (!ret) {
3230 g_warning ("failed to restore kbd backlight to %i: %s",
3231 manager->priv->kbd_brightness_pre_dim,
3232 error->message);
3233 g_error_free (error);
3234 }
3235 manager->priv->kbd_brightness_pre_dim = -1;
3236 }
3237
3238 }
3239 }
3240
3241 static gboolean
idle_is_session_inhibited(CsdPowerManager * manager,guint mask)3242 idle_is_session_inhibited (CsdPowerManager *manager, guint mask)
3243 {
3244 gboolean ret;
3245 GVariant *retval = NULL;
3246 GError *error = NULL;
3247
3248 /* not yet connected to cinnamon-session */
3249 if (manager->priv->session_proxy == NULL) {
3250 g_debug ("session inhibition not available, cinnamon-session is not available");
3251 return FALSE;
3252 }
3253
3254 retval = g_dbus_proxy_call_sync (manager->priv->session_proxy,
3255 "IsInhibited",
3256 g_variant_new ("(u)",
3257 mask),
3258 G_DBUS_CALL_FLAGS_NONE,
3259 -1, NULL,
3260 &error);
3261 if (retval == NULL) {
3262 /* abort as the DBUS method failed */
3263 g_warning ("IsInhibited failed: %s", error->message);
3264 g_error_free (error);
3265 return FALSE;
3266 }
3267
3268 g_variant_get (retval, "(b)", &ret);
3269 g_variant_unref (retval);
3270
3271 return ret;
3272 }
3273
3274 /**
3275 * idle_adjust_timeout:
3276 * @idle_time: Current idle time, in seconds.
3277 * @timeout: The new timeout we want to set, in seconds.
3278 *
3279 * On slow machines, or machines that have lots to load duing login,
3280 * the current idle time could be bigger than the requested timeout.
3281 * In this case the scheduled idle timeout will never fire, unless
3282 * some user activity (keyboard, mouse) resets the current idle time.
3283 * Instead of relying on user activity to correct this issue, we need
3284 * to adjust timeout, as related to current idle time, so the idle
3285 * timeout will fire as designed.
3286 *
3287 * Return value: timeout to set, adjusted acccording to current idle time.
3288 **/
3289 static guint
idle_adjust_timeout(guint idle_time,guint timeout)3290 idle_adjust_timeout (guint idle_time, guint timeout)
3291 {
3292 /* allow 2 sec margin for messaging delay. */
3293 idle_time += 2;
3294
3295 /* Double timeout until it's larger than current idle time.
3296 * Give up for ultra slow machines. (86400 sec = 24 hours) */
3297 while (timeout < idle_time &&
3298 timeout < 86400 &&
3299 timeout > 0) {
3300 timeout *= 2;
3301 }
3302 return timeout;
3303 }
3304
3305 /**
3306 * @timeout: The new timeout we want to set, in seconds
3307 **/
3308 static void
idle_set_timeout_dim(CsdPowerManager * manager,guint timeout)3309 idle_set_timeout_dim (CsdPowerManager *manager, guint timeout)
3310 {
3311 guint idle_time;
3312 gboolean is_idle_inhibited;
3313
3314 /* are we inhibited from going idle */
3315 is_idle_inhibited = idle_is_session_inhibited (manager,
3316 SESSION_INHIBIT_MASK_IDLE);
3317 if (is_idle_inhibited) {
3318 g_debug ("inhibited, so using normal state");
3319 idle_set_mode (manager, CSD_POWER_IDLE_MODE_NORMAL);
3320
3321 gpm_idletime_alarm_remove (manager->priv->idletime,
3322 CSD_POWER_IDLETIME_DIM_ID);
3323 return;
3324 }
3325
3326 idle_time = gpm_idletime_get_time (manager->priv->idletime) / 1000;
3327
3328 g_debug ("Setting dim idle timeout: %ds", timeout);
3329 if (timeout > 0) {
3330 gpm_idletime_alarm_set (manager->priv->idletime,
3331 CSD_POWER_IDLETIME_DIM_ID,
3332 idle_adjust_timeout (idle_time, timeout) * 1000);
3333 } else {
3334 gpm_idletime_alarm_remove (manager->priv->idletime,
3335 CSD_POWER_IDLETIME_DIM_ID);
3336 }
3337 return;
3338 }
3339
3340 static void
refresh_idle_dim_settings(CsdPowerManager * manager)3341 refresh_idle_dim_settings (CsdPowerManager *manager)
3342 {
3343 gint timeout_dim;
3344 timeout_dim = g_settings_get_int (manager->priv->settings,
3345 "idle-dim-time");
3346 g_debug ("idle dim set with timeout %i", timeout_dim);
3347 idle_set_timeout_dim (manager, timeout_dim);
3348 }
3349
3350 /**
3351 * idle_adjust_timeout_blank:
3352 * @idle_time: current idle time, in seconds.
3353 * @timeout: the new timeout we want to set, in seconds.
3354 *
3355 * Same as idle_adjust_timeout(), but also accounts for the duration
3356 * of the fading animation in the screensaver (so that blanking happens
3357 * exactly at the end of it, if configured with the same timeouts)
3358 */
3359 static guint
idle_adjust_timeout_blank(guint idle_time,guint timeout)3360 idle_adjust_timeout_blank (guint idle_time, guint timeout)
3361 {
3362 return idle_adjust_timeout (idle_time,
3363 timeout + SCREENSAVER_FADE_TIME);
3364 }
3365
3366 static void
idle_configure(CsdPowerManager * manager)3367 idle_configure (CsdPowerManager *manager)
3368 {
3369 gboolean is_idle_inhibited;
3370 guint current_idle_time;
3371 guint timeout_lock;
3372 guint timeout_blank;
3373 guint timeout_sleep;
3374 gboolean on_battery;
3375
3376 /* are we inhibited from going idle */
3377 is_idle_inhibited = idle_is_session_inhibited (manager,
3378 SESSION_INHIBIT_MASK_IDLE);
3379 if (is_idle_inhibited) {
3380 g_debug ("inhibited, so using normal state");
3381 idle_set_mode (manager, CSD_POWER_IDLE_MODE_NORMAL);
3382
3383 gpm_idletime_alarm_remove (manager->priv->idletime,
3384 CSD_POWER_IDLETIME_LOCK_ID);
3385 gpm_idletime_alarm_remove (manager->priv->idletime,
3386 CSD_POWER_IDLETIME_BLANK_ID);
3387 gpm_idletime_alarm_remove (manager->priv->idletime,
3388 CSD_POWER_IDLETIME_SLEEP_ID);
3389
3390 refresh_idle_dim_settings (manager);
3391 return;
3392 }
3393
3394 current_idle_time = gpm_idletime_get_time (manager->priv->idletime) / 1000;
3395
3396 /* set up blank callback even when session is not idle,
3397 * but only if we actually want to blank. */
3398 on_battery = up_client_get_on_battery (manager->priv->up_client);
3399 if (on_battery) {
3400 timeout_blank = g_settings_get_int (manager->priv->settings,
3401 "sleep-display-battery");
3402 } else {
3403 timeout_blank = g_settings_get_int (manager->priv->settings,
3404 "sleep-display-ac");
3405 }
3406
3407 /* set up custom screensaver lock after idle time trigger */
3408 timeout_lock = g_settings_get_uint (manager->priv->settings_desktop_session,
3409 "idle-delay");
3410 if (timeout_lock != 0) {
3411 if (timeout_blank != 0 && timeout_lock > timeout_blank) {
3412 g_debug ("reducing lock timeout to match blank timeout");
3413 timeout_lock = timeout_blank;
3414 }
3415 g_debug ("setting up lock callback for %is", timeout_lock);
3416
3417 gpm_idletime_alarm_set (manager->priv->idletime,
3418 CSD_POWER_IDLETIME_LOCK_ID,
3419 idle_adjust_timeout (current_idle_time, timeout_lock) * 1000);
3420 } else {
3421 gpm_idletime_alarm_remove (manager->priv->idletime,
3422 CSD_POWER_IDLETIME_LOCK_ID);
3423 }
3424
3425 if (timeout_blank != 0) {
3426 g_debug ("setting up blank callback for %is", timeout_blank);
3427
3428 gpm_idletime_alarm_set (manager->priv->idletime,
3429 CSD_POWER_IDLETIME_BLANK_ID,
3430 idle_adjust_timeout_blank (current_idle_time, timeout_blank) * 1000);
3431 } else {
3432 gpm_idletime_alarm_remove (manager->priv->idletime,
3433 CSD_POWER_IDLETIME_BLANK_ID);
3434 }
3435
3436 gboolean is_sleep_inhibited = idle_is_session_inhibited (manager,
3437 SESSION_INHIBIT_MASK_SUSPEND);
3438 /* only do the sleep timeout when the session is idle
3439 * and we aren't inhibited from sleeping */
3440 if (on_battery) {
3441 timeout_sleep = g_settings_get_int (manager->priv->settings,
3442 "sleep-inactive-battery-timeout");
3443 } else {
3444 timeout_sleep = g_settings_get_int (manager->priv->settings,
3445 "sleep-inactive-ac-timeout");
3446 }
3447 if (!is_sleep_inhibited && timeout_sleep != 0) {
3448 g_debug ("setting up sleep callback %is", timeout_sleep);
3449
3450 gpm_idletime_alarm_set (manager->priv->idletime,
3451 CSD_POWER_IDLETIME_SLEEP_ID,
3452 idle_adjust_timeout (current_idle_time, timeout_sleep) * 1000);
3453 } else {
3454 gpm_idletime_alarm_remove (manager->priv->idletime,
3455 CSD_POWER_IDLETIME_SLEEP_ID);
3456 }
3457
3458 refresh_idle_dim_settings (manager);
3459 }
3460
3461 #if UP_CHECK_VERSION(0,99,0)
3462 static void
up_client_on_battery_cb(UpClient * client,GParamSpec * pspec,CsdPowerManager * manager)3463 up_client_on_battery_cb (UpClient *client,
3464 GParamSpec *pspec,
3465 CsdPowerManager *manager)
3466 {
3467 idle_configure (manager);
3468 lid_state_changed_cb(client, pspec, manager);
3469 }
3470 #endif
3471
3472 static void
csd_power_manager_class_init(CsdPowerManagerClass * klass)3473 csd_power_manager_class_init (CsdPowerManagerClass *klass)
3474 {
3475 GObjectClass *object_class = G_OBJECT_CLASS (klass);
3476
3477 object_class->finalize = csd_power_manager_finalize;
3478
3479 g_type_class_add_private (klass, sizeof (CsdPowerManagerPrivate));
3480 }
3481
3482 static void
setup_locker_process(gpointer user_data)3483 setup_locker_process (gpointer user_data)
3484 {
3485 /* This function should only contain signal safe code, as it is invoked
3486 * between fork and exec. See signal-safety(7) for more information. */
3487 CsdPowerManager *manager = user_data;
3488
3489 /* close all FDs except stdin, stdout, stderr and the inhibition fd */
3490 for (gint fd = 3; fd < manager->priv->fd_close_loop_end; fd++)
3491 if (fd != manager->priv->inhibit_suspend_fd)
3492 close (fd);
3493
3494 /* make sure the inhibit fd does not get closed on exec, as it's options
3495 * are not specified in the logind inhibitor interface documentation. */
3496 if (-1 != manager->priv->inhibit_suspend_fd)
3497 fcntl (manager->priv->inhibit_suspend_fd,
3498 F_SETFD,
3499 ~FD_CLOEXEC & fcntl (manager->priv->inhibit_suspend_fd, F_GETFD));
3500 }
3501
3502 static void
lock_screen_with_custom_saver(CsdPowerManager * manager,gchar * custom_saver,gboolean idle_lock)3503 lock_screen_with_custom_saver (CsdPowerManager *manager,
3504 gchar *custom_saver,
3505 gboolean idle_lock)
3506 {
3507 gboolean res;
3508 gchar *fd = NULL;
3509 gchar **argv = NULL;
3510 gchar **env = NULL;
3511 GError *error = NULL;
3512
3513 /* environment setup */
3514 fd = g_strdup_printf ("%d", manager->priv->inhibit_suspend_fd);
3515 if (!fd) {
3516 g_warning ("failed to printf inhibit_suspend_fd");
3517 goto quit;
3518 }
3519 if (!(env = g_get_environ ())) {
3520 g_warning ("failed to get environment");
3521 goto quit;
3522 }
3523 env = g_environ_setenv (env, "XSS_SLEEP_LOCK_FD", fd, FALSE);
3524 if (!env) {
3525 g_warning ("failed to set XSS_SLEEP_LOCK_FD");
3526 goto quit;
3527 }
3528 env = g_environ_setenv (env,
3529 "LOCKED_BY_SESSION_IDLE",
3530 idle_lock ? "true" : "false",
3531 TRUE);
3532 if (!env) {
3533 g_warning ("failed to set LOCKED_BY_SESSION_IDLE");
3534 goto quit;
3535 }
3536
3537 /* argv setup */
3538 res = g_shell_parse_argv (custom_saver, NULL, &argv, &error);
3539 if (!res) {
3540 g_warning ("failed to parse custom saver cmd '%s': %s",
3541 custom_saver,
3542 error->message);
3543 goto quit;
3544 }
3545
3546 /* get the max number of open file descriptors */
3547 manager->priv->fd_close_loop_end = sysconf (_SC_OPEN_MAX);
3548 if (-1 == manager->priv->fd_close_loop_end)
3549 /* use some sane default */
3550 manager->priv->fd_close_loop_end = 32768;
3551
3552 /* spawn the custom screen locker */
3553 res = g_spawn_async (NULL,
3554 argv,
3555 env,
3556 G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_SEARCH_PATH,
3557 &setup_locker_process,
3558 manager,
3559 NULL,
3560 &error);
3561 if (!res)
3562 g_warning ("failed to run custom screensaver '%s': %s",
3563 custom_saver,
3564 error->message);
3565
3566 quit:
3567 g_free (fd);
3568 g_strfreev (argv);
3569 g_strfreev (env);
3570 g_clear_error (&error);
3571 }
3572
3573 static void
lock_screensaver(CsdPowerManager * manager)3574 lock_screensaver (CsdPowerManager *manager)
3575 {
3576 GError *error;
3577 gboolean ret;
3578 gchar *custom_saver = g_settings_get_string (manager->priv->settings_screensaver,
3579 "custom-screensaver-command");
3580
3581 g_debug ("Locking screen before sleep/hibernate");
3582
3583 if (custom_saver && g_strcmp0 (custom_saver, "") != 0) {
3584 lock_screen_with_custom_saver (manager, custom_saver, FALSE);
3585 goto quit;
3586 }
3587
3588 /* if we fail to get the gsettings entry, or if the user did not select
3589 * a custom screen saver, default to invoking cinnamon-screensaver */
3590 /* do this sync to ensure it's on the screen when we start suspending */
3591 error = NULL;
3592 ret = g_spawn_command_line_sync ("cinnamon-screensaver-command --lock", NULL, NULL, NULL, &error);
3593
3594 if (!ret) {
3595 g_warning ("Couldn't lock screen: %s", error->message);
3596 g_error_free (error);
3597 }
3598
3599 quit:
3600 g_free (custom_saver);
3601 }
3602
3603 static void
idle_dbus_signal_cb(GDBusProxy * proxy,const gchar * sender_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)3604 idle_dbus_signal_cb (GDBusProxy *proxy,
3605 const gchar *sender_name,
3606 const gchar *signal_name,
3607 GVariant *parameters,
3608 gpointer user_data)
3609 {
3610 CsdPowerManager *manager = CSD_POWER_MANAGER (user_data);
3611
3612 if (g_strcmp0 (signal_name, "InhibitorAdded") == 0 ||
3613 g_strcmp0 (signal_name, "InhibitorRemoved") == 0) {
3614 g_debug ("Received gnome session inhibitor change");
3615 idle_configure (manager);
3616 }
3617 if (g_strcmp0 (signal_name, "StatusChanged") == 0) {
3618 guint status;
3619
3620 g_variant_get (parameters, "(u)", &status);
3621 g_dbus_proxy_set_cached_property (proxy, "status",
3622 g_variant_new ("u", status));
3623 g_debug ("Received gnome session status change");
3624 idle_configure (manager);
3625 }
3626 }
3627
3628 static void
session_proxy_ready_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)3629 session_proxy_ready_cb (GObject *source_object,
3630 GAsyncResult *res,
3631 gpointer user_data)
3632 {
3633 GError *error = NULL;
3634 CsdPowerManager *manager = CSD_POWER_MANAGER (user_data);
3635
3636 manager->priv->session_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
3637 if (manager->priv->session_proxy == NULL) {
3638 g_warning ("Could not connect to cinnamon-session: %s",
3639 error->message);
3640 g_error_free (error);
3641 } else {
3642 g_signal_connect (manager->priv->session_proxy, "g-signal",
3643 G_CALLBACK (idle_dbus_signal_cb), manager);
3644 }
3645
3646 idle_configure (manager);
3647 }
3648
3649 static void
session_presence_proxy_ready_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)3650 session_presence_proxy_ready_cb (GObject *source_object,
3651 GAsyncResult *res,
3652 gpointer user_data)
3653 {
3654 GError *error = NULL;
3655 CsdPowerManager *manager = CSD_POWER_MANAGER (user_data);
3656
3657 manager->priv->session_presence_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
3658 if (manager->priv->session_presence_proxy == NULL) {
3659 g_warning ("Could not connect to gnome-sesson: %s",
3660 error->message);
3661 g_error_free (error);
3662 return;
3663 }
3664 g_signal_connect (manager->priv->session_presence_proxy, "g-signal",
3665 G_CALLBACK (idle_dbus_signal_cb), manager);
3666 }
3667
3668 static void
power_keyboard_proxy_ready_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)3669 power_keyboard_proxy_ready_cb (GObject *source_object,
3670 GAsyncResult *res,
3671 gpointer user_data)
3672 {
3673 GVariant *k_now = NULL;
3674 GVariant *k_max = NULL;
3675 GError *error = NULL;
3676 CsdPowerManager *manager = CSD_POWER_MANAGER (user_data);
3677
3678 manager->priv->upower_kbd_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
3679 if (manager->priv->upower_kbd_proxy == NULL) {
3680 g_warning ("Could not connect to UPower: %s",
3681 error->message);
3682 g_error_free (error);
3683 goto out;
3684 }
3685
3686 k_now = g_dbus_proxy_call_sync (manager->priv->upower_kbd_proxy,
3687 "GetBrightness",
3688 NULL,
3689 G_DBUS_CALL_FLAGS_NONE,
3690 -1,
3691 NULL,
3692 &error);
3693 if (k_now == NULL) {
3694 if (error->domain != G_DBUS_ERROR ||
3695 error->code != G_DBUS_ERROR_UNKNOWN_METHOD) {
3696 g_warning ("Failed to get brightness: %s",
3697 error->message);
3698 }
3699 g_error_free (error);
3700 goto out;
3701 }
3702
3703 k_max = g_dbus_proxy_call_sync (manager->priv->upower_kbd_proxy,
3704 "GetMaxBrightness",
3705 NULL,
3706 G_DBUS_CALL_FLAGS_NONE,
3707 -1,
3708 NULL,
3709 &error);
3710 if (k_max == NULL) {
3711 g_warning ("Failed to get max brightness: %s", error->message);
3712 g_error_free (error);
3713 goto out;
3714 }
3715
3716 g_signal_connect (manager->priv->upower_kbd_proxy, "g-signal", G_CALLBACK(upower_kbd_handle_changed), manager);
3717
3718 g_variant_get (k_now, "(i)", &manager->priv->kbd_brightness_now);
3719 g_variant_get (k_max, "(i)", &manager->priv->kbd_brightness_max);
3720
3721 /* Set keyboard brightness to zero if the current value is out of valid range.
3722 Unlike display brightness, keyboard backlight brightness should be dim by default.*/
3723 if ((manager->priv->kbd_brightness_now < 0) || (manager->priv->kbd_brightness_now > manager->priv->kbd_brightness_max)) {
3724 gboolean ret;
3725 ret = upower_kbd_set_brightness (manager,
3726 0,
3727 &error);
3728 if (!ret) {
3729 g_warning ("failed to initialize kbd backlight to %i: %s",
3730 0,
3731 error->message);
3732 g_error_free (error);
3733 }
3734 }
3735 out:
3736 if (k_now != NULL)
3737 g_variant_unref (k_now);
3738 if (k_max != NULL)
3739 g_variant_unref (k_max);
3740 }
3741
3742 static void
idle_idletime_alarm_expired_cb(GpmIdletime * idletime,guint alarm_id,CsdPowerManager * manager)3743 idle_idletime_alarm_expired_cb (GpmIdletime *idletime,
3744 guint alarm_id,
3745 CsdPowerManager *manager)
3746 {
3747 g_debug ("idletime alarm: %i", alarm_id);
3748
3749 switch (alarm_id) {
3750 case CSD_POWER_IDLETIME_DIM_ID:
3751 idle_set_mode (manager, CSD_POWER_IDLE_MODE_DIM);
3752 break;
3753 case CSD_POWER_IDLETIME_LOCK_ID:
3754 /* cinnamon-screensaver has its own lock after some idle delay.
3755 * If we have a custom screensaver configured, we have to use
3756 * the idle delay from cinnamon-settings-daemon to trigger the
3757 * screen lock after the idle timeout */
3758 ; /* empty statement, because C does not allow a declaration to
3759 * follow a label */
3760 gchar *custom_saver = g_settings_get_string (manager->priv->settings_screensaver,
3761 "custom-screensaver-command");
3762 if (custom_saver && g_strcmp0 (custom_saver, "") != 0)
3763 lock_screen_with_custom_saver (manager,
3764 custom_saver,
3765 TRUE);
3766 g_free (custom_saver);
3767
3768 break;
3769 case CSD_POWER_IDLETIME_BLANK_ID:
3770 idle_set_mode (manager, CSD_POWER_IDLE_MODE_BLANK);
3771 break;
3772 case CSD_POWER_IDLETIME_SLEEP_ID:
3773 idle_set_mode (manager, CSD_POWER_IDLE_MODE_SLEEP);
3774 break;
3775 }
3776 }
3777
3778 static void
idle_idletime_reset_cb(GpmIdletime * idletime,CsdPowerManager * manager)3779 idle_idletime_reset_cb (GpmIdletime *idletime,
3780 CsdPowerManager *manager)
3781 {
3782 g_debug ("idletime reset");
3783
3784 idle_set_mode (manager, CSD_POWER_IDLE_MODE_NORMAL);
3785 }
3786
3787 static void
engine_settings_key_changed_cb(GSettings * settings,const gchar * key,CsdPowerManager * manager)3788 engine_settings_key_changed_cb (GSettings *settings,
3789 const gchar *key,
3790 CsdPowerManager *manager)
3791 {
3792 /* note: you *have* to check if your key was changed here before
3793 * doing anything here. this gets invoked on module stop, and
3794 * will crash c-s-d if you don't. */
3795 if (g_strcmp0 (key, "use-time-for-policy") == 0) {
3796 manager->priv->use_time_primary = g_settings_get_boolean (settings, key);
3797 return;
3798 }
3799 if (g_strcmp0 (key, "idle-dim-time") == 0) {
3800 refresh_idle_dim_settings (manager);
3801 return;
3802 }
3803 if (g_str_has_prefix (key, "sleep-inactive") ||
3804 g_str_has_prefix (key, "sleep-display")) {
3805 idle_configure (manager);
3806 return;
3807 }
3808
3809 if (g_str_has_prefix (key, "backlight-helper")) {
3810 backlight_override_settings_refresh (manager);
3811 return;
3812 }
3813 }
3814
3815 static void
engine_session_active_changed_cb(CinnamonSettingsSession * session,GParamSpec * pspec,CsdPowerManager * manager)3816 engine_session_active_changed_cb (CinnamonSettingsSession *session,
3817 GParamSpec *pspec,
3818 CsdPowerManager *manager)
3819 {
3820 /* when doing the fast-user-switch into a new account,
3821 * ensure the new account is undimmed and with the backlight on */
3822 idle_set_mode (manager, CSD_POWER_IDLE_MODE_NORMAL);
3823 }
3824
3825 /* This timer goes off every few minutes, whether the user is idle or not,
3826 to try and clean up anything that has gone wrong.
3827
3828 It calls disable_builtin_screensaver() so that if xset has been used,
3829 or some other program (like xlock) has messed with the XSetScreenSaver()
3830 settings, they will be set back to sensible values (if a server extension
3831 is in use, messing with xlock can cause the screensaver to never get a wakeup
3832 event, and could cause monitor power-saving to occur, and all manner of
3833 heinousness.)
3834
3835 This code was originally part of cinnamon-screensaver, see
3836 http://git.gnome.org/browse/cinnamon-screensaver/tree/src/gs-watcher-x11.c?id=fec00b12ec46c86334cfd36b37771cc4632f0d4d#n530
3837 */
3838 static gboolean
disable_builtin_screensaver(gpointer unused)3839 disable_builtin_screensaver (gpointer unused)
3840 {
3841 int current_server_timeout, current_server_interval;
3842 int current_prefer_blank, current_allow_exp;
3843 int desired_server_timeout, desired_server_interval;
3844 int desired_prefer_blank, desired_allow_exp;
3845
3846 XGetScreenSaver (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
3847 ¤t_server_timeout,
3848 ¤t_server_interval,
3849 ¤t_prefer_blank,
3850 ¤t_allow_exp);
3851
3852 desired_server_timeout = current_server_timeout;
3853 desired_server_interval = current_server_interval;
3854 desired_prefer_blank = current_prefer_blank;
3855 desired_allow_exp = current_allow_exp;
3856
3857 desired_server_interval = 0;
3858
3859 /* I suspect (but am not sure) that DontAllowExposures might have
3860 something to do with powering off the monitor as well, at least
3861 on some systems that don't support XDPMS? Who know... */
3862 desired_allow_exp = AllowExposures;
3863
3864 /* When we're not using an extension, set the server-side timeout to 0,
3865 so that the server never gets involved with screen blanking, and we
3866 do it all ourselves. (However, when we *are* using an extension,
3867 we tell the server when to notify us, and rather than blanking the
3868 screen, the server will send us an X event telling us to blank.)
3869 */
3870 desired_server_timeout = 0;
3871
3872 if (desired_server_timeout != current_server_timeout
3873 || desired_server_interval != current_server_interval
3874 || desired_prefer_blank != current_prefer_blank
3875 || desired_allow_exp != current_allow_exp) {
3876
3877 g_debug ("disabling server builtin screensaver:"
3878 " (xset s %d %d; xset s %s; xset s %s)",
3879 desired_server_timeout,
3880 desired_server_interval,
3881 (desired_prefer_blank ? "blank" : "noblank"),
3882 (desired_allow_exp ? "expose" : "noexpose"));
3883
3884 XSetScreenSaver (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
3885 desired_server_timeout,
3886 desired_server_interval,
3887 desired_prefer_blank,
3888 desired_allow_exp);
3889
3890 XSync (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), FALSE);
3891 }
3892
3893 return TRUE;
3894 }
3895
3896 static void
inhibit_lid_switch_done(GObject * source,GAsyncResult * result,gpointer user_data)3897 inhibit_lid_switch_done (GObject *source,
3898 GAsyncResult *result,
3899 gpointer user_data)
3900 {
3901 GDBusProxy *proxy = G_DBUS_PROXY (source);
3902 CsdPowerManager *manager = CSD_POWER_MANAGER (user_data);
3903 GError *error = NULL;
3904 GVariant *res;
3905 GUnixFDList *fd_list = NULL;
3906 gint idx;
3907
3908 res = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, &fd_list, result, &error);
3909 if (res == NULL) {
3910 g_warning ("Unable to inhibit lid switch: %s", error->message);
3911 g_error_free (error);
3912 } else {
3913 g_variant_get (res, "(h)", &idx);
3914 manager->priv->inhibit_lid_switch_fd = g_unix_fd_list_get (fd_list, idx, &error);
3915 if (manager->priv->inhibit_lid_switch_fd == -1) {
3916 g_warning ("Failed to receive system inhibitor fd: %s", error->message);
3917 g_error_free (error);
3918 }
3919 g_debug ("System inhibitor fd is %d", manager->priv->inhibit_lid_switch_fd);
3920 g_object_unref (fd_list);
3921 g_variant_unref (res);
3922 }
3923 }
3924
3925 static void
inhibit_lid_switch(CsdPowerManager * manager)3926 inhibit_lid_switch (CsdPowerManager *manager)
3927 {
3928 if (!manager->priv->inhibit_lid_switch_enabled) {
3929 // The users asks us not to interfere with what logind does
3930 // w.r.t. handling the lid switch
3931 g_debug ("inhibiting lid-switch disabled");
3932 return;
3933 }
3934
3935 GVariant *params;
3936
3937 if (manager->priv->inhibit_lid_switch_taken) {
3938 g_debug ("already inhibited lid-switch");
3939 return;
3940 }
3941 g_debug ("Adding lid switch system inhibitor");
3942 manager->priv->inhibit_lid_switch_taken = TRUE;
3943
3944 params = g_variant_new ("(ssss)",
3945 "handle-lid-switch",
3946 g_get_user_name (),
3947 "Multiple displays attached",
3948 "block");
3949 g_dbus_proxy_call_with_unix_fd_list (manager->priv->logind_proxy,
3950 "Inhibit",
3951 params,
3952 0,
3953 G_MAXINT,
3954 NULL,
3955 NULL,
3956 inhibit_lid_switch_done,
3957 manager);
3958 }
3959
3960 static void
uninhibit_lid_switch(CsdPowerManager * manager)3961 uninhibit_lid_switch (CsdPowerManager *manager)
3962 {
3963 if (manager->priv->inhibit_lid_switch_fd == -1) {
3964 g_debug ("no lid-switch inhibitor");
3965 return;
3966 }
3967 g_debug ("Removing lid switch system inhibitor");
3968 close (manager->priv->inhibit_lid_switch_fd);
3969 manager->priv->inhibit_lid_switch_fd = -1;
3970 manager->priv->inhibit_lid_switch_taken = FALSE;
3971 }
3972
3973
3974 static void
inhibit_suspend_done(GObject * source,GAsyncResult * result,gpointer user_data)3975 inhibit_suspend_done (GObject *source,
3976 GAsyncResult *result,
3977 gpointer user_data)
3978 {
3979 GDBusProxy *proxy = G_DBUS_PROXY (source);
3980 CsdPowerManager *manager = CSD_POWER_MANAGER (user_data);
3981 GError *error = NULL;
3982 GVariant *res;
3983 GUnixFDList *fd_list = NULL;
3984 gint idx;
3985
3986 res = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, &fd_list, result, &error);
3987 if (res == NULL) {
3988 g_warning ("Unable to inhibit suspend: %s", error->message);
3989 g_error_free (error);
3990 } else {
3991 g_variant_get (res, "(h)", &idx);
3992 manager->priv->inhibit_suspend_fd = g_unix_fd_list_get (fd_list, idx, &error);
3993 if (manager->priv->inhibit_suspend_fd == -1) {
3994 g_warning ("Failed to receive system inhibitor fd: %s", error->message);
3995 g_error_free (error);
3996 }
3997 g_debug ("System inhibitor fd is %d", manager->priv->inhibit_suspend_fd);
3998 g_object_unref (fd_list);
3999 g_variant_unref (res);
4000 }
4001 }
4002
4003 /* We take a delay inhibitor here, which causes logind to send a
4004 * PrepareToSleep signal, which gives us a chance to lock the screen
4005 * and do some other preparations.
4006 */
4007 static void
inhibit_suspend(CsdPowerManager * manager)4008 inhibit_suspend (CsdPowerManager *manager)
4009 {
4010 if (manager->priv->inhibit_suspend_taken) {
4011 g_debug ("already inhibited lid-switch");
4012 return;
4013 }
4014 g_debug ("Adding suspend delay inhibitor");
4015 manager->priv->inhibit_suspend_taken = TRUE;
4016 g_dbus_proxy_call_with_unix_fd_list (manager->priv->logind_proxy,
4017 "Inhibit",
4018 g_variant_new ("(ssss)",
4019 "sleep",
4020 g_get_user_name (),
4021 "Cinnamon needs to lock the screen",
4022 "delay"),
4023 0,
4024 G_MAXINT,
4025 NULL,
4026 NULL,
4027 inhibit_suspend_done,
4028 manager);
4029 }
4030
4031 static void
uninhibit_suspend(CsdPowerManager * manager)4032 uninhibit_suspend (CsdPowerManager *manager)
4033 {
4034 if (manager->priv->inhibit_suspend_fd == -1) {
4035 g_debug ("no suspend delay inhibitor");
4036 return;
4037 }
4038 g_debug ("Removing suspend delay inhibitor");
4039 close (manager->priv->inhibit_suspend_fd);
4040 manager->priv->inhibit_suspend_fd = -1;
4041 manager->priv->inhibit_suspend_taken = FALSE;
4042 }
4043
4044 static void
handle_suspend_actions(CsdPowerManager * manager)4045 handle_suspend_actions (CsdPowerManager *manager)
4046 {
4047 /* Is this even necessary? We lock ahead of the suspend initiation,
4048 * during do_power_action_type(). This is a signal from logind or
4049 * upower that we're about to suspend. That may have originated in
4050 * this module, or elsewhere (cinnamon-session via menu or user
4051 * applet. Lock is handled there as well... but just in case I
4052 * suppose.)
4053 */
4054 if (should_lock_on_suspend (manager)) {
4055 lock_screensaver (manager);
4056 }
4057
4058 /* lift the delay inhibit, so logind can proceed */
4059 uninhibit_suspend (manager);
4060 }
4061
4062 static void
handle_resume_actions(CsdPowerManager * manager)4063 handle_resume_actions (CsdPowerManager *manager)
4064 {
4065 gboolean ret;
4066 GError *error = NULL;
4067
4068 /* this displays the unlock dialogue so the user doesn't have
4069 * to move the mouse or press any key before the window comes up */
4070 g_dbus_connection_call (manager->priv->connection,
4071 GS_DBUS_NAME,
4072 GS_DBUS_PATH,
4073 GS_DBUS_INTERFACE,
4074 "SimulateUserActivity",
4075 NULL, NULL,
4076 G_DBUS_CALL_FLAGS_NONE, -1,
4077 NULL, NULL, NULL);
4078
4079 /* close existing notifications on resume, the system power
4080 * state is probably different now */
4081 notify_close_if_showing (manager->priv->notification_low);
4082 notify_close_if_showing (manager->priv->notification_discharging);
4083
4084 /* ensure we turn the panel back on after resume */
4085 ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen,
4086 GNOME_RR_DPMS_ON,
4087 &error);
4088 if (!ret) {
4089 g_warning ("failed to turn the panel on after resume: %s",
4090 error->message);
4091 g_error_free (error);
4092 }
4093
4094 /* set up the delay again */
4095 inhibit_suspend (manager);
4096 }
4097
4098 #if ! UP_CHECK_VERSION(0,99,0)
4099 static void
upower_notify_sleep_cb(UpClient * client,UpSleepKind sleep_kind,CsdPowerManager * manager)4100 upower_notify_sleep_cb (UpClient *client,
4101 UpSleepKind sleep_kind,
4102 CsdPowerManager *manager)
4103 {
4104 handle_suspend_actions (manager);
4105 }
4106
4107 static void
upower_notify_resume_cb(UpClient * client,UpSleepKind sleep_kind,CsdPowerManager * manager)4108 upower_notify_resume_cb (UpClient *client,
4109 UpSleepKind sleep_kind,
4110 CsdPowerManager *manager)
4111 {
4112 handle_resume_actions (manager);
4113 }
4114 #endif
4115
4116 static void
logind_proxy_signal_cb(GDBusProxy * proxy,const gchar * sender_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)4117 logind_proxy_signal_cb (GDBusProxy *proxy,
4118 const gchar *sender_name,
4119 const gchar *signal_name,
4120 GVariant *parameters,
4121 gpointer user_data)
4122 {
4123 CsdPowerManager *manager = CSD_POWER_MANAGER (user_data);
4124 gboolean is_about_to_suspend;
4125
4126 if (g_strcmp0 (signal_name, "PrepareForSleep") != 0)
4127 return;
4128 g_variant_get (parameters, "(b)", &is_about_to_suspend);
4129 if (is_about_to_suspend) {
4130 handle_suspend_actions (manager);
4131 } else {
4132 handle_resume_actions (manager);
4133 }
4134 }
4135
4136 static gboolean
is_hardware_a_virtual_machine(void)4137 is_hardware_a_virtual_machine (void)
4138 {
4139 const gchar *str;
4140 gboolean ret = FALSE;
4141 GError *error = NULL;
4142 GVariant *inner;
4143 GVariant *variant = NULL;
4144 GDBusConnection *connection;
4145
4146 connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM,
4147 NULL,
4148 &error);
4149 if (connection == NULL) {
4150 g_warning ("system bus not available: %s", error->message);
4151 g_error_free (error);
4152 goto out;
4153 }
4154 variant = g_dbus_connection_call_sync (connection,
4155 "org.freedesktop.systemd1",
4156 "/org/freedesktop/systemd1",
4157 "org.freedesktop.DBus.Properties",
4158 "Get",
4159 g_variant_new ("(ss)",
4160 "org.freedesktop.systemd1.Manager",
4161 "Virtualization"),
4162 NULL,
4163 G_DBUS_CALL_FLAGS_NONE,
4164 -1,
4165 NULL,
4166 &error);
4167 if (variant == NULL) {
4168 g_debug ("Failed to get property '%s': %s", "Virtualization", error->message);
4169 g_error_free (error);
4170 goto out;
4171 }
4172
4173 /* on bare-metal hardware this is the empty string,
4174 * otherwise an identifier such as "kvm", "vmware", etc. */
4175 g_variant_get (variant, "(v)", &inner);
4176 str = g_variant_get_string (inner, NULL);
4177 if (str != NULL && str[0] != '\0')
4178 ret = TRUE;
4179 out:
4180 if (connection != NULL)
4181 g_object_unref (connection);
4182 if (variant != NULL)
4183 g_variant_unref (variant);
4184 return ret;
4185 }
4186
4187 gboolean
csd_power_manager_start(CsdPowerManager * manager,GError ** error)4188 csd_power_manager_start (CsdPowerManager *manager,
4189 GError **error)
4190 {
4191 gboolean ret;
4192
4193 g_debug ("Starting power manager");
4194 cinnamon_settings_profile_start (NULL);
4195
4196 /* coldplug the list of screens */
4197 manager->priv->x11_screen = gnome_rr_screen_new (gdk_screen_get_default (), error);
4198 if (manager->priv->x11_screen == NULL)
4199 return FALSE;
4200
4201 /* Set up the logind proxy */
4202 manager->priv->logind_proxy =
4203 g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
4204 0,
4205 NULL,
4206 LOGIND_DBUS_NAME,
4207 LOGIND_DBUS_PATH,
4208 LOGIND_DBUS_INTERFACE,
4209 NULL,
4210 error);
4211 g_signal_connect (manager->priv->logind_proxy, "g-signal",
4212 G_CALLBACK (logind_proxy_signal_cb),
4213 manager);
4214
4215 /* Set up a delay inhibitor to be informed about suspend attempts */
4216 inhibit_suspend (manager);
4217
4218 /* track the active session */
4219 manager->priv->session = cinnamon_settings_session_new ();
4220 g_signal_connect (manager->priv->session, "notify::state",
4221 G_CALLBACK (engine_session_active_changed_cb),
4222 manager);
4223
4224 manager->priv->kbd_brightness_old = -1;
4225 manager->priv->kbd_brightness_pre_dim = -1;
4226 manager->priv->pre_dim_brightness = -1;
4227 manager->priv->settings = g_settings_new (CSD_POWER_SETTINGS_SCHEMA);
4228 g_signal_connect (manager->priv->settings, "changed",
4229 G_CALLBACK (engine_settings_key_changed_cb), manager);
4230 manager->priv->settings_screensaver = g_settings_new (CSD_SAVER_SETTINGS_SCHEMA);
4231 manager->priv->settings_xrandr = g_settings_new (CSD_XRANDR_SETTINGS_SCHEMA);
4232 manager->priv->settings_desktop_session = g_settings_new (CSD_SESSION_SETTINGS_SCHEMA);
4233 manager->priv->settings_cinnamon_session = g_settings_new (CSD_CINNAMON_SESSION_SCHEMA);
4234 manager->priv->inhibit_lid_switch_enabled =
4235 g_settings_get_boolean (manager->priv->settings, "inhibit-lid-switch");
4236
4237 /* Disable logind's lid handling while g-s-d is active */
4238 inhibit_lid_switch (manager);
4239
4240 manager->priv->up_client = up_client_new ();
4241 #if ! UP_CHECK_VERSION(0,99,0)
4242 g_signal_connect (manager->priv->up_client, "notify-sleep",
4243 G_CALLBACK (upower_notify_sleep_cb), manager);
4244 g_signal_connect (manager->priv->up_client, "notify-resume",
4245 G_CALLBACK (upower_notify_resume_cb), manager);
4246 #endif
4247 manager->priv->lid_is_closed = up_client_get_lid_is_closed (manager->priv->up_client);
4248 manager->priv->on_battery = up_client_get_on_battery(manager->priv->up_client);
4249 g_signal_connect (manager->priv->up_client, "device-added",
4250 G_CALLBACK (engine_device_added_cb), manager);
4251 g_signal_connect (manager->priv->up_client, "device-removed",
4252 G_CALLBACK (engine_device_removed_cb), manager);
4253 #if UP_CHECK_VERSION(0,99,0)
4254 g_signal_connect_after (manager->priv->up_client, "notify::lid-is-closed",
4255 G_CALLBACK (lid_state_changed_cb), manager);
4256
4257 g_signal_connect (manager->priv->up_client, "notify::on-battery",
4258 G_CALLBACK (up_client_on_battery_cb), manager);
4259 #else
4260 g_signal_connect (manager->priv->up_client, "device-changed",
4261 G_CALLBACK (engine_device_changed_cb), manager);
4262 g_signal_connect_after (manager->priv->up_client, "changed",
4263 G_CALLBACK (up_client_changed_cb), manager);
4264 #endif
4265
4266 /* use the fallback name from gnome-power-manager so the shell
4267 * blocks this, and uses the power extension instead */
4268 manager->priv->status_icon = gtk_status_icon_new ();
4269 gtk_status_icon_set_name (manager->priv->status_icon,
4270 "gnome-power-manager");
4271 /* TRANSLATORS: this is the title of the power manager status icon
4272 * that is only shown in fallback mode */
4273 gtk_status_icon_set_title (manager->priv->status_icon, _("Power Manager"));
4274 gtk_status_icon_set_visible (manager->priv->status_icon, FALSE);
4275
4276 /* connect to UPower for keyboard backlight control */
4277 g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
4278 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
4279 NULL,
4280 UPOWER_DBUS_NAME,
4281 UPOWER_DBUS_PATH_KBDBACKLIGHT,
4282 UPOWER_DBUS_INTERFACE_KBDBACKLIGHT,
4283 NULL,
4284 power_keyboard_proxy_ready_cb,
4285 manager);
4286
4287 /* connect to the session */
4288 g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
4289 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
4290 NULL,
4291 GNOME_SESSION_DBUS_NAME,
4292 GNOME_SESSION_DBUS_PATH,
4293 GNOME_SESSION_DBUS_INTERFACE,
4294 NULL,
4295 session_proxy_ready_cb,
4296 manager);
4297 g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
4298 0,
4299 NULL,
4300 GNOME_SESSION_DBUS_NAME,
4301 GNOME_SESSION_DBUS_PATH_PRESENCE,
4302 GNOME_SESSION_DBUS_INTERFACE_PRESENCE,
4303 NULL,
4304 session_presence_proxy_ready_cb,
4305 manager);
4306
4307 manager->priv->devices_array = g_ptr_array_new_with_free_func (g_object_unref);
4308 manager->priv->canberra_context = ca_gtk_context_get_for_screen (gdk_screen_get_default ());
4309
4310 manager->priv->phone = gpm_phone_new ();
4311 g_signal_connect (manager->priv->phone, "device-added",
4312 G_CALLBACK (phone_device_added_cb), manager);
4313 g_signal_connect (manager->priv->phone, "device-removed",
4314 G_CALLBACK (phone_device_removed_cb), manager);
4315 g_signal_connect (manager->priv->phone, "device-refresh",
4316 G_CALLBACK (phone_device_refresh_cb), manager);
4317
4318 /* create a fake virtual composite battery */
4319 manager->priv->device_composite = up_device_new ();
4320 g_object_set (manager->priv->device_composite,
4321 "kind", UP_DEVICE_KIND_BATTERY,
4322 "is-rechargeable", TRUE,
4323 "native-path", "dummy:composite_battery",
4324 "power-supply", TRUE,
4325 "is-present", TRUE,
4326 NULL);
4327
4328 /* get backlight setting overrides */
4329 manager->priv->backlight_helper_preference_args = NULL;
4330 backlight_override_settings_refresh (manager);
4331
4332 /* get percentage policy */
4333 manager->priv->low_percentage = g_settings_get_int (manager->priv->settings,
4334 "percentage-low");
4335 manager->priv->critical_percentage = g_settings_get_int (manager->priv->settings,
4336 "percentage-critical");
4337 manager->priv->action_percentage = g_settings_get_int (manager->priv->settings,
4338 "percentage-action");
4339
4340 /* get time policy */
4341 manager->priv->low_time = g_settings_get_int (manager->priv->settings,
4342 "time-low");
4343 manager->priv->critical_time = g_settings_get_int (manager->priv->settings,
4344 "time-critical");
4345 manager->priv->action_time = g_settings_get_int (manager->priv->settings,
4346 "time-action");
4347
4348 /* we can disable this if the time remaining is inaccurate or just plain wrong */
4349 manager->priv->use_time_primary = g_settings_get_boolean (manager->priv->settings,
4350 "use-time-for-policy");
4351
4352 /* create IDLETIME watcher */
4353 manager->priv->idletime = gpm_idletime_new ();
4354 g_signal_connect (manager->priv->idletime, "reset",
4355 G_CALLBACK (idle_idletime_reset_cb), manager);
4356 g_signal_connect (manager->priv->idletime, "alarm-expired",
4357 G_CALLBACK (idle_idletime_alarm_expired_cb), manager);
4358
4359 /* set up the screens */
4360 g_signal_connect (manager->priv->x11_screen, "changed", G_CALLBACK (on_randr_event), manager);
4361 on_randr_event (manager->priv->x11_screen, manager);
4362
4363 /* ensure the default dpms timeouts are cleared */
4364 ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen,
4365 GNOME_RR_DPMS_ON,
4366 error);
4367 if (!ret) {
4368 g_warning ("Failed set DPMS mode: %s", (*error)->message);
4369 g_clear_error (error);
4370 }
4371
4372 /* coldplug the engine */
4373 engine_coldplug (manager);
4374
4375 /* Make sure that Xorg's DPMS extension never gets in our way. The defaults seem to have changed in Xorg 1.14
4376 * being "0" by default to being "600" by default
4377 * https://bugzilla.gnome.org/show_bug.cgi?id=709114
4378 */
4379 gdk_x11_display_error_trap_push (gdk_display_get_default ());
4380 int dummy;
4381 if (DPMSQueryExtension(GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &dummy, &dummy)) {
4382 DPMSSetTimeouts (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), 0, 0, 0);
4383 }
4384 gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ());
4385
4386 manager->priv->xscreensaver_watchdog_timer_id = g_timeout_add_seconds (XSCREENSAVER_WATCHDOG_TIMEOUT,
4387 disable_builtin_screensaver,
4388 NULL);
4389 /* don't blank inside a VM */
4390 manager->priv->is_virtual_machine = is_hardware_a_virtual_machine ();
4391
4392 cinnamon_settings_profile_end (NULL);
4393 return TRUE;
4394 }
4395
4396 void
csd_power_manager_stop(CsdPowerManager * manager)4397 csd_power_manager_stop (CsdPowerManager *manager)
4398 {
4399 g_debug ("Stopping power manager");
4400
4401 if (manager->priv->bus_cancellable != NULL) {
4402 g_cancellable_cancel (manager->priv->bus_cancellable);
4403 g_object_unref (manager->priv->bus_cancellable);
4404 manager->priv->bus_cancellable = NULL;
4405 }
4406
4407 kill_lid_close_safety_timer (manager);
4408
4409 g_signal_handlers_disconnect_by_data (manager->priv->up_client, manager);
4410
4411 if (manager->priv->connection != NULL) {
4412 g_object_unref (manager->priv->connection);
4413 manager->priv->connection = NULL;
4414 }
4415
4416 if (manager->priv->session != NULL) {
4417 g_object_unref (manager->priv->session);
4418 manager->priv->session = NULL;
4419 }
4420
4421 if (manager->priv->settings != NULL) {
4422 g_object_unref (manager->priv->settings);
4423 manager->priv->settings = NULL;
4424 }
4425
4426 if (manager->priv->settings_screensaver != NULL) {
4427 g_object_unref (manager->priv->settings_screensaver);
4428 manager->priv->settings_screensaver = NULL;
4429 }
4430
4431 if (manager->priv->settings_xrandr != NULL) {
4432 g_object_unref (manager->priv->settings_xrandr);
4433 manager->priv->settings_xrandr = NULL;
4434 }
4435
4436 if (manager->priv->settings_desktop_session != NULL) {
4437 g_object_unref (manager->priv->settings_desktop_session);
4438 manager->priv->settings_desktop_session = NULL;
4439 }
4440
4441 if (manager->priv->settings_cinnamon_session != NULL) {
4442 g_object_unref (manager->priv->settings_cinnamon_session);
4443 manager->priv->settings_cinnamon_session = NULL;
4444 }
4445
4446 if (manager->priv->up_client != NULL) {
4447 g_object_unref (manager->priv->up_client);
4448 manager->priv->up_client = NULL;
4449 }
4450
4451 if (manager->priv->inhibit_lid_switch_fd != -1) {
4452 close (manager->priv->inhibit_lid_switch_fd);
4453 manager->priv->inhibit_lid_switch_fd = -1;
4454 manager->priv->inhibit_lid_switch_taken = FALSE;
4455 }
4456 if (manager->priv->inhibit_suspend_fd != -1) {
4457 close (manager->priv->inhibit_suspend_fd);
4458 manager->priv->inhibit_suspend_fd = -1;
4459 manager->priv->inhibit_suspend_taken = FALSE;
4460 }
4461
4462 if (manager->priv->logind_proxy != NULL) {
4463 g_object_unref (manager->priv->logind_proxy);
4464 manager->priv->logind_proxy = NULL;
4465 }
4466
4467 g_free (manager->priv->backlight_helper_preference_args);
4468 manager->priv->backlight_helper_preference_args = NULL;
4469
4470 if (manager->priv->x11_screen != NULL) {
4471 g_object_unref (manager->priv->x11_screen);
4472 manager->priv->x11_screen = NULL;
4473 }
4474
4475 g_ptr_array_unref (manager->priv->devices_array);
4476 manager->priv->devices_array = NULL;
4477
4478 if (manager->priv->phone != NULL) {
4479 g_object_unref (manager->priv->phone);
4480 manager->priv->phone = NULL;
4481 }
4482
4483 if (manager->priv->device_composite != NULL) {
4484 g_object_unref (manager->priv->device_composite);
4485 manager->priv->device_composite = NULL;
4486 }
4487
4488 if (manager->priv->previous_icon != NULL) {
4489 g_object_unref (manager->priv->previous_icon);
4490 manager->priv->previous_icon = NULL;
4491 }
4492
4493 g_free (manager->priv->previous_summary);
4494 manager->priv->previous_summary = NULL;
4495
4496 if (manager->priv->session_proxy != NULL) {
4497 g_object_unref (manager->priv->session_proxy);
4498 manager->priv->session_proxy = NULL;
4499 }
4500
4501 if (manager->priv->session_presence_proxy != NULL) {
4502 g_object_unref (manager->priv->session_presence_proxy);
4503 manager->priv->session_presence_proxy = NULL;
4504 }
4505
4506 if (manager->priv->critical_alert_timeout_id > 0) {
4507 g_source_remove (manager->priv->critical_alert_timeout_id);
4508 manager->priv->critical_alert_timeout_id = 0;
4509 }
4510 g_signal_handlers_disconnect_by_func (manager->priv->idletime,
4511 idle_idletime_reset_cb,
4512 manager);
4513 g_signal_handlers_disconnect_by_func (manager->priv->idletime,
4514 idle_idletime_alarm_expired_cb,
4515 manager);
4516
4517 if (manager->priv->idletime != NULL) {
4518 g_object_unref (manager->priv->idletime);
4519 manager->priv->idletime = NULL;
4520 }
4521
4522 if (manager->priv->status_icon != NULL) {
4523 g_object_unref (manager->priv->status_icon);
4524 manager->priv->status_icon = NULL;
4525 }
4526
4527 if (manager->priv->xscreensaver_watchdog_timer_id > 0) {
4528 g_source_remove (manager->priv->xscreensaver_watchdog_timer_id);
4529 manager->priv->xscreensaver_watchdog_timer_id = 0;
4530 }
4531
4532 g_clear_object (&manager->priv->power_iface);
4533 g_clear_object (&manager->priv->screen_iface);
4534 g_clear_object (&manager->priv->keyboard_iface);
4535 }
4536
4537 static void
csd_power_manager_init(CsdPowerManager * manager)4538 csd_power_manager_init (CsdPowerManager *manager)
4539 {
4540 manager->priv = CSD_POWER_MANAGER_GET_PRIVATE (manager);
4541 manager->priv->inhibit_lid_switch_fd = -1;
4542 manager->priv->inhibit_suspend_fd = -1;
4543 }
4544
4545 static void
csd_power_manager_finalize(GObject * object)4546 csd_power_manager_finalize (GObject *object)
4547 {
4548 CsdPowerManager *manager;
4549
4550 manager = CSD_POWER_MANAGER (object);
4551
4552 g_return_if_fail (manager->priv != NULL);
4553
4554 if (manager->priv->p_name_id != 0)
4555 g_bus_unown_name (manager->priv->p_name_id);
4556
4557 if (manager->priv->s_name_id != 0)
4558 g_bus_unown_name (manager->priv->s_name_id);
4559
4560 if (manager->priv->k_name_id != 0)
4561 g_bus_unown_name (manager->priv->k_name_id);
4562
4563 G_OBJECT_CLASS (csd_power_manager_parent_class)->finalize (object);
4564 }
4565
4566 #if !UP_CHECK_VERSION(0,99,0)
4567 #define UP_DEVICE_LEVEL_NONE 1
4568 #endif
4569
4570 static GVariant *
device_to_variant_blob(UpDevice * device)4571 device_to_variant_blob (UpDevice *device)
4572 {
4573 const gchar *object_path, *vendor, *model;
4574 gchar *device_icon;
4575 gdouble percentage;
4576 GIcon *icon;
4577 guint64 time_empty, time_full;
4578 guint64 time_state = 0;
4579 GVariant *value;
4580 UpDeviceKind kind;
4581 UpDeviceState state;
4582 gint battery_level;
4583
4584 icon = gpm_upower_get_device_icon (device, TRUE);
4585 device_icon = g_icon_to_string (icon);
4586 g_object_get (device,
4587 "vendor", &vendor,
4588 "model", &model,
4589 "kind", &kind,
4590 "percentage", &percentage,
4591 "state", &state,
4592 "time-to-empty", &time_empty,
4593 "time-to-full", &time_full,
4594 NULL);
4595
4596 /* upower < 0.99.5 compatibility */
4597 if (g_object_class_find_property (G_OBJECT_GET_CLASS (device), "battery-level")) {
4598 g_object_get (device,
4599 "battery-level", &battery_level,
4600 NULL);
4601 } else {
4602 battery_level = UP_DEVICE_LEVEL_NONE;
4603 }
4604
4605 /* only return time for these simple states */
4606 if (state == UP_DEVICE_STATE_DISCHARGING)
4607 time_state = time_empty;
4608 else if (state == UP_DEVICE_STATE_CHARGING)
4609 time_state = time_full;
4610
4611 /* get an object path, even for the composite device */
4612 object_path = up_device_get_object_path (device);
4613 if (object_path == NULL)
4614 object_path = CSD_POWER_DBUS_PATH;
4615
4616 /* format complex object */
4617 value = g_variant_new ("(sssusduut)",
4618 object_path,
4619 vendor,
4620 model,
4621 kind,
4622 device_icon,
4623 percentage,
4624 state,
4625 battery_level,
4626 time_state);
4627 g_free (device_icon);
4628 g_object_unref (icon);
4629 return value;
4630 }
4631
4632 /* returns new level */
4633 static void
handle_method_call_keyboard(CsdPowerManager * manager,const gchar * method_name,GVariant * parameters,GDBusMethodInvocation * invocation)4634 handle_method_call_keyboard (CsdPowerManager *manager,
4635 const gchar *method_name,
4636 GVariant *parameters,
4637 GDBusMethodInvocation *invocation)
4638 {
4639 gint step;
4640 gint value = -1;
4641 gboolean ret;
4642 guint percentage;
4643 GError *error = NULL;
4644
4645 if (g_strcmp0 (method_name, "GetPercentage") == 0) {
4646 g_debug ("keyboard get percentage");
4647 ret = upower_kbd_get_percentage (manager, &error);
4648 value = manager->priv->kbd_brightness_now;
4649
4650 } else if (g_strcmp0 (method_name, "SetPercentage") == 0) {
4651 g_debug ("keyboard set percentage");
4652
4653 guint value_tmp;
4654 g_variant_get (parameters, "(u)", &percentage);
4655 value_tmp = PERCENTAGE_TO_ABS (0, manager->priv->kbd_brightness_max, percentage);
4656
4657 ret = upower_kbd_set_brightness (manager, value_tmp, &error);
4658 if (ret)
4659 value = value_tmp;
4660
4661 } else if (g_strcmp0 (method_name, "StepUp") == 0) {
4662 g_debug ("keyboard step up");
4663 step = BRIGHTNESS_STEP_AMOUNT (manager->priv->kbd_brightness_max);
4664 value = MIN (manager->priv->kbd_brightness_now + step,
4665 manager->priv->kbd_brightness_max);
4666 ret = upower_kbd_set_brightness (manager, value, &error);
4667
4668 } else if (g_strcmp0 (method_name, "StepDown") == 0) {
4669 g_debug ("keyboard step down");
4670 step = BRIGHTNESS_STEP_AMOUNT (manager->priv->kbd_brightness_max);
4671 value = MAX (manager->priv->kbd_brightness_now - step, 0);
4672 ret = upower_kbd_set_brightness (manager, value, &error);
4673 } else if (g_strcmp0 (method_name, "GetStep") == 0) {
4674 g_debug ("keyboard get step");
4675 value = BRIGHTNESS_STEP_AMOUNT (manager->priv->kbd_brightness_max);
4676 ret = (value > 0);
4677 } else if (g_strcmp0 (method_name, "Toggle") == 0) {
4678 ret = upower_kbd_toggle (manager, &error);
4679 value = manager->priv->kbd_brightness_now;
4680 } else {
4681 g_assert_not_reached ();
4682 }
4683
4684 /* return value */
4685 if (!ret) {
4686 g_dbus_method_invocation_return_gerror (invocation,
4687 error);
4688 g_error_free (error);
4689 } else {
4690 percentage = ABS_TO_PERCENTAGE (0,
4691 manager->priv->kbd_brightness_max,
4692 value);
4693 g_dbus_method_invocation_return_value (invocation,
4694 g_variant_new ("(u)", percentage));
4695 }
4696 }
4697
4698 static void
handle_method_call_screen(CsdPowerManager * manager,const gchar * method_name,GVariant * parameters,GDBusMethodInvocation * invocation)4699 handle_method_call_screen (CsdPowerManager *manager,
4700 const gchar *method_name,
4701 GVariant *parameters,
4702 GDBusMethodInvocation *invocation)
4703 {
4704 gboolean ret = FALSE;
4705 gint value = -1;
4706 guint value_tmp;
4707 GError *error = NULL;
4708
4709 if ((g_strcmp0 (method_name, "GetPercentage") == 0) || (g_strcmp0 (method_name, "SetPercentage") == 0)) {
4710 if (g_strcmp0 (method_name, "GetPercentage") == 0) {
4711 g_debug ("screen get percentage");
4712 value = backlight_get_percentage (manager, &error);
4713
4714 } else if (g_strcmp0 (method_name, "SetPercentage") == 0) {
4715 g_debug ("screen set percentage");
4716 g_variant_get (parameters, "(u)", &value_tmp);
4717 ret = backlight_set_percentage (manager, value_tmp, TRUE, &error);
4718 if (ret)
4719 value = value_tmp;
4720 }
4721
4722 /* return value */
4723 if (value < 0) {
4724 g_dbus_method_invocation_return_gerror (invocation,
4725 error);
4726 g_error_free (error);
4727 } else {
4728 g_dbus_method_invocation_return_value (invocation,
4729 g_variant_new ("(u)",
4730 value));
4731 }
4732 } else if ((g_strcmp0 (method_name, "StepUp") == 0) || (g_strcmp0 (method_name, "StepDown") == 0)) {
4733 if (g_strcmp0 (method_name, "StepUp") == 0) {
4734 g_debug ("screen step up");
4735 value = backlight_step_up (manager, &error);
4736 } else if (g_strcmp0 (method_name, "StepDown") == 0) {
4737 g_debug ("screen step down");
4738 value = backlight_step_down (manager, &error);
4739 }
4740
4741 /* return value */
4742 if (value < 0) {
4743 g_dbus_method_invocation_return_gerror (invocation,
4744 error);
4745 g_error_free (error);
4746 } else {
4747 g_dbus_method_invocation_return_value (invocation,
4748 g_variant_new ("(ui)",
4749 value,
4750 backlight_get_output_id (manager)));
4751 }
4752 } else {
4753 g_assert_not_reached ();
4754 }
4755 }
4756
4757 static gboolean
screen_iface_method_cb(CsdScreen * object,GDBusMethodInvocation * invocation,gpointer user_data)4758 screen_iface_method_cb (CsdScreen *object,
4759 GDBusMethodInvocation *invocation,
4760 gpointer user_data)
4761 {
4762 CsdPowerManager *manager = CSD_POWER_MANAGER (user_data);
4763
4764 handle_method_call_screen (manager,
4765 g_dbus_method_invocation_get_method_name (invocation),
4766 g_dbus_method_invocation_get_parameters (invocation),
4767 invocation);
4768
4769 return TRUE;
4770 }
4771
4772 static gboolean
screen_iface_set_method_cb(CsdScreen * object,GDBusMethodInvocation * invocation,guint percent,gpointer user_data)4773 screen_iface_set_method_cb (CsdScreen *object,
4774 GDBusMethodInvocation *invocation,
4775 guint percent,
4776 gpointer user_data)
4777 {
4778 CsdPowerManager *manager = CSD_POWER_MANAGER (user_data);
4779
4780 handle_method_call_screen (manager,
4781 g_dbus_method_invocation_get_method_name (invocation),
4782 g_dbus_method_invocation_get_parameters (invocation),
4783 invocation);
4784
4785 return TRUE;
4786 }
4787
4788 static gboolean
keyboard_iface_method_cb(CsdScreen * object,GDBusMethodInvocation * invocation,gpointer user_data)4789 keyboard_iface_method_cb (CsdScreen *object,
4790 GDBusMethodInvocation *invocation,
4791 gpointer user_data)
4792 {
4793 CsdPowerManager *manager = CSD_POWER_MANAGER (user_data);
4794
4795 handle_method_call_keyboard (manager,
4796 g_dbus_method_invocation_get_method_name (invocation),
4797 g_dbus_method_invocation_get_parameters (invocation),
4798 invocation);
4799
4800 return TRUE;
4801 }
4802
4803 static gboolean
keyboard_iface_set_method_cb(CsdScreen * object,GDBusMethodInvocation * invocation,guint percent,gpointer user_data)4804 keyboard_iface_set_method_cb (CsdScreen *object,
4805 GDBusMethodInvocation *invocation,
4806 guint percent,
4807 gpointer user_data)
4808 {
4809 CsdPowerManager *manager = CSD_POWER_MANAGER (user_data);
4810
4811 handle_method_call_keyboard (manager,
4812 g_dbus_method_invocation_get_method_name (invocation),
4813 g_dbus_method_invocation_get_parameters (invocation),
4814 invocation);
4815
4816 return TRUE;
4817 }
4818
4819 static gboolean
power_iface_handle_get_primary_device(CsdPower * object,GDBusMethodInvocation * invocation,gpointer user_data)4820 power_iface_handle_get_primary_device (CsdPower *object,
4821 GDBusMethodInvocation *invocation,
4822 gpointer user_data)
4823 {
4824 CsdPowerManager *manager = CSD_POWER_MANAGER (user_data);
4825 UpDevice *device;
4826 GVariant *tuple = NULL;
4827 GVariant *value = NULL;
4828
4829 g_debug ("Handling Power interface method GetPrimaryDevice");
4830
4831 /* get the virtual device */
4832 device = engine_get_primary_device (manager);
4833 if (device == NULL) {
4834 g_dbus_method_invocation_return_dbus_error (invocation,
4835 "org.cinnamon.SettingsDaemon.Power.Failed",
4836 "There is no primary device.");
4837 return TRUE;
4838 }
4839
4840 /* return the value */
4841 value = device_to_variant_blob (device);
4842 tuple = g_variant_new_tuple (&value, 1);
4843 g_dbus_method_invocation_return_value (invocation, tuple);
4844 g_object_unref (device);
4845
4846 return TRUE;
4847 }
4848
4849 static gboolean
power_iface_handle_get_devices(CsdPower * object,GDBusMethodInvocation * invocation,gpointer user_data)4850 power_iface_handle_get_devices (CsdPower *object,
4851 GDBusMethodInvocation *invocation,
4852 gpointer user_data)
4853 {
4854 CsdPowerManager *manager = CSD_POWER_MANAGER (user_data);
4855 UpDevice *device;
4856 GPtrArray *array;
4857 guint i;
4858 GVariantBuilder *builder;
4859 GVariant *tuple = NULL;
4860 GVariant *value = NULL;
4861
4862 g_debug ("Handling Power interface method GetDevices");
4863
4864 /* create builder */
4865 builder = g_variant_builder_new (G_VARIANT_TYPE("a(sssusduut)"));
4866
4867 /* add each tuple to the array */
4868 array = manager->priv->devices_array;
4869 for (i=0; i<array->len; i++) {
4870 device = g_ptr_array_index (array, i);
4871 value = device_to_variant_blob (device);
4872 g_variant_builder_add_value (builder, value);
4873 }
4874
4875 /* return the value */
4876 value = g_variant_builder_end (builder);
4877 tuple = g_variant_new_tuple (&value, 1);
4878 g_dbus_method_invocation_return_value (invocation, tuple);
4879 g_variant_builder_unref (builder);
4880
4881 return TRUE;
4882 }
4883
4884 static void
power_name_acquired(GDBusConnection * connection,const gchar * name,gpointer user_data)4885 power_name_acquired (GDBusConnection *connection,
4886 const gchar *name,
4887 gpointer user_data)
4888 {
4889 CsdPower *iface;
4890 CsdPowerManager *manager = CSD_POWER_MANAGER (user_data);
4891
4892 iface = csd_power_skeleton_new ();
4893
4894 g_signal_connect (iface,
4895 "handle-get-primary-device",
4896 G_CALLBACK (power_iface_handle_get_primary_device),
4897 manager);
4898
4899 g_signal_connect (iface,
4900 "handle-get-devices",
4901 G_CALLBACK (power_iface_handle_get_devices),
4902 manager);
4903
4904 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (iface),
4905 connection,
4906 CSD_POWER_DBUS_PATH,
4907 NULL);
4908
4909 manager->priv->power_iface = iface;
4910
4911 engine_recalculate_state (manager);
4912 }
4913
4914 static void
screen_name_acquired(GDBusConnection * connection,const gchar * name,gpointer user_data)4915 screen_name_acquired (GDBusConnection *connection,
4916 const gchar *name,
4917 gpointer user_data)
4918 {
4919 CsdScreen *iface;
4920 CsdPowerManager *manager = CSD_POWER_MANAGER (user_data);
4921
4922 iface = csd_screen_skeleton_new ();
4923
4924 g_signal_connect (iface,
4925 "handle-get-percentage",
4926 G_CALLBACK (screen_iface_method_cb),
4927 manager);
4928
4929 g_signal_connect (iface,
4930 "handle-set-percentage",
4931 G_CALLBACK (screen_iface_set_method_cb),
4932 manager);
4933
4934 g_signal_connect (iface,
4935 "handle-step-down",
4936 G_CALLBACK (screen_iface_method_cb),
4937 manager);
4938
4939 g_signal_connect (iface,
4940 "handle-step-up",
4941 G_CALLBACK (screen_iface_method_cb),
4942 manager);
4943
4944 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (iface),
4945 connection,
4946 CSD_POWER_DBUS_PATH,
4947 NULL);
4948
4949 manager->priv->screen_iface = iface;
4950
4951 backlight_emit_changed (manager);
4952 }
4953
4954 static void
keyboard_name_acquired(GDBusConnection * connection,const gchar * name,gpointer user_data)4955 keyboard_name_acquired (GDBusConnection *connection,
4956 const gchar *name,
4957 gpointer user_data)
4958 {
4959 CsdKeyboard *iface;
4960 CsdPowerManager *manager = CSD_POWER_MANAGER (user_data);
4961
4962 iface = csd_keyboard_skeleton_new ();
4963
4964 g_signal_connect (iface,
4965 "handle-get-percentage",
4966 G_CALLBACK (keyboard_iface_method_cb),
4967 manager);
4968
4969 g_signal_connect (iface,
4970 "handle-set-percentage",
4971 G_CALLBACK (keyboard_iface_set_method_cb),
4972 manager);
4973
4974 g_signal_connect (iface,
4975 "handle-step-down",
4976 G_CALLBACK (keyboard_iface_method_cb),
4977 manager);
4978
4979 g_signal_connect (iface,
4980 "handle-step-up",
4981 G_CALLBACK (keyboard_iface_method_cb),
4982 manager);
4983
4984 g_signal_connect (iface,
4985 "handle-get-step",
4986 G_CALLBACK (keyboard_iface_method_cb),
4987 manager);
4988
4989 g_signal_connect (iface,
4990 "handle-toggle",
4991 G_CALLBACK (keyboard_iface_method_cb),
4992 manager);
4993
4994 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (iface),
4995 connection,
4996 CSD_POWER_DBUS_PATH,
4997 NULL);
4998
4999 manager->priv->keyboard_iface = iface;
5000
5001 upower_kbd_emit_changed (manager);
5002 }
5003
5004 static void
on_bus_gotten(GObject * source_object,GAsyncResult * res,CsdPowerManager * manager)5005 on_bus_gotten (GObject *source_object,
5006 GAsyncResult *res,
5007 CsdPowerManager *manager)
5008 {
5009 GDBusConnection *connection;
5010 GError *error = NULL;
5011
5012 if (manager->priv->bus_cancellable == NULL ||
5013 g_cancellable_is_cancelled (manager->priv->bus_cancellable)) {
5014 g_warning ("Operation has been cancelled, so not retrieving session bus");
5015 return;
5016 }
5017
5018 connection = g_bus_get_finish (res, &error);
5019 if (connection == NULL) {
5020 g_warning ("Could not get session bus: %s", error->message);
5021 g_error_free (error);
5022 return;
5023 }
5024
5025 manager->priv->connection = connection;
5026
5027 manager->priv->p_name_id = g_bus_own_name_on_connection (connection,
5028 CSD_POWER_DBUS_INTERFACE,
5029 G_BUS_NAME_OWNER_FLAGS_NONE,
5030 power_name_acquired,
5031 NULL,
5032 manager,
5033 NULL);
5034 manager->priv->s_name_id = g_bus_own_name_on_connection (connection,
5035 CSD_POWER_DBUS_INTERFACE_SCREEN,
5036 G_BUS_NAME_OWNER_FLAGS_NONE,
5037 screen_name_acquired,
5038 NULL,
5039 manager,
5040 NULL);
5041 manager->priv->k_name_id = g_bus_own_name_on_connection (connection,
5042 CSD_POWER_DBUS_INTERFACE_KEYBOARD,
5043 G_BUS_NAME_OWNER_FLAGS_NONE,
5044 keyboard_name_acquired,
5045 NULL,
5046 manager,
5047 NULL);
5048 }
5049
5050 static void
register_manager_dbus(CsdPowerManager * manager)5051 register_manager_dbus (CsdPowerManager *manager)
5052 {
5053 manager->priv->bus_cancellable = g_cancellable_new ();
5054
5055 g_bus_get (G_BUS_TYPE_SESSION,
5056 manager->priv->bus_cancellable,
5057 (GAsyncReadyCallback) on_bus_gotten,
5058 manager);
5059 }
5060
5061 CsdPowerManager *
csd_power_manager_new(void)5062 csd_power_manager_new (void)
5063 {
5064 if (manager_object != NULL) {
5065 g_object_ref (manager_object);
5066 } else {
5067 manager_object = g_object_new (CSD_TYPE_POWER_MANAGER, NULL);
5068 g_object_add_weak_pointer (manager_object,
5069 (gpointer *) &manager_object);
5070 register_manager_dbus (manager_object);
5071 }
5072 return CSD_POWER_MANAGER (manager_object);
5073 }
5074