1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3
* Copyright (C) 2004-2005 William Jon McCann <mccann@jhu.edu>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
* Authors: William Jon McCann <mccann@jhu.edu>
29
#include <glib/gi18n.h>
31
#define DBUS_API_SUBJECT_TO_CHANGE
32
#include <dbus/dbus.h>
33
#include <dbus/dbus-glib.h>
34
#include <dbus/dbus-glib-lowlevel.h>
36
#include "gs-listener-dbus.h"
38
/* this is for dbus < 0.3 */
39
#if ((DBUS_VERSION_MAJOR == 0) && (DBUS_VERSION_MINOR < 30))
40
#define dbus_bus_name_has_owner(connection, name, err) dbus_bus_service_exists(connection, name, err)
41
#define dbus_bus_request_name(connection, name, flags, err) dbus_bus_acquire_service(connection, name, flags, err)
44
static void gs_listener_class_init (GSListenerClass *klass);
45
static void gs_listener_init (GSListener *listener);
46
static void gs_listener_finalize (GObject *object);
48
static void gs_listener_unregister_handler (DBusConnection *connection,
51
static DBusHandlerResult gs_listener_message_handler (DBusConnection *connection,
55
#define GS_LISTENER_SERVICE "org.gnome.screensaver"
56
#define GS_LISTENER_PATH "/org/gnome/screensaver"
57
#define GS_LISTENER_INTERFACE "org.gnome.screensaver"
59
#define GS_LISTENER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_LISTENER, GSListenerPrivate))
61
struct GSListenerPrivate
63
DBusConnection *connection;
67
guint throttle_enabled : 1;
68
GHashTable *inhibitors;
79
THROTTLE_ENABLED_CHANGED,
87
PROP_THROTTLE_ENABLED,
91
static DBusObjectPathVTable
92
gs_listener_vtable = { &gs_listener_unregister_handler,
93
&gs_listener_message_handler,
99
static GObjectClass *parent_class = NULL;
100
static guint signals [LAST_SIGNAL] = { 0, };
102
G_DEFINE_TYPE (GSListener, gs_listener, G_TYPE_OBJECT);
105
gs_listener_error_quark (void)
107
static GQuark quark = 0;
109
quark = g_quark_from_static_string ("gs_listener_error");
115
gs_listener_unregister_handler (DBusConnection *connection,
121
gs_listener_send_signal_active_changed (GSListener *listener)
123
DBusMessage *message;
124
DBusMessageIter iter;
127
g_return_if_fail (listener != NULL);
129
message = dbus_message_new_signal (GS_LISTENER_PATH,
133
active = listener->priv->active;
134
dbus_message_iter_init_append (message, &iter);
135
dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &active);
137
if (! dbus_connection_send (listener->priv->connection, message, NULL)) {
138
g_warning ("Could not send ActiveChanged signal");
141
dbus_message_unref (message);
145
gs_listener_send_signal_throttle_enabled_changed (GSListener *listener)
147
DBusMessage *message;
148
DBusMessageIter iter;
151
g_return_if_fail (listener != NULL);
153
message = dbus_message_new_signal (GS_LISTENER_PATH,
155
"ThrottleEnabledChanged");
157
enabled = listener->priv->throttle_enabled;
158
dbus_message_iter_init_append (message, &iter);
159
dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &enabled);
161
if (! dbus_connection_send (listener->priv->connection, message, NULL)) {
162
g_warning ("Could not send ThrottleEnabledChanged signal");
165
dbus_message_unref (message);
168
#ifdef DEBUG_INHIBITORS
170
list_inhibitors (gpointer key,
174
g_message ("Inhibited by bus %s for reason: %s", (char *)key, (char *)value);
179
listener_check_activation (GSListener *listener)
181
guint n_inhibitors = 0;
183
/* if we aren't inhibited then activate */
184
if (listener->priv->inhibitors)
185
n_inhibitors = g_hash_table_size (listener->priv->inhibitors);
187
#ifdef DEBUG_INHIBITORS
188
g_hash_table_foreach (listener->priv->inhibitors, list_inhibitors, NULL);
191
if (listener->priv->idle
192
&& n_inhibitors == 0) {
193
gs_listener_set_active (listener, TRUE);
198
gs_listener_set_active (GSListener *listener,
201
g_return_if_fail (GS_IS_LISTENER (listener));
203
if (listener->priv->active != active) {
205
listener->priv->active = active;
207
g_signal_emit (listener, signals [ACTIVE_CHANGED], 0, active);
208
gs_listener_send_signal_active_changed (listener);
211
/* if we are deactivating then reset the throttle */
212
gs_listener_set_throttle_enabled (listener, FALSE);
213
/* if we are deactivating then reset the idle */
214
listener->priv->idle = active;
215
listener->priv->idle_start = 0;
221
gs_listener_set_idle (GSListener *listener,
224
g_return_val_if_fail (GS_IS_LISTENER (listener), FALSE);
226
if (listener->priv->idle == idle)
230
guint n_inhibitors = 0;
232
/* if we aren't inhibited then set idle */
233
if (listener->priv->inhibitors)
234
n_inhibitors = g_hash_table_size (listener->priv->inhibitors);
236
if (n_inhibitors != 0) {
240
listener->priv->idle_start = time (NULL);
242
listener->priv->idle_start = 0;
245
listener->priv->idle = idle;
247
listener_check_activation (listener);
253
gs_listener_set_throttle_enabled (GSListener *listener,
256
g_return_if_fail (GS_IS_LISTENER (listener));
258
if (listener->priv->throttle_enabled != enabled) {
260
listener->priv->throttle_enabled = enabled;
262
g_signal_emit (listener, signals [THROTTLE_ENABLED_CHANGED], 0, enabled);
263
gs_listener_send_signal_throttle_enabled_changed (listener);
268
listener_property_set_bool (GSListener *listener,
274
gs_listener_set_active (listener, value);
278
gs_listener_set_idle (listener, value);
281
case PROP_THROTTLE_ENABLED:
282
gs_listener_set_throttle_enabled (listener, value);
293
raise_error (DBusConnection *connection,
294
DBusMessage *in_reply_to,
295
const char *error_name,
302
va_start (args, format);
303
vsnprintf (buf, sizeof (buf), format, args);
307
reply = dbus_message_new_error (in_reply_to, error_name, buf);
309
g_error ("No memory");
310
if (! dbus_connection_send (connection, reply, NULL))
311
g_error ("No memory");
313
dbus_message_unref (reply);
317
raise_syntax (DBusConnection *connection,
318
DBusMessage *in_reply_to,
319
const char *method_name)
321
raise_error (connection, in_reply_to,
322
GS_LISTENER_SERVICE ".SyntaxError",
323
"There is a syntax error in the invocation of the method %s",
327
static DBusHandlerResult
328
listener_add_inhibitor (GSListener *listener,
329
DBusConnection *connection,
330
DBusMessage *message)
338
path = dbus_message_get_path (message);
340
dbus_error_init (&error);
341
if (! dbus_message_get_args (message, &error,
342
DBUS_TYPE_STRING, &reason,
343
DBUS_TYPE_INVALID)) {
344
raise_syntax (connection, message, "InhibitActivation");
346
return DBUS_HANDLER_RESULT_HANDLED;
349
reply = dbus_message_new_method_return (message);
351
g_error ("No memory");
353
sender = dbus_message_get_sender (message);
355
if (listener->priv->inhibitors == NULL) {
356
listener->priv->inhibitors =
357
g_hash_table_new_full (g_str_hash,
363
g_hash_table_insert (listener->priv->inhibitors, g_strdup (sender), g_strdup (reason));
365
if (! dbus_connection_send (connection, reply, NULL))
366
g_error ("No memory");
368
dbus_message_unref (reply);
370
return DBUS_HANDLER_RESULT_HANDLED;
373
static DBusHandlerResult
374
listener_remove_inhibitor (GSListener *listener,
375
DBusConnection *connection,
376
DBusMessage *message)
383
path = dbus_message_get_path (message);
385
dbus_error_init (&error);
386
if (! dbus_message_get_args (message, &error,
387
DBUS_TYPE_INVALID)) {
388
raise_syntax (connection, message, "AllowActivation");
390
return DBUS_HANDLER_RESULT_HANDLED;
393
reply = dbus_message_new_method_return (message);
395
g_error ("No memory");
397
sender = dbus_message_get_sender (message);
399
if (g_hash_table_lookup (listener->priv->inhibitors, sender)) {
400
g_hash_table_remove (listener->priv->inhibitors, sender);
401
listener_check_activation (listener);
403
g_warning ("Service '%s' was not in the list of inhibitors!", sender);
406
/* FIXME? Pointless? */
407
if (! dbus_connection_send (connection, reply, NULL))
408
g_error ("No memory");
410
dbus_message_unref (reply);
412
return DBUS_HANDLER_RESULT_HANDLED;
416
listener_service_deleted (GSListener *listener,
417
DBusMessage *message)
419
char *old_service_name;
420
char *new_service_name;
423
if (! dbus_message_get_args (message, NULL,
424
DBUS_TYPE_STRING, &old_service_name,
425
DBUS_TYPE_STRING, &new_service_name,
426
DBUS_TYPE_INVALID)) {
427
g_error ("Invalid NameOwnerChanged signal from bus!");
431
reason = g_hash_table_lookup (listener->priv->inhibitors, new_service_name);
433
if (reason != NULL) {
434
g_hash_table_remove (listener->priv->inhibitors, new_service_name);
435
listener_check_activation (listener);
440
raise_property_type_error (DBusConnection *connection,
441
DBusMessage *in_reply_to,
442
const char *device_id)
448
"Type mismatch setting property with id %s",
452
reply = dbus_message_new_error (in_reply_to,
453
"org.gnome.screensaver.TypeMismatch",
456
g_error ("No memory");
457
if (!dbus_connection_send (connection, reply, NULL))
458
g_error ("No memory");
460
dbus_message_unref (reply);
463
static DBusHandlerResult
464
listener_set_property (GSListener *listener,
465
DBusConnection *connection,
466
DBusMessage *message,
472
DBusMessageIter iter;
475
path = dbus_message_get_path (message);
477
dbus_message_iter_init (message, &iter);
478
type = dbus_message_iter_get_arg_type (&iter);
482
case DBUS_TYPE_BOOLEAN:
485
dbus_message_iter_get_basic (&iter, &v);
486
rc = listener_property_set_bool (listener, prop_id, v);
490
g_warning ("Unsupported property type %d", type);
495
raise_property_type_error (connection, message, path);
496
return DBUS_HANDLER_RESULT_HANDLED;
499
reply = dbus_message_new_method_return (message);
502
g_error ("No memory");
504
if (!dbus_connection_send (connection, reply, NULL))
505
g_error ("No memory");
507
dbus_message_unref (reply);
509
return DBUS_HANDLER_RESULT_HANDLED;
512
static DBusHandlerResult
513
listener_get_property (GSListener *listener,
514
DBusConnection *connection,
515
DBusMessage *message,
519
DBusMessageIter iter;
522
path = dbus_message_get_path (message);
524
reply = dbus_message_new_method_return (message);
526
dbus_message_iter_init_append (reply, &iter);
529
g_error ("No memory");
535
b = listener->priv->active;
536
dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &b);
542
b = listener->priv->idle;
543
dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &b);
546
case PROP_THROTTLE_ENABLED:
549
b = listener->priv->throttle_enabled;
550
dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &b);
554
g_warning ("Unsupported property id %d", prop_id);
558
if (!dbus_connection_send (connection, reply, NULL))
559
g_error ("No memory");
561
dbus_message_unref (reply);
563
return DBUS_HANDLER_RESULT_HANDLED;
566
static DBusHandlerResult
567
listener_get_idle_time (GSListener *listener,
568
DBusConnection *connection,
569
DBusMessage *message)
572
DBusMessageIter iter;
576
path = dbus_message_get_path (message);
578
reply = dbus_message_new_method_return (message);
580
dbus_message_iter_init_append (reply, &iter);
583
g_error ("No memory");
585
if (listener->priv->idle) {
586
time_t now = time (NULL);
588
if (now < listener->priv->idle_start) {
589
/* should't happen */
590
g_warning ("Idle start time is in the future");
593
secs = listener->priv->idle_start - now;
598
dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &secs);
600
if (! dbus_connection_send (connection, reply, NULL))
601
g_error ("No memory");
603
dbus_message_unref (reply);
605
return DBUS_HANDLER_RESULT_HANDLED;
608
static DBusHandlerResult
609
listener_dbus_filter_handle_methods (DBusConnection *connection,
610
DBusMessage *message,
612
dbus_bool_t local_interface)
614
GSListener *listener = GS_LISTENER (user_data);
616
g_return_val_if_fail (connection != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
617
g_return_val_if_fail (message != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
619
if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "lock")) {
620
g_signal_emit (listener, signals [LOCK], 0);
621
return DBUS_HANDLER_RESULT_HANDLED;
623
if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "quit")) {
624
g_signal_emit (listener, signals [QUIT], 0);
625
return DBUS_HANDLER_RESULT_HANDLED;
627
if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "cycle")) {
628
g_signal_emit (listener, signals [CYCLE], 0);
629
return DBUS_HANDLER_RESULT_HANDLED;
631
if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "InhibitActivation")) {
632
return listener_add_inhibitor (listener, connection, message);
634
if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "AllowActivation")) {
635
return listener_remove_inhibitor (listener, connection, message);
637
if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "setActive")) {
638
return listener_set_property (listener, connection, message, PROP_ACTIVE);
640
if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "getActive")) {
641
return listener_get_property (listener, connection, message, PROP_ACTIVE);
643
if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "getIdle")) {
644
return listener_get_property (listener, connection, message, PROP_IDLE);
646
if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "getIdleTime")) {
647
return listener_get_idle_time (listener, connection, message);
649
if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "setThrottleEnabled")) {
650
return listener_set_property (listener, connection, message, PROP_THROTTLE_ENABLED);
652
if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "getThrottleEnabled")) {
653
return listener_get_property (listener, connection, message, PROP_THROTTLE_ENABLED);
655
if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "poke")) {
656
g_signal_emit (listener, signals [POKE], 0);
657
return DBUS_HANDLER_RESULT_HANDLED;
659
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
662
static DBusHandlerResult
663
gs_listener_message_handler (DBusConnection *connection,
664
DBusMessage *message,
667
g_return_val_if_fail (connection != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
668
g_return_val_if_fail (message != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
671
g_message ("obj_path=%s interface=%s method=%s destination=%s",
672
dbus_message_get_path (message),
673
dbus_message_get_interface (message),
674
dbus_message_get_member (message),
675
dbus_message_get_destination (message));
678
if (dbus_message_is_method_call (message, "org.freedesktop.DBus", "AddMatch")) {
681
/* cheat, and handle AddMatch since libhal will try to invoke this method */
682
reply = dbus_message_new_method_return (message);
685
g_error ("No memory");
687
if (!dbus_connection_send (connection, reply, NULL))
688
g_error ("No memory");
690
dbus_message_unref (reply);
692
return DBUS_HANDLER_RESULT_HANDLED;
693
} else if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") &&
694
strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) {
696
dbus_connection_unref (connection);
698
return DBUS_HANDLER_RESULT_HANDLED;
700
else return listener_dbus_filter_handle_methods (connection, message, user_data, TRUE);
703
static DBusHandlerResult
704
listener_dbus_filter_function (DBusConnection *connection,
705
DBusMessage *message,
708
GSListener *listener = GS_LISTENER (user_data);
711
path = dbus_message_get_path (message);
714
g_message ("obj_path=%s interface=%s method=%s",
715
dbus_message_get_path (message),
716
dbus_message_get_interface (message),
717
dbus_message_get_member (message));
720
if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") &&
721
strcmp (path, DBUS_PATH_LOCAL) == 0) {
723
/* this is a local message; e.g. from libdbus in this process */
725
g_message ("Got disconnected from the system message bus; "
726
"retrying to reconnect every 3000 ms");
729
dbus_connection_unref (dbus_connection);
730
dbus_connection = NULL;
732
g_timeout_add (3000, reinit_dbus, NULL);
734
} else if (dbus_message_is_signal (message,
736
"NameOwnerChanged")) {
738
if (listener->priv->inhibitors != NULL)
739
listener_service_deleted (listener, message);
741
return listener_dbus_filter_handle_methods (connection, message, user_data, FALSE);
743
return DBUS_HANDLER_RESULT_HANDLED;
747
gs_listener_set_property (GObject *object,
754
self = GS_LISTENER (object);
758
gs_listener_set_active (self, g_value_get_boolean (value));
761
gs_listener_set_idle (self, g_value_get_boolean (value));
763
case PROP_THROTTLE_ENABLED:
764
gs_listener_set_throttle_enabled (self, g_value_get_boolean (value));
767
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
773
gs_listener_get_property (GObject *object,
780
self = GS_LISTENER (object);
784
g_value_set_boolean (value, self->priv->active);
787
g_value_set_boolean (value, self->priv->idle);
789
case PROP_THROTTLE_ENABLED:
790
g_value_set_boolean (value, self->priv->throttle_enabled);
793
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
799
gs_listener_class_init (GSListenerClass *klass)
801
GObjectClass *object_class = G_OBJECT_CLASS (klass);
803
parent_class = g_type_class_peek_parent (klass);
805
object_class->finalize = gs_listener_finalize;
806
object_class->get_property = gs_listener_get_property;
807
object_class->set_property = gs_listener_set_property;
810
g_signal_new ("lock",
811
G_TYPE_FROM_CLASS (object_class),
813
G_STRUCT_OFFSET (GSListenerClass, lock),
816
g_cclosure_marshal_VOID__VOID,
820
g_signal_new ("quit",
821
G_TYPE_FROM_CLASS (object_class),
823
G_STRUCT_OFFSET (GSListenerClass, quit),
826
g_cclosure_marshal_VOID__VOID,
830
g_signal_new ("cycle",
831
G_TYPE_FROM_CLASS (object_class),
833
G_STRUCT_OFFSET (GSListenerClass, cycle),
836
g_cclosure_marshal_VOID__VOID,
840
g_signal_new ("poke",
841
G_TYPE_FROM_CLASS (object_class),
843
G_STRUCT_OFFSET (GSListenerClass, poke),
846
g_cclosure_marshal_VOID__VOID,
849
signals [ACTIVE_CHANGED] =
850
g_signal_new ("active-changed",
851
G_TYPE_FROM_CLASS (object_class),
853
G_STRUCT_OFFSET (GSListenerClass, active_changed),
856
g_cclosure_marshal_VOID__BOOLEAN,
860
signals [THROTTLE_ENABLED_CHANGED] =
861
g_signal_new ("throttle-enabled-changed",
862
G_TYPE_FROM_CLASS (object_class),
864
G_STRUCT_OFFSET (GSListenerClass, throttle_enabled_changed),
867
g_cclosure_marshal_VOID__BOOLEAN,
872
g_object_class_install_property (object_class,
874
g_param_spec_boolean ("active",
879
g_object_class_install_property (object_class,
880
PROP_THROTTLE_ENABLED,
881
g_param_spec_boolean ("throttle-enabled",
887
g_type_class_add_private (klass, sizeof (GSListenerPrivate));
892
screensaver_is_running (DBusConnection *connection)
897
g_return_val_if_fail (connection != NULL, FALSE);
899
dbus_error_init (&error);
900
exists = dbus_bus_name_has_owner (connection, GS_LISTENER_SERVICE, &error);
901
if (dbus_error_is_set (&error))
902
dbus_error_free (&error);
908
gs_listener_acquire (GSListener *listener,
914
g_return_val_if_fail (listener != NULL, FALSE);
916
if (!listener->priv->connection) {
919
GS_LISTENER_ERROR_ACQUISITION_FAILURE,
921
_("failed to register with the message bus"));
925
if (screensaver_is_running (listener->priv->connection)) {
928
GS_LISTENER_ERROR_ACQUISITION_FAILURE,
930
_("screensaver already running in this session"));
934
dbus_error_init (&buserror);
936
if (dbus_connection_register_object_path (listener->priv->connection,
940
g_critical ("out of memory registering object path");
942
acquired = dbus_bus_request_name (listener->priv->connection,
945
if (dbus_error_is_set (&buserror))
948
GS_LISTENER_ERROR_ACQUISITION_FAILURE,
952
dbus_error_free (&buserror);
954
dbus_connection_add_filter (listener->priv->connection, listener_dbus_filter_function, listener, NULL);
956
dbus_bus_add_match (listener->priv->connection,
958
",interface='"DBUS_INTERFACE_DBUS"'"
959
",sender='"DBUS_SERVICE_DBUS"'"
960
",member='NameOwnerChanged'",
967
gs_listener_init (GSListener *listener)
971
listener->priv = GS_LISTENER_GET_PRIVATE (listener);
973
dbus_error_init (&error);
974
listener->priv->connection = dbus_bus_get (DBUS_BUS_SESSION, &error);
975
if (listener->priv->connection == NULL) {
976
g_critical ("couldn't connect to session bus: %s",
979
dbus_connection_setup_with_g_main (listener->priv->connection, NULL);
982
dbus_error_free (&error);
986
gs_listener_finalize (GObject *object)
988
GSListener *listener;
990
g_return_if_fail (object != NULL);
991
g_return_if_fail (GS_IS_LISTENER (object));
993
listener = GS_LISTENER (object);
995
g_return_if_fail (listener->priv != NULL);
997
/*dbus_connection_unref (listener->priv->connection);*/
999
if (listener->priv->inhibitors)
1000
g_hash_table_destroy (listener->priv->inhibitors);
1002
G_OBJECT_CLASS (parent_class)->finalize (object);
1006
gs_listener_new (void)
1008
GSListener *listener;
1010
listener = g_object_new (GS_TYPE_LISTENER, NULL);
1012
return GS_LISTENER (listener);