1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3
* Copyright (C) 2006-2009 Richard Hughes <richard@hughsie.com>
5
* Licensed under the GNU General Public License Version 2
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
#include <dbus/dbus-glib.h>
26
#include <dbus/dbus-glib-lowlevel.h>
27
#include <glib/gi18n.h>
29
#include <gconf/gconf-client.h>
31
#include "egg-debug.h"
32
#include "gpm-common.h"
33
#include "gpm-inhibit.h"
35
static void gpm_inhibit_finalize (GObject *object);
37
#define GPM_INHIBIT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPM_TYPE_INHIBIT, GpmInhibitPrivate))
38
#define GPM_SESSION_MANAGER_SERVICE "org.gnome.SessionManager"
39
#define GPM_SESSION_MANAGER_PATH "/org/gnome/SessionManager"
40
#define GPM_SESSION_MANAGER_INTERFACE "org.gnome.SessionManager"
50
struct GpmInhibitPrivate
54
DBusGProxy *proxy_session;
56
gboolean ignore_inhibits;
64
static guint signals [LAST_SIGNAL] = { 0 };
66
G_DEFINE_TYPE (GpmInhibit, gpm_inhibit, G_TYPE_OBJECT)
69
* gpm_inhibit_error_quark:
70
* Return value: Our personal error quark.
73
gpm_inhibit_error_quark (void)
75
static GQuark quark = 0;
77
quark = g_quark_from_static_string ("gpm_inhibit_error");
82
* gpm_inhibit_cookie_compare_func
83
* @a: Pointer to the data to test
84
* @b: Pointer to a cookie to compare
86
* A GCompareFunc for comparing a cookie to a list.
88
* Return value: 0 if cookie matches
91
gpm_inhibit_cookie_compare_func (gconstpointer a, gconstpointer b)
95
data = (GpmInhibitData*) a;
96
cookie = *((guint32*) b);
97
if (cookie == data->cookie)
103
* gpm_inhibit_find_cookie:
104
* @inhibit: This inhibit instance
105
* @cookie: The cookie we are looking for
107
* Finds the data in the cookie list.
109
* Return value: The cookie data, or NULL if not found
111
static GpmInhibitData *
112
gpm_inhibit_find_cookie (GpmInhibit *inhibit, guint32 cookie)
114
GpmInhibitData *data;
117
ret = g_slist_find_custom (inhibit->priv->list, &cookie,
118
gpm_inhibit_cookie_compare_func);
121
data = (GpmInhibitData *) ret->data;
126
* gpm_inhibit_inhibit:
127
* @application: Application name, e.g. "Nautilus"
128
* @reason: Reason for inhibiting, e.g. "Copying files"
130
* Allocates a random cookie used to identify the connection, as multiple
131
* inhibit requests can come from one caller sharing a dbus connection.
132
* We need to refcount internally, and data is saved in the GpmInhibitData
135
* Return value: a new random cookie.
138
gpm_inhibit_inhibit (GpmInhibit *inhibit, const gchar *application, const gchar *reason, DBusGMethodInvocation *context)
141
GError *error = NULL;
142
const gchar *connection;
143
GpmInhibitData *data;
144
guint inhibit_cookie = 0;
146
/* as we are async, we can get the sender */
147
connection = dbus_g_method_get_sender (context);
149
/* handle where the application does not add required data */
150
if (application == NULL || reason == NULL) {
151
egg_warning ("Recieved Inhibit, but application "
152
"did not set the parameters correctly");
153
dbus_g_method_return (context, -1);
157
/* if there's no gnome-session, this will be NULL */
158
if (inhibit->priv->proxy_session == NULL)
161
/* proxy to gnome-session */
162
ret = dbus_g_proxy_call (inhibit->priv->proxy_session, "Inhibit", &error,
163
G_TYPE_STRING, application, /* app_id */
164
G_TYPE_UINT, 0, /* toplevel_xid */
165
G_TYPE_STRING, reason, /* reason*/
166
G_TYPE_UINT, 8, /* flags */
168
G_TYPE_UINT, &inhibit_cookie,
171
egg_warning ("failed to proxy: %s", error->message);
172
dbus_g_method_return_error (context, error);
177
/* seems okay, add to list */
178
data = g_new (GpmInhibitData, 1);
179
data->cookie = inhibit_cookie;
180
data->application = g_strdup (application);
181
data->connection = g_strdup (connection);
182
data->reason = g_strdup (reason);
184
inhibit->priv->list = g_slist_append (inhibit->priv->list, (gpointer) data);
186
egg_debug ("Recieved Inhibit from '%s' (%s) because '%s' saving as #%i",
187
data->application, data->connection, data->reason, data->cookie);
189
/* only emit event on the first one */
190
if (g_slist_length (inhibit->priv->list) == 1)
191
g_signal_emit (inhibit, signals [HAS_INHIBIT_CHANGED], 0, TRUE);
193
dbus_g_method_return (context, data->cookie);
196
/* free one element in GpmInhibitData struct */
198
gpm_inhibit_free_data_object (GpmInhibitData *data)
200
g_free (data->application);
201
g_free (data->reason);
202
g_free (data->connection);
207
* gpm_inhibit_un_inhibit:
208
* @application: Application name
209
* @cookie: The cookie that we used to register
211
* Removes a cookie and associated data from the GpmInhibitData struct.
214
gpm_inhibit_un_inhibit (GpmInhibit *inhibit, guint32 cookie, GError **error)
217
GpmInhibitData *data;
219
/* Only remove the correct cookie */
220
data = gpm_inhibit_find_cookie (inhibit, cookie);
222
*error = g_error_new (gpm_inhibit_error_quark (),
223
GPM_INHIBIT_ERROR_GENERAL,
224
"Cannot find registered program for #%i, so "
225
"cannot do UnInhibit!", cookie);
228
egg_debug ("UnInhibit okay #%i", cookie);
230
/* if there's no gnome-session, this will be NULL */
231
if (inhibit->priv->proxy_session == NULL)
234
/* proxy to gnome-session */
235
ret = dbus_g_proxy_call (inhibit->priv->proxy_session, "Uninhibit", error,
240
egg_warning ("failed to proxy: %s", (*error)->message);
245
gpm_inhibit_free_data_object (data);
247
/* remove it from the list */
248
inhibit->priv->list = g_slist_remove (inhibit->priv->list, (gconstpointer) data);
250
/* only emit event on the last one */
251
if (g_slist_length (inhibit->priv->list) == 0)
252
g_signal_emit (inhibit, signals [HAS_INHIBIT_CHANGED], 0, FALSE);
258
* gpm_inhibit_remove_dbus:
259
* @connection: Connection name
260
* @application: Application name
261
* @cookie: The cookie that we used to register
263
* Checks to see if the dbus closed session is registered, in which case
267
gpm_inhibit_remove_dbus (GpmInhibit *inhibit, const gchar *connection)
270
GpmInhibitData *data;
272
GError *error = NULL;
274
/* Remove *any* connections that match the connection */
275
for (a=0; a<g_slist_length (inhibit->priv->list); a++) {
276
data = (GpmInhibitData *) g_slist_nth_data (inhibit->priv->list, a);
277
if (strcmp (data->connection, connection) == 0) {
278
egg_debug ("Auto-revoked idle inhibit on '%s'.", data->application);
280
/* if there's no gnome-session, this will be NULL */
281
if (inhibit->priv->proxy_session == NULL)
284
/* proxy to gnome-session */
285
ret = dbus_g_proxy_call (inhibit->priv->proxy_session, "Uninhibit", &error,
286
G_TYPE_UINT, data->cookie,
290
egg_warning ("failed to proxy: %s", error->message);
291
g_error_free (error);
294
gpm_inhibit_free_data_object (data);
295
/* remove it from the list */
296
inhibit->priv->list = g_slist_remove (inhibit->priv->list, (gconstpointer) data);
302
* gpm_inhibit_name_owner_changed_cb:
305
gpm_inhibit_name_owner_changed_cb (DBusGProxy *proxy, const gchar *name,
306
const gchar *prev, const gchar *new,
309
if (strlen (new) == 0)
310
gpm_inhibit_remove_dbus (inhibit, name);
314
* gpm_inhibit_has_inhibit
316
* Checks to see if we are being stopped from performing an action.
318
* TRUE if the action is OK, i.e. we have *not* been inhibited.
321
gpm_inhibit_has_inhibit (GpmInhibit *inhibit, gboolean *has_inihibit, GError **error)
325
length = g_slist_length (inhibit->priv->list);
327
if (inhibit->priv->ignore_inhibits) {
328
egg_debug ("Inhibit ignored through gconf policy!");
329
*has_inihibit = FALSE;
332
/* An inhibit can stop the action */
334
egg_debug ("Valid as no inhibitors");
335
*has_inihibit = FALSE;
337
/* we have at least one application blocking the action */
338
egg_debug ("We have %i valid inhibitors", length);
339
*has_inihibit = TRUE;
342
/* we always return successful for DBUS */
347
* gpm_inhibit_get_message:
349
* @message: Description string, e.g. "Nautilus because 'copying files'"
350
* @action: Action we wanted to do, e.g. "suspend"
352
* Returns a localised message text describing what application has inhibited
353
* the action, and why.
357
gpm_inhibit_get_message (GpmInhibit *inhibit, GString *message, const gchar *action)
360
GpmInhibitData *data;
364
if (g_slist_length (inhibit->priv->list) == 1) {
365
data = (GpmInhibitData *) g_slist_nth_data (inhibit->priv->list, 0);
366
boldstr = g_strdup_printf ("<b>%s</b>", data->application);
367
italicstr = g_strdup_printf ("<b>%s</b>", data->reason);
369
if (strcmp (action, "suspend") == 0) {
370
/*Translators: first %s is an application name, second %s is the reason*/
371
g_string_append_printf (message, _("%s has stopped the suspend from taking place: %s."),
374
} else if (strcmp (action, "hibernate") == 0) {
375
/*Translators: first %s is an application name, second %s is the reason*/
376
g_string_append_printf (message, _("%s has stopped the hibernate from taking place: %s."),
379
} else if (strcmp (action, "policy action") == 0) {
380
/*Translators: first %s is an application name, second %s is the reason*/
381
g_string_append_printf (message, _("%s has stopped the policy action from taking place: %s."),
384
} else if (strcmp (action, "reboot") == 0) {
385
/*Translators: first %s is an application name, second %s is the reason*/
386
g_string_append_printf (message, _("%s has stopped the reboot from taking place: %s."),
389
} else if (strcmp (action, "shutdown") == 0) {
390
/*Translators: first %s is an application name, second %s is the reason*/
391
g_string_append_printf (message, _("%s has stopped the shutdown from taking place: %s."),
394
} else if (strcmp (action, "timeout action") == 0) {
395
/*Translators: first %s is an application name, second %s is the reason*/
396
g_string_append_printf (message, _("%s has stopped the timeout action from taking place: %s."),
404
if (strcmp (action, "suspend") == 0) {
405
g_string_append (message, _("Multiple applications have stopped the suspend from taking place."));
407
} else if (strcmp (action, "hibernate") == 0) {
408
g_string_append (message, _("Multiple applications have stopped the hibernate from taking place."));
410
} else if (strcmp (action, "policy action") == 0) {
411
g_string_append (message, _("Multiple applications have stopped the policy action from taking place."));
413
} else if (strcmp (action, "reboot") == 0) {
414
g_string_append (message, _("Multiple applications have stopped the reboot from taking place."));
416
} else if (strcmp (action, "shutdown") == 0) {
417
g_string_append (message, _("Multiple applications have stopped the shutdown from taking place."));
419
} else if (strcmp (action, "timeout action") == 0) {
420
g_string_append (message, _("Multiple applications have stopped the suspend from taking place."));
423
for (a=0; a<g_slist_length (inhibit->priv->list); a++) {
424
data = (GpmInhibitData *) g_slist_nth_data (inhibit->priv->list, a);
425
g_string_append_printf (message,
426
"\n<b>%s</b> : <i>%s</i>",
427
data->application, data->reason);
432
/** intialise the class */
434
gpm_inhibit_class_init (GpmInhibitClass *klass)
436
GObjectClass *object_class = G_OBJECT_CLASS (klass);
437
object_class->finalize = gpm_inhibit_finalize;
439
signals [HAS_INHIBIT_CHANGED] =
440
g_signal_new ("has-inhibit-changed",
441
G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
442
G_STRUCT_OFFSET (GpmInhibitClass, has_inhibit_changed),
443
NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN,
444
G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
445
g_type_class_add_private (klass, sizeof (GpmInhibitPrivate));
448
/** intialise the object */
450
gpm_inhibit_init (GpmInhibit *inhibit)
452
DBusGConnection *connection;
453
GError *error = NULL;
455
inhibit->priv = GPM_INHIBIT_GET_PRIVATE (inhibit);
456
inhibit->priv->list = NULL;
457
inhibit->priv->conf = gconf_client_get_default ();
459
connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
461
egg_warning ("Cannot connect to bus: %s", error->message);
462
g_error_free (error);
464
inhibit->priv->proxy = dbus_g_proxy_new_for_name_owner (connection,
465
DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
466
DBUS_INTERFACE_DBUS, &error);
467
if (inhibit->priv->proxy == NULL) {
468
egg_warning ("failed to get proxy: %s", error->message);
469
g_error_free (error);
472
dbus_g_proxy_add_signal (inhibit->priv->proxy, "NameOwnerChanged",
473
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
474
dbus_g_proxy_connect_signal (inhibit->priv->proxy, "NameOwnerChanged",
475
G_CALLBACK (gpm_inhibit_name_owner_changed_cb),
478
inhibit->priv->proxy_session = dbus_g_proxy_new_for_name_owner (connection,
479
GPM_SESSION_MANAGER_SERVICE, GPM_SESSION_MANAGER_PATH,
480
GPM_SESSION_MANAGER_INTERFACE, &error);
481
if (inhibit->priv->proxy_session == NULL) {
482
egg_warning ("failed to get proxy: %s", error->message);
483
g_error_free (error);
486
/* Do we ignore inhibit requests? */
487
inhibit->priv->ignore_inhibits = gconf_client_get_bool (inhibit->priv->conf, GPM_CONF_IGNORE_INHIBITS, NULL);
490
/** finalise the object */
492
gpm_inhibit_finalize (GObject *object)
496
GpmInhibitData *data;
498
g_return_if_fail (object != NULL);
499
g_return_if_fail (GPM_IS_INHIBIT (object));
501
inhibit = GPM_INHIBIT (object);
502
inhibit->priv = GPM_INHIBIT_GET_PRIVATE (inhibit);
504
for (a=0; a<g_slist_length (inhibit->priv->list); a++) {
505
data = (GpmInhibitData *) g_slist_nth_data (inhibit->priv->list, a);
506
gpm_inhibit_free_data_object (data);
508
g_slist_free (inhibit->priv->list);
510
g_object_unref (inhibit->priv->conf);
511
g_object_unref (inhibit->priv->proxy);
512
if (inhibit->priv->proxy_session != NULL)
513
g_object_unref (inhibit->priv->proxy_session);
514
G_OBJECT_CLASS (gpm_inhibit_parent_class)->finalize (object);
517
/** create the object */
519
gpm_inhibit_new (void)
522
inhibit = g_object_new (GPM_TYPE_INHIBIT, NULL);
523
return GPM_INHIBIT (inhibit);
526
/***************************************************************************
527
*** MAKE CHECK TESTS ***
528
***************************************************************************/
530
#include "egg-test.h"
531
#include "egg-dbus-proxy.h"
532
#include "gpm-common.h"
534
/** cookie is returned as an unsigned integer */
536
inhibit (EggDbusProxy *gproxy,
537
const gchar *appname,
541
GError *error = NULL;
545
g_return_val_if_fail (cookie != NULL, FALSE);
547
proxy = egg_dbus_proxy_get_proxy (gproxy);
549
g_warning ("not connected");
553
ret = dbus_g_proxy_call (proxy, "Inhibit", &error,
554
G_TYPE_STRING, appname,
555
G_TYPE_STRING, reason,
560
g_debug ("ERROR: %s", error->message);
561
g_error_free (error);
565
/* abort as the DBUS method failed */
566
g_warning ("Inhibit failed!");
573
uninhibit (EggDbusProxy *gproxy,
576
GError *error = NULL;
580
proxy = egg_dbus_proxy_get_proxy (gproxy);
582
g_warning ("not connected");
586
ret = dbus_g_proxy_call (proxy, "UnInhibit", &error,
591
egg_debug ("ERROR: %s", error->message);
592
g_error_free (error);
598
gpm_inhibit_test_has_inhibit (EggDbusProxy *gproxy, gboolean *has_inhibit)
600
GError *error = NULL;
604
proxy = egg_dbus_proxy_get_proxy (gproxy);
606
g_warning ("not connected");
610
ret = dbus_g_proxy_call (proxy, "HasInhibit", &error,
612
G_TYPE_BOOLEAN, has_inhibit,
615
g_debug ("ERROR: %s", error->message);
616
g_error_free (error);
619
/* abort as the DBUS method failed */
620
g_warning ("HasInhibit failed!");
627
gpm_inhibit_test (gpointer data)
633
DBusGConnection *connection;
634
EggDbusProxy *gproxy;
635
EggTest *test = (EggTest *) data;
637
if (egg_test_start (test, "GpmInhibit") == FALSE) {
641
gproxy = egg_dbus_proxy_new ();
642
connection = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
643
egg_dbus_proxy_assign (gproxy, connection, GPM_DBUS_SERVICE,
644
GPM_DBUS_PATH_INHIBIT, GPM_DBUS_INTERFACE_INHIBIT);
646
if (gproxy == NULL) {
647
g_warning ("Unable to get connection to power manager");
651
/************************************************************/
652
egg_test_title (test, "make sure we are not inhibited");
653
ret = gpm_inhibit_test_has_inhibit (gproxy, &valid);
655
egg_test_failed (test, "Unable to test validity");
657
egg_test_failed (test, "Already inhibited");
659
egg_test_success (test, NULL);
662
/************************************************************/
663
egg_test_title (test, "clear an invalid cookie");
664
ret = uninhibit (gproxy, 123456);
666
egg_test_success (test, "invalid cookie failed as expected");
668
egg_test_failed (test, "should have rejected invalid cookie");
671
/************************************************************/
672
egg_test_title (test, "get auto cookie 1");
673
ret = inhibit (gproxy,
674
"gnome-power-self-test",
678
egg_test_failed (test, "Unable to inhibit");
679
} else if (cookie1 == 0) {
680
egg_test_failed (test, "Cookie invalid (cookie: %u)", cookie1);
682
egg_test_success (test, "cookie: %u", cookie1);
685
/************************************************************/
686
egg_test_title (test, "make sure we are auto inhibited");
687
ret = gpm_inhibit_test_has_inhibit (gproxy, &valid);
689
egg_test_failed (test, "Unable to test validity");
691
egg_test_success (test, "inhibited");
693
egg_test_failed (test, "inhibit failed");
696
/************************************************************/
697
egg_test_title (test, "get cookie 2");
698
ret = inhibit (gproxy,
699
"gnome-power-self-test",
703
egg_test_failed (test, "Unable to inhibit");
704
} else if (cookie2 == 0) {
705
egg_test_failed (test, "Cookie invalid (cookie: %u)", cookie2);
707
egg_test_success (test, "cookie: %u", cookie2);
710
/************************************************************/
711
egg_test_title (test, "clear cookie 1");
712
ret = uninhibit (gproxy, cookie1);
714
egg_test_failed (test, "cookie failed to clear");
716
egg_test_success (test, NULL);
719
/************************************************************/
720
egg_test_title (test, "make sure we are still inhibited");
721
ret = gpm_inhibit_test_has_inhibit (gproxy, &valid);
723
egg_test_failed (test, "Unable to test validity");
725
egg_test_success (test, "inhibited");
727
egg_test_failed (test, "inhibit failed");
730
/************************************************************/
731
egg_test_title (test, "clear cookie 2");
732
ret = uninhibit (gproxy, cookie2);
734
egg_test_failed (test, "cookie failed to clear");
736
egg_test_success (test, NULL);
739
g_object_unref (gproxy);