1 /*
2 * Copyright (C) 2010-2011 Robert Ancell.
3 * Author: Robert Ancell <robert.ancell@canonical.com>
4 *
5 * This library is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU Lesser General Public License as published by the Free
7 * Software Foundation; either version 2 or version 3 of the License.
8 * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
9 */
10
11 #include <config.h>
12
13 #include <string.h>
14 #include <gio/gio.h>
15
16 #include "lightdm/power.h"
17
18 /**
19 * SECTION:power
20 * @title: Power Management
21 * @short_description: Shutdown, restart, sleep the system
22 * @include: lightdm.h
23 *
24 * Helper functions to perform power management operations.
25 */
26
27 static GDBusProxy *upower_proxy = NULL;
28 static GDBusProxy *ck_proxy = NULL;
29 static GDBusProxy *login1_proxy = NULL;
30
31 static GVariant *
upower_call_function(const gchar * function,GError ** error)32 upower_call_function (const gchar *function, GError **error)
33 {
34 if (!upower_proxy)
35 {
36 upower_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
37 G_DBUS_PROXY_FLAGS_NONE,
38 NULL,
39 "org.freedesktop.UPower",
40 "/org/freedesktop/UPower",
41 "org.freedesktop.UPower",
42 NULL,
43 error);
44 if (!upower_proxy)
45 return NULL;
46 }
47
48 return g_dbus_proxy_call_sync (upower_proxy,
49 function,
50 NULL,
51 G_DBUS_CALL_FLAGS_NONE,
52 -1,
53 NULL,
54 error);
55 }
56
57 static GVariant *
login1_call_function(const gchar * function,GVariant * parameters,GError ** error)58 login1_call_function (const gchar *function, GVariant *parameters, GError **error)
59 {
60 if (!login1_proxy)
61 {
62 login1_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
63 G_DBUS_PROXY_FLAGS_NONE,
64 NULL,
65 "org.freedesktop.login1",
66 "/org/freedesktop/login1",
67 "org.freedesktop.login1.Manager",
68 NULL,
69 error);
70 if (!login1_proxy)
71 return NULL;
72 }
73
74 return g_dbus_proxy_call_sync (login1_proxy,
75 function,
76 parameters,
77 G_DBUS_CALL_FLAGS_NONE,
78 -1,
79 NULL,
80 error);
81 }
82
83 static GVariant *
ck_call_function(const gchar * function,GVariant * parameters,GError ** error)84 ck_call_function (const gchar *function, GVariant *parameters, GError **error)
85 {
86 if (!ck_proxy)
87 {
88 ck_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
89 G_DBUS_PROXY_FLAGS_NONE,
90 NULL,
91 "org.freedesktop.ConsoleKit",
92 "/org/freedesktop/ConsoleKit/Manager",
93 "org.freedesktop.ConsoleKit.Manager",
94 NULL,
95 error);
96 if (!ck_proxy)
97 return FALSE;
98 }
99
100 return g_dbus_proxy_call_sync (ck_proxy,
101 function,
102 parameters,
103 G_DBUS_CALL_FLAGS_NONE,
104 -1,
105 NULL,
106 error);
107 }
108
109 /**
110 * lightdm_get_can_suspend:
111 *
112 * Checks if authorized to do a system suspend.
113 *
114 * Return value: #TRUE if can suspend the system
115 **/
116 gboolean
lightdm_get_can_suspend(void)117 lightdm_get_can_suspend (void)
118 {
119 g_autoptr(GVariant) r = login1_call_function ("CanSuspend", NULL, NULL);
120 gboolean can_suspend = FALSE;
121 if (r)
122 {
123 const gchar *result;
124 if (g_variant_is_of_type (r, G_VARIANT_TYPE ("(s)")))
125 {
126 g_variant_get (r, "(&s)", &result);
127 can_suspend = g_strcmp0 (result, "yes") == 0;
128 }
129 }
130 if (!r)
131 {
132 const gchar *result;
133 r = ck_call_function ("CanSuspend", NULL, NULL);
134 if (r && g_variant_is_of_type (r, G_VARIANT_TYPE ("(s)")))
135 {
136 g_variant_get (r, "(&s)", &result);
137 can_suspend = g_strcmp0 (result, "yes") == 0;
138 }
139 }
140 if (!r)
141 {
142 r = upower_call_function ("SuspendAllowed", NULL);
143 if (r && g_variant_is_of_type (r, G_VARIANT_TYPE ("(b)")))
144 g_variant_get (r, "(b)", &can_suspend);
145 }
146
147 return can_suspend;
148 }
149
150 /**
151 * lightdm_suspend:
152 * @error: return location for a #GError, or %NULL
153 *
154 * Triggers a system suspend.
155 *
156 * Return value: #TRUE if suspend initiated.
157 **/
158 gboolean
lightdm_suspend(GError ** error)159 lightdm_suspend (GError **error)
160 {
161 g_autoptr(GError) login1_error = NULL;
162 g_autoptr(GVariant) login1_result = login1_call_function ("Suspend", g_variant_new("(b)", FALSE), &login1_error);
163 if (login1_result)
164 return TRUE;
165
166 g_debug ("Can't suspend using logind; falling back to ConsoleKit: %s", login1_error->message);
167
168 g_autoptr(GError) ck_error = NULL;
169 g_autoptr(GVariant) ck_result = ck_call_function ("Suspend", g_variant_new ("(b)", FALSE), &ck_error);
170 if (ck_result)
171 return TRUE;
172
173 g_debug ("Can't suspend using logind or ConsoleKit; falling back to UPower: %s", ck_error->message);
174
175 g_autoptr(GVariant) upower_result = upower_call_function ("Suspend", error);
176 return upower_result != NULL;
177 }
178
179 /**
180 * lightdm_get_can_hibernate:
181 *
182 * Checks if is authorized to do a system hibernate.
183 *
184 * Return value: #TRUE if can hibernate the system
185 **/
186 gboolean
lightdm_get_can_hibernate(void)187 lightdm_get_can_hibernate (void)
188 {
189 g_autoptr(GVariant) r = login1_call_function ("CanHibernate", NULL, NULL);
190 gboolean can_hibernate = FALSE;
191 if (r)
192 {
193 const gchar *result;
194 if (g_variant_is_of_type (r, G_VARIANT_TYPE ("(s)")))
195 {
196 g_variant_get (r, "(&s)", &result);
197 can_hibernate = g_strcmp0 (result, "yes") == 0;
198 }
199 }
200 if (!r)
201 {
202 const gchar *result;
203 r = ck_call_function ("CanHibernate", NULL, NULL);
204 if (r && g_variant_is_of_type (r, G_VARIANT_TYPE ("(s)")))
205 {
206 g_variant_get (r, "(&s)", &result);
207 can_hibernate = g_strcmp0 (result, "yes") == 0;
208 }
209 }
210 if (!r)
211 {
212 r = upower_call_function ("HibernateAllowed", NULL);
213 if (r && g_variant_is_of_type (r, G_VARIANT_TYPE ("(b)")))
214 g_variant_get (r, "(b)", &can_hibernate);
215 }
216
217 return can_hibernate;
218 }
219
220 /**
221 * lightdm_hibernate:
222 * @error: return location for a #GError, or %NULL
223 *
224 * Triggers a system hibernate.
225 *
226 * Return value: #TRUE if hibernate initiated.
227 **/
228 gboolean
lightdm_hibernate(GError ** error)229 lightdm_hibernate (GError **error)
230 {
231 g_autoptr(GError) login1_error = NULL;
232 g_autoptr(GVariant) login1_result = login1_call_function ("Hibernate", g_variant_new("(b)", FALSE), &login1_error);
233 if (login1_result)
234 return TRUE;
235
236 g_debug ("Can't hibernate using logind; falling back to ConsoleKit: %s", login1_error->message);
237
238 g_autoptr(GError) ck_error = NULL;
239 g_autoptr(GVariant) ck_result = ck_call_function ("Hibernate", g_variant_new ("(b)", FALSE), &ck_error);
240 if (ck_result)
241 return TRUE;
242
243 g_debug ("Can't hibernate using logind or ConsoleKit; falling back to UPower: %s", ck_error->message);
244
245 g_autoptr(GVariant) upower_result = upower_call_function ("Hibernate", error);
246 return upower_result != NULL;
247 }
248
249 /**
250 * lightdm_get_can_restart:
251 *
252 * Checks if is authorized to do a system restart.
253 *
254 * Return value: #TRUE if can restart the system
255 **/
256 gboolean
lightdm_get_can_restart(void)257 lightdm_get_can_restart (void)
258 {
259 g_autoptr(GVariant) r = login1_call_function ("CanReboot", NULL, NULL);
260 gboolean can_restart = FALSE;
261 if (r)
262 {
263 const gchar *result;
264 if (g_variant_is_of_type (r, G_VARIANT_TYPE ("(s)")))
265 {
266 g_variant_get (r, "(&s)", &result);
267 can_restart = g_strcmp0 (result, "yes") == 0;
268 }
269 }
270 else
271 {
272 r = ck_call_function ("CanRestart", NULL, NULL);
273 if (r && g_variant_is_of_type (r, G_VARIANT_TYPE ("(b)")))
274 g_variant_get (r, "(b)", &can_restart);
275 }
276
277 return can_restart;
278 }
279
280 /**
281 * lightdm_restart:
282 * @error: return location for a #GError, or %NULL
283 *
284 * Triggers a system restart.
285 *
286 * Return value: #TRUE if restart initiated.
287 **/
288 gboolean
lightdm_restart(GError ** error)289 lightdm_restart (GError **error)
290 {
291 g_autoptr(GError) login1_error = NULL;
292 g_autoptr(GVariant) login1_result = login1_call_function ("Reboot", g_variant_new("(b)", FALSE), &login1_error);
293 if (login1_result)
294 return TRUE;
295
296 g_autoptr(GVariant) ck_result = ck_call_function ("Restart", NULL, error);
297 return ck_result != NULL;
298 }
299
300 /**
301 * lightdm_get_can_shutdown:
302 *
303 * Checks if is authorized to do a system shutdown.
304 *
305 * Return value: #TRUE if can shutdown the system
306 **/
307 gboolean
lightdm_get_can_shutdown(void)308 lightdm_get_can_shutdown (void)
309 {
310 g_autoptr(GVariant) r = login1_call_function ("CanPowerOff", NULL, NULL);
311 gboolean can_shutdown = FALSE;
312 if (r)
313 {
314 const gchar *result;
315 if (g_variant_is_of_type (r, G_VARIANT_TYPE ("(s)")))
316 {
317 g_variant_get (r, "(&s)", &result);
318 can_shutdown = g_strcmp0 (result, "yes") == 0;
319 }
320 }
321 else
322 {
323 r = ck_call_function ("CanStop", NULL, NULL);
324 if (r && g_variant_is_of_type (r, G_VARIANT_TYPE ("(b)")))
325 g_variant_get (r, "(b)", &can_shutdown);
326 }
327
328 return can_shutdown;
329 }
330
331 /**
332 * lightdm_shutdown:
333 * @error: return location for a #GError, or %NULL
334 *
335 * Triggers a system shutdown.
336 *
337 * Return value: #TRUE if shutdown initiated.
338 **/
339 gboolean
lightdm_shutdown(GError ** error)340 lightdm_shutdown (GError **error)
341 {
342 g_autoptr(GError) login1_error = NULL;
343 g_autoptr(GVariant) login1_result = login1_call_function ("PowerOff", g_variant_new("(b)", FALSE), &login1_error);
344 if (login1_result)
345 return TRUE;
346
347 g_autoptr(GVariant) ck_result = ck_call_function ("Stop", NULL, error);
348 return ck_result != NULL;
349 }
350