~ubuntu-branches/ubuntu/dapper/gnome-screensaver/dapper

« back to all changes in this revision

Viewing changes to src/gs-listener-dbus.c

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Grawert
  • Date: 2005-10-10 00:18:18 UTC
  • Revision ID: james.westby@ubuntu.com-20051010001818-3mujs05r8rht7xi1
Tags: upstream-0.0.15
ImportĀ upstreamĀ versionĀ 0.0.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
 
2
 *
 
3
 * Copyright (C) 2004-2005 William Jon McCann <mccann@jhu.edu>
 
4
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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.
 
18
 *
 
19
 * Authors: William Jon McCann <mccann@jhu.edu>
 
20
 *
 
21
 */
 
22
 
 
23
#include "config.h"
 
24
#include <stdlib.h>
 
25
#include <stdio.h>
 
26
#include <time.h>
 
27
#include <string.h>
 
28
 
 
29
#include <glib/gi18n.h>
 
30
 
 
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>
 
35
 
 
36
#include "gs-listener-dbus.h"
 
37
 
 
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)
 
42
#endif
 
43
 
 
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);
 
47
 
 
48
static void              gs_listener_unregister_handler (DBusConnection  *connection,
 
49
                                                         void            *data);
 
50
 
 
51
static DBusHandlerResult gs_listener_message_handler    (DBusConnection  *connection,
 
52
                                                         DBusMessage     *message,
 
53
                                                         void            *user_data);
 
54
 
 
55
#define GS_LISTENER_SERVICE   "org.gnome.screensaver"
 
56
#define GS_LISTENER_PATH      "/org/gnome/screensaver"
 
57
#define GS_LISTENER_INTERFACE "org.gnome.screensaver"
 
58
 
 
59
#define GS_LISTENER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_LISTENER, GSListenerPrivate))
 
60
 
 
61
struct GSListenerPrivate
 
62
{
 
63
        DBusConnection *connection;
 
64
 
 
65
        guint           idle : 1;
 
66
        guint           active : 1;
 
67
        guint           throttle_enabled : 1;
 
68
        GHashTable     *inhibitors;
 
69
 
 
70
        time_t          idle_start;
 
71
};
 
72
 
 
73
enum {
 
74
        LOCK,
 
75
        CYCLE,
 
76
        QUIT,
 
77
        POKE,
 
78
        ACTIVE_CHANGED,
 
79
        THROTTLE_ENABLED_CHANGED,
 
80
        LAST_SIGNAL
 
81
};
 
82
 
 
83
enum {
 
84
        PROP_0,
 
85
        PROP_ACTIVE,
 
86
        PROP_IDLE,
 
87
        PROP_THROTTLE_ENABLED,
 
88
};
 
89
 
 
90
 
 
91
static DBusObjectPathVTable
 
92
gs_listener_vtable = { &gs_listener_unregister_handler,
 
93
                       &gs_listener_message_handler,
 
94
                       NULL,
 
95
                       NULL,
 
96
                       NULL,
 
97
                       NULL };
 
98
 
 
99
static GObjectClass *parent_class = NULL;
 
100
static guint         signals [LAST_SIGNAL] = { 0, };
 
101
 
 
102
G_DEFINE_TYPE (GSListener, gs_listener, G_TYPE_OBJECT);
 
103
 
 
104
GQuark
 
105
gs_listener_error_quark (void)
 
106
{
 
107
        static GQuark quark = 0;
 
108
        if (!quark)
 
109
                quark = g_quark_from_static_string ("gs_listener_error");
 
110
 
 
111
        return quark;
 
112
}
 
113
 
 
114
static void
 
115
gs_listener_unregister_handler (DBusConnection *connection,
 
116
                                void           *data)
 
117
{
 
118
}
 
119
 
 
120
static void
 
121
gs_listener_send_signal_active_changed (GSListener *listener)
 
122
{
 
123
        DBusMessage    *message;
 
124
        DBusMessageIter iter;
 
125
        dbus_bool_t     active;
 
126
 
 
127
        g_return_if_fail (listener != NULL);
 
128
 
 
129
        message = dbus_message_new_signal (GS_LISTENER_PATH,
 
130
                                           GS_LISTENER_SERVICE,
 
131
                                           "ActiveChanged");
 
132
 
 
133
        active = listener->priv->active;
 
134
        dbus_message_iter_init_append (message, &iter);
 
135
        dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &active);
 
136
 
 
137
        if (! dbus_connection_send (listener->priv->connection, message, NULL)) {
 
138
                g_warning ("Could not send ActiveChanged signal");
 
139
        }
 
140
 
 
141
        dbus_message_unref (message);
 
142
}
 
143
 
 
144
static void
 
145
gs_listener_send_signal_throttle_enabled_changed (GSListener *listener)
 
146
{
 
147
        DBusMessage    *message;
 
148
        DBusMessageIter iter;
 
149
        dbus_bool_t     enabled;
 
150
 
 
151
        g_return_if_fail (listener != NULL);
 
152
 
 
153
        message = dbus_message_new_signal (GS_LISTENER_PATH,
 
154
                                           GS_LISTENER_SERVICE,
 
155
                                           "ThrottleEnabledChanged");
 
156
 
 
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);
 
160
 
 
161
        if (! dbus_connection_send (listener->priv->connection, message, NULL)) {
 
162
                g_warning ("Could not send ThrottleEnabledChanged signal");
 
163
        }
 
164
 
 
165
        dbus_message_unref (message);
 
166
}
 
167
 
 
168
#ifdef DEBUG_INHIBITORS
 
169
static void
 
170
list_inhibitors (gpointer key,
 
171
                 gpointer value,
 
172
                 gpointer user_data)
 
173
{
 
174
        g_message ("Inhibited by bus %s for reason: %s", (char *)key, (char *)value);
 
175
}
 
176
#endif
 
177
 
 
178
static void
 
179
listener_check_activation (GSListener *listener)
 
180
{
 
181
        guint n_inhibitors = 0;
 
182
 
 
183
        /* if we aren't inhibited then activate */
 
184
        if (listener->priv->inhibitors)
 
185
                n_inhibitors = g_hash_table_size (listener->priv->inhibitors);
 
186
 
 
187
#ifdef DEBUG_INHIBITORS
 
188
        g_hash_table_foreach (listener->priv->inhibitors, list_inhibitors, NULL);
 
189
#endif
 
190
 
 
191
        if (listener->priv->idle
 
192
            && n_inhibitors == 0) {
 
193
                gs_listener_set_active (listener, TRUE);
 
194
        }
 
195
}
 
196
 
 
197
void
 
198
gs_listener_set_active (GSListener *listener,
 
199
                        gboolean    active)
 
200
{
 
201
        g_return_if_fail (GS_IS_LISTENER (listener));
 
202
 
 
203
        if (listener->priv->active != active) {
 
204
 
 
205
                listener->priv->active = active;
 
206
 
 
207
                g_signal_emit (listener, signals [ACTIVE_CHANGED], 0, active);
 
208
                gs_listener_send_signal_active_changed (listener);
 
209
 
 
210
                if (! active) {
 
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;
 
216
                }
 
217
        }
 
218
}
 
219
 
 
220
gboolean
 
221
gs_listener_set_idle (GSListener *listener,
 
222
                      gboolean    idle)
 
223
{
 
224
        g_return_val_if_fail (GS_IS_LISTENER (listener), FALSE);
 
225
 
 
226
        if (listener->priv->idle == idle)
 
227
                return FALSE;
 
228
 
 
229
        if (idle) {
 
230
                guint n_inhibitors = 0;
 
231
 
 
232
                /* if we aren't inhibited then set idle */
 
233
                if (listener->priv->inhibitors)
 
234
                        n_inhibitors = g_hash_table_size (listener->priv->inhibitors);
 
235
 
 
236
                if (n_inhibitors != 0) {
 
237
                        return FALSE;
 
238
                }
 
239
 
 
240
                listener->priv->idle_start = time (NULL);
 
241
        } else {
 
242
                listener->priv->idle_start = 0;
 
243
        }
 
244
 
 
245
        listener->priv->idle = idle;
 
246
 
 
247
        listener_check_activation (listener);
 
248
 
 
249
        return TRUE;
 
250
}
 
251
 
 
252
void
 
253
gs_listener_set_throttle_enabled (GSListener *listener,
 
254
                                  gboolean    enabled)
 
255
{
 
256
        g_return_if_fail (GS_IS_LISTENER (listener));
 
257
 
 
258
        if (listener->priv->throttle_enabled != enabled) {
 
259
 
 
260
                listener->priv->throttle_enabled = enabled;
 
261
 
 
262
                g_signal_emit (listener, signals [THROTTLE_ENABLED_CHANGED], 0, enabled);
 
263
                gs_listener_send_signal_throttle_enabled_changed (listener);
 
264
        }
 
265
}
 
266
 
 
267
static dbus_bool_t
 
268
listener_property_set_bool (GSListener *listener,
 
269
                            guint       prop_id,
 
270
                            dbus_bool_t value)
 
271
{
 
272
        switch (prop_id) {
 
273
        case PROP_ACTIVE:
 
274
                gs_listener_set_active (listener, value);
 
275
                return TRUE;
 
276
                break;
 
277
        case PROP_IDLE:
 
278
                gs_listener_set_idle (listener, value);
 
279
                return TRUE;
 
280
                break;
 
281
        case PROP_THROTTLE_ENABLED:
 
282
                gs_listener_set_throttle_enabled (listener, value);
 
283
                return TRUE;
 
284
                break;
 
285
        default:
 
286
                break;
 
287
        }
 
288
 
 
289
        return FALSE;
 
290
}
 
291
 
 
292
static void
 
293
raise_error (DBusConnection *connection,
 
294
             DBusMessage    *in_reply_to,
 
295
             const char     *error_name,
 
296
             char           *format, ...)
 
297
{
 
298
        char         buf[512];
 
299
        DBusMessage *reply;
 
300
 
 
301
        va_list args;
 
302
        va_start (args, format);
 
303
        vsnprintf (buf, sizeof (buf), format, args);
 
304
        va_end (args);
 
305
 
 
306
        g_warning (buf);
 
307
        reply = dbus_message_new_error (in_reply_to, error_name, buf);
 
308
        if (reply == NULL)
 
309
                g_error ("No memory");
 
310
        if (! dbus_connection_send (connection, reply, NULL))
 
311
                g_error ("No memory");
 
312
 
 
313
        dbus_message_unref (reply);
 
314
}
 
315
 
 
316
static void
 
317
raise_syntax (DBusConnection *connection,
 
318
              DBusMessage    *in_reply_to,
 
319
              const char     *method_name)
 
320
{
 
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",
 
324
                     method_name);
 
325
}
 
326
 
 
327
static DBusHandlerResult
 
328
listener_add_inhibitor (GSListener     *listener,
 
329
                        DBusConnection *connection,
 
330
                        DBusMessage    *message)
 
331
{
 
332
        const char     *path;
 
333
        const char     *sender;
 
334
        DBusMessage    *reply;
 
335
        DBusError       error;
 
336
        char           *reason;
 
337
 
 
338
        path = dbus_message_get_path (message);
 
339
 
 
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");
 
345
 
 
346
                return DBUS_HANDLER_RESULT_HANDLED;
 
347
        }
 
348
 
 
349
        reply = dbus_message_new_method_return (message);
 
350
        if (reply == NULL)
 
351
                g_error ("No memory");
 
352
 
 
353
        sender = dbus_message_get_sender (message);
 
354
 
 
355
        if (listener->priv->inhibitors == NULL) {
 
356
                listener->priv->inhibitors =
 
357
                        g_hash_table_new_full (g_str_hash,
 
358
                                               g_str_equal,
 
359
                                               g_free,
 
360
                                               g_free);
 
361
        }
 
362
 
 
363
        g_hash_table_insert (listener->priv->inhibitors, g_strdup (sender), g_strdup (reason));
 
364
 
 
365
        if (! dbus_connection_send (connection, reply, NULL))
 
366
                g_error ("No memory");
 
367
 
 
368
        dbus_message_unref (reply);
 
369
 
 
370
        return DBUS_HANDLER_RESULT_HANDLED;
 
371
}
 
372
 
 
373
static DBusHandlerResult
 
374
listener_remove_inhibitor (GSListener     *listener,
 
375
                           DBusConnection *connection,
 
376
                           DBusMessage    *message)
 
377
{
 
378
        const char  *path;
 
379
        DBusMessage *reply;
 
380
        DBusError    error;
 
381
        const char  *sender;
 
382
 
 
383
        path = dbus_message_get_path (message);
 
384
 
 
385
        dbus_error_init (&error);
 
386
        if (! dbus_message_get_args (message, &error,
 
387
                                     DBUS_TYPE_INVALID)) {
 
388
                raise_syntax (connection, message, "AllowActivation");
 
389
 
 
390
                return DBUS_HANDLER_RESULT_HANDLED;
 
391
        }
 
392
 
 
393
        reply = dbus_message_new_method_return (message);
 
394
        if (reply == NULL)
 
395
                g_error ("No memory");
 
396
 
 
397
        sender = dbus_message_get_sender (message);
 
398
 
 
399
        if (g_hash_table_lookup (listener->priv->inhibitors, sender)) {
 
400
                g_hash_table_remove (listener->priv->inhibitors, sender);
 
401
                listener_check_activation (listener);
 
402
        } else {
 
403
                g_warning ("Service '%s' was not in the list of inhibitors!", sender);
 
404
        }
 
405
 
 
406
        /* FIXME?  Pointless? */
 
407
        if (! dbus_connection_send (connection, reply, NULL))
 
408
                g_error ("No memory");
 
409
 
 
410
        dbus_message_unref (reply);
 
411
 
 
412
        return DBUS_HANDLER_RESULT_HANDLED;
 
413
}
 
414
 
 
415
static void
 
416
listener_service_deleted (GSListener  *listener,
 
417
                          DBusMessage *message)
 
418
{
 
419
        char *old_service_name;
 
420
        char *new_service_name;
 
421
        char *reason;
 
422
 
 
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!");
 
428
                return;
 
429
        }
 
430
 
 
431
        reason = g_hash_table_lookup (listener->priv->inhibitors, new_service_name);
 
432
 
 
433
        if (reason != NULL) {
 
434
                g_hash_table_remove (listener->priv->inhibitors, new_service_name);
 
435
                listener_check_activation (listener);
 
436
        }
 
437
}
 
438
 
 
439
static void
 
440
raise_property_type_error (DBusConnection *connection,
 
441
                           DBusMessage    *in_reply_to,
 
442
                           const char     *device_id)
 
443
{
 
444
        char         buf [512];
 
445
        DBusMessage *reply;
 
446
 
 
447
        snprintf (buf, 511,
 
448
                  "Type mismatch setting property with id %s",
 
449
                  device_id);
 
450
        g_warning (buf);
 
451
 
 
452
        reply = dbus_message_new_error (in_reply_to,
 
453
                                        "org.gnome.screensaver.TypeMismatch",
 
454
                                        buf);
 
455
        if (reply == NULL)
 
456
                g_error ("No memory");
 
457
        if (!dbus_connection_send (connection, reply, NULL))
 
458
                g_error ("No memory");
 
459
 
 
460
        dbus_message_unref (reply);
 
461
}
 
462
 
 
463
static DBusHandlerResult
 
464
listener_set_property (GSListener     *listener,
 
465
                       DBusConnection *connection,
 
466
                       DBusMessage    *message,
 
467
                       guint           prop_id)
 
468
{
 
469
        const char     *path;
 
470
        int             type;
 
471
        gboolean        rc;
 
472
        DBusMessageIter iter;
 
473
        DBusMessage    *reply;
 
474
 
 
475
        path = dbus_message_get_path (message);
 
476
 
 
477
        dbus_message_iter_init (message, &iter);
 
478
        type = dbus_message_iter_get_arg_type (&iter);
 
479
        rc = FALSE;
 
480
 
 
481
        switch (type) {
 
482
        case DBUS_TYPE_BOOLEAN:
 
483
                {
 
484
                        dbus_bool_t v;
 
485
                        dbus_message_iter_get_basic (&iter, &v);
 
486
                        rc = listener_property_set_bool (listener, prop_id, v);
 
487
                        break;
 
488
                }
 
489
        default:
 
490
                g_warning ("Unsupported property type %d", type);
 
491
                break;
 
492
        }
 
493
 
 
494
        if (! rc) {
 
495
                raise_property_type_error (connection, message, path);
 
496
                return DBUS_HANDLER_RESULT_HANDLED;
 
497
        }
 
498
 
 
499
        reply = dbus_message_new_method_return (message);
 
500
 
 
501
        if (reply == NULL)
 
502
                g_error ("No memory");
 
503
 
 
504
        if (!dbus_connection_send (connection, reply, NULL))
 
505
                g_error ("No memory");
 
506
 
 
507
        dbus_message_unref (reply);
 
508
 
 
509
        return DBUS_HANDLER_RESULT_HANDLED;
 
510
}
 
511
 
 
512
static DBusHandlerResult
 
513
listener_get_property (GSListener     *listener,
 
514
                       DBusConnection *connection,
 
515
                       DBusMessage    *message,
 
516
                       guint           prop_id)
 
517
{
 
518
        const char     *path;
 
519
        DBusMessageIter iter;
 
520
        DBusMessage    *reply;
 
521
 
 
522
        path = dbus_message_get_path (message);
 
523
 
 
524
        reply = dbus_message_new_method_return (message);
 
525
 
 
526
        dbus_message_iter_init_append (reply, &iter);
 
527
 
 
528
        if (reply == NULL)
 
529
                g_error ("No memory");
 
530
 
 
531
        switch (prop_id) {
 
532
        case PROP_ACTIVE:
 
533
                {
 
534
                        dbus_bool_t b;
 
535
                        b = listener->priv->active;
 
536
                        dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &b);
 
537
                }
 
538
                break;
 
539
        case PROP_IDLE:
 
540
                {
 
541
                        dbus_bool_t b;
 
542
                        b = listener->priv->idle;
 
543
                        dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &b);
 
544
                }
 
545
                break;
 
546
        case PROP_THROTTLE_ENABLED:
 
547
                {
 
548
                        dbus_bool_t b;
 
549
                        b = listener->priv->throttle_enabled;
 
550
                        dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &b);
 
551
                }
 
552
                break;
 
553
        default:
 
554
                g_warning ("Unsupported property id %d", prop_id);
 
555
                break;
 
556
        }
 
557
 
 
558
        if (!dbus_connection_send (connection, reply, NULL))
 
559
                g_error ("No memory");
 
560
 
 
561
        dbus_message_unref (reply);
 
562
 
 
563
        return DBUS_HANDLER_RESULT_HANDLED;
 
564
}
 
565
 
 
566
static DBusHandlerResult
 
567
listener_get_idle_time (GSListener     *listener,
 
568
                        DBusConnection *connection,
 
569
                        DBusMessage    *message)
 
570
{
 
571
        const char     *path;
 
572
        DBusMessageIter iter;
 
573
        DBusMessage    *reply;
 
574
        dbus_uint32_t    secs;
 
575
 
 
576
        path = dbus_message_get_path (message);
 
577
 
 
578
        reply = dbus_message_new_method_return (message);
 
579
 
 
580
        dbus_message_iter_init_append (reply, &iter);
 
581
 
 
582
        if (reply == NULL)
 
583
                g_error ("No memory");
 
584
 
 
585
        if (listener->priv->idle) {
 
586
                time_t now = time (NULL);
 
587
 
 
588
                if (now < listener->priv->idle_start) {
 
589
                        /* should't happen */
 
590
                        g_warning ("Idle start time is in the future");
 
591
                        secs = 0;
 
592
                } else {
 
593
                        secs = listener->priv->idle_start - now;
 
594
                }
 
595
        } else {
 
596
                secs = 0;
 
597
        }
 
598
        dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &secs);
 
599
 
 
600
        if (! dbus_connection_send (connection, reply, NULL))
 
601
                g_error ("No memory");
 
602
 
 
603
        dbus_message_unref (reply);
 
604
 
 
605
        return DBUS_HANDLER_RESULT_HANDLED;
 
606
}
 
607
 
 
608
static DBusHandlerResult
 
609
listener_dbus_filter_handle_methods (DBusConnection *connection,
 
610
                                     DBusMessage    *message, 
 
611
                                     void           *user_data,
 
612
                                     dbus_bool_t     local_interface)
 
613
{
 
614
        GSListener *listener = GS_LISTENER (user_data);
 
615
 
 
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);
 
618
 
 
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;
 
622
        }
 
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;
 
626
        }
 
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;
 
630
        }
 
631
        if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "InhibitActivation")) {
 
632
                return listener_add_inhibitor (listener, connection, message);
 
633
        }
 
634
        if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "AllowActivation")) {
 
635
                return listener_remove_inhibitor (listener, connection, message);
 
636
        }
 
637
        if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "setActive")) {
 
638
                return listener_set_property (listener, connection, message, PROP_ACTIVE);
 
639
        }
 
640
        if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "getActive")) {
 
641
                return listener_get_property (listener, connection, message, PROP_ACTIVE);
 
642
        }
 
643
        if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "getIdle")) {
 
644
                return listener_get_property (listener, connection, message, PROP_IDLE);
 
645
        }
 
646
        if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "getIdleTime")) {
 
647
                return listener_get_idle_time (listener, connection, message);
 
648
        }
 
649
        if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "setThrottleEnabled")) {
 
650
                return listener_set_property (listener, connection, message, PROP_THROTTLE_ENABLED);
 
651
        }
 
652
        if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "getThrottleEnabled")) {
 
653
                return listener_get_property (listener, connection, message, PROP_THROTTLE_ENABLED);
 
654
        }
 
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;
 
658
        }
 
659
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
660
}
 
661
 
 
662
static DBusHandlerResult
 
663
gs_listener_message_handler (DBusConnection *connection,
 
664
                             DBusMessage    *message,
 
665
                             void           *user_data)
 
666
{
 
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);
 
669
 
 
670
        /*
 
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));
 
676
        */
 
677
 
 
678
        if (dbus_message_is_method_call (message, "org.freedesktop.DBus", "AddMatch")) {
 
679
                DBusMessage *reply;
 
680
 
 
681
                /* cheat, and handle AddMatch since libhal will try to invoke this method */
 
682
                reply = dbus_message_new_method_return (message);
 
683
 
 
684
                if (reply == NULL)
 
685
                        g_error ("No memory");
 
686
 
 
687
                if (!dbus_connection_send (connection, reply, NULL))
 
688
                        g_error ("No memory");
 
689
 
 
690
                dbus_message_unref (reply);
 
691
 
 
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) {
 
695
                
 
696
                dbus_connection_unref (connection);
 
697
 
 
698
                return DBUS_HANDLER_RESULT_HANDLED;
 
699
        } 
 
700
        else return listener_dbus_filter_handle_methods (connection, message, user_data, TRUE);
 
701
}
 
702
 
 
703
static DBusHandlerResult
 
704
listener_dbus_filter_function (DBusConnection *connection,
 
705
                               DBusMessage    *message,
 
706
                               void           *user_data)
 
707
{
 
708
        GSListener *listener = GS_LISTENER (user_data);
 
709
        const char *path;
 
710
 
 
711
        path = dbus_message_get_path (message);
 
712
 
 
713
        /*
 
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));
 
718
        */
 
719
 
 
720
        if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") &&
 
721
            strcmp (path, DBUS_PATH_LOCAL) == 0) {
 
722
 
 
723
                /* this is a local message; e.g. from libdbus in this process */
 
724
 
 
725
                g_message ("Got disconnected from the system message bus; "
 
726
                           "retrying to reconnect every 3000 ms");
 
727
 
 
728
#if 0
 
729
                dbus_connection_unref (dbus_connection);
 
730
                dbus_connection = NULL;
 
731
 
 
732
                g_timeout_add (3000, reinit_dbus, NULL);
 
733
#endif
 
734
        } else if (dbus_message_is_signal (message,
 
735
                                           DBUS_INTERFACE_DBUS,
 
736
                                           "NameOwnerChanged")) {
 
737
 
 
738
                if (listener->priv->inhibitors != NULL)
 
739
                        listener_service_deleted (listener, message);
 
740
        } else 
 
741
                return listener_dbus_filter_handle_methods (connection, message, user_data, FALSE);
 
742
 
 
743
        return DBUS_HANDLER_RESULT_HANDLED;
 
744
}
 
745
 
 
746
static void
 
747
gs_listener_set_property (GObject            *object,
 
748
                          guint               prop_id,
 
749
                          const GValue       *value,
 
750
                          GParamSpec         *pspec)
 
751
{
 
752
        GSListener *self;
 
753
 
 
754
        self = GS_LISTENER (object);
 
755
 
 
756
        switch (prop_id) {
 
757
        case PROP_ACTIVE:
 
758
                gs_listener_set_active (self, g_value_get_boolean (value));
 
759
                break;
 
760
        case PROP_IDLE:
 
761
                gs_listener_set_idle (self, g_value_get_boolean (value));
 
762
                break;
 
763
        case PROP_THROTTLE_ENABLED:
 
764
                gs_listener_set_throttle_enabled (self, g_value_get_boolean (value));
 
765
                break;
 
766
        default:
 
767
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
768
                break;
 
769
        }
 
770
}
 
771
 
 
772
static void
 
773
gs_listener_get_property (GObject            *object,
 
774
                          guint               prop_id,
 
775
                          GValue             *value,
 
776
                          GParamSpec         *pspec)
 
777
{
 
778
        GSListener *self;
 
779
 
 
780
        self = GS_LISTENER (object);
 
781
 
 
782
        switch (prop_id) {
 
783
        case PROP_ACTIVE:
 
784
                g_value_set_boolean (value, self->priv->active);
 
785
                break;
 
786
        case PROP_IDLE:
 
787
                g_value_set_boolean (value, self->priv->idle);
 
788
                break;
 
789
        case PROP_THROTTLE_ENABLED:
 
790
                g_value_set_boolean (value, self->priv->throttle_enabled);
 
791
                break;
 
792
        default:
 
793
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
794
                break;
 
795
        }
 
796
}
 
797
 
 
798
static void
 
799
gs_listener_class_init (GSListenerClass *klass)
 
800
{
 
801
        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
 
802
 
 
803
        parent_class = g_type_class_peek_parent (klass);
 
804
 
 
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;
 
808
 
 
809
        signals [LOCK] =
 
810
                g_signal_new ("lock",
 
811
                              G_TYPE_FROM_CLASS (object_class),
 
812
                              G_SIGNAL_RUN_LAST,
 
813
                              G_STRUCT_OFFSET (GSListenerClass, lock),
 
814
                              NULL,
 
815
                              NULL,
 
816
                              g_cclosure_marshal_VOID__VOID,
 
817
                              G_TYPE_NONE,
 
818
                              0);
 
819
        signals [QUIT] =
 
820
                g_signal_new ("quit",
 
821
                              G_TYPE_FROM_CLASS (object_class),
 
822
                              G_SIGNAL_RUN_LAST,
 
823
                              G_STRUCT_OFFSET (GSListenerClass, quit),
 
824
                              NULL,
 
825
                              NULL,
 
826
                              g_cclosure_marshal_VOID__VOID,
 
827
                              G_TYPE_NONE,
 
828
                              0);
 
829
        signals [CYCLE] =
 
830
                g_signal_new ("cycle",
 
831
                              G_TYPE_FROM_CLASS (object_class),
 
832
                              G_SIGNAL_RUN_LAST,
 
833
                              G_STRUCT_OFFSET (GSListenerClass, cycle),
 
834
                              NULL,
 
835
                              NULL,
 
836
                              g_cclosure_marshal_VOID__VOID,
 
837
                              G_TYPE_NONE,
 
838
                              0);
 
839
        signals [POKE] =
 
840
                g_signal_new ("poke",
 
841
                              G_TYPE_FROM_CLASS (object_class),
 
842
                              G_SIGNAL_RUN_LAST,
 
843
                              G_STRUCT_OFFSET (GSListenerClass, poke),
 
844
                              NULL,
 
845
                              NULL,
 
846
                              g_cclosure_marshal_VOID__VOID,
 
847
                              G_TYPE_NONE,
 
848
                              0);
 
849
        signals [ACTIVE_CHANGED] =
 
850
                g_signal_new ("active-changed",
 
851
                              G_TYPE_FROM_CLASS (object_class),
 
852
                              G_SIGNAL_RUN_LAST,
 
853
                              G_STRUCT_OFFSET (GSListenerClass, active_changed),
 
854
                              NULL,
 
855
                              NULL,
 
856
                              g_cclosure_marshal_VOID__BOOLEAN,
 
857
                              G_TYPE_NONE,
 
858
                              1,
 
859
                              G_TYPE_BOOLEAN);
 
860
        signals [THROTTLE_ENABLED_CHANGED] =
 
861
                g_signal_new ("throttle-enabled-changed",
 
862
                              G_TYPE_FROM_CLASS (object_class),
 
863
                              G_SIGNAL_RUN_LAST,
 
864
                              G_STRUCT_OFFSET (GSListenerClass, throttle_enabled_changed),
 
865
                              NULL,
 
866
                              NULL,
 
867
                              g_cclosure_marshal_VOID__BOOLEAN,
 
868
                              G_TYPE_NONE,
 
869
                              1,
 
870
                              G_TYPE_BOOLEAN);
 
871
 
 
872
        g_object_class_install_property (object_class,
 
873
                                         PROP_ACTIVE,
 
874
                                         g_param_spec_boolean ("active",
 
875
                                                               NULL,
 
876
                                                               NULL,
 
877
                                                               FALSE,
 
878
                                                               G_PARAM_READWRITE));
 
879
        g_object_class_install_property (object_class,
 
880
                                         PROP_THROTTLE_ENABLED,
 
881
                                         g_param_spec_boolean ("throttle-enabled",
 
882
                                                               NULL,
 
883
                                                               NULL,
 
884
                                                               FALSE,
 
885
                                                               G_PARAM_READWRITE));
 
886
 
 
887
        g_type_class_add_private (klass, sizeof (GSListenerPrivate));
 
888
}
 
889
 
 
890
 
 
891
static gboolean
 
892
screensaver_is_running (DBusConnection *connection)
 
893
{
 
894
        DBusError               error;
 
895
        gboolean                exists;
 
896
 
 
897
        g_return_val_if_fail (connection != NULL, FALSE);
 
898
 
 
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);
 
903
 
 
904
        return exists;
 
905
}
 
906
 
 
907
gboolean
 
908
gs_listener_acquire (GSListener *listener,
 
909
                     GError    **error)
 
910
{
 
911
        gboolean acquired;
 
912
        DBusError buserror;
 
913
 
 
914
        g_return_val_if_fail (listener != NULL, FALSE);
 
915
 
 
916
        if (!listener->priv->connection) {
 
917
                g_set_error (error,
 
918
                             GS_LISTENER_ERROR,
 
919
                             GS_LISTENER_ERROR_ACQUISITION_FAILURE,
 
920
                             "%s",
 
921
                             _("failed to register with the message bus"));
 
922
                return FALSE;
 
923
        }
 
924
 
 
925
        if (screensaver_is_running (listener->priv->connection)) {
 
926
                g_set_error (error,
 
927
                             GS_LISTENER_ERROR,
 
928
                             GS_LISTENER_ERROR_ACQUISITION_FAILURE,
 
929
                             "%s",
 
930
                             _("screensaver already running in this session"));
 
931
                return FALSE;
 
932
        }
 
933
 
 
934
        dbus_error_init (&buserror);
 
935
 
 
936
        if (dbus_connection_register_object_path (listener->priv->connection,
 
937
                                                  GS_LISTENER_PATH,
 
938
                                                  &gs_listener_vtable,
 
939
                                                  listener) == FALSE)
 
940
                g_critical ("out of memory registering object path");
 
941
 
 
942
        acquired = dbus_bus_request_name (listener->priv->connection,
 
943
                                          GS_LISTENER_SERVICE,
 
944
                                          0, &buserror) != -1;
 
945
        if (dbus_error_is_set (&buserror))
 
946
                g_set_error (error,
 
947
                             GS_LISTENER_ERROR,
 
948
                             GS_LISTENER_ERROR_ACQUISITION_FAILURE,
 
949
                             "%s",
 
950
                             buserror.message);
 
951
 
 
952
        dbus_error_free (&buserror);
 
953
 
 
954
        dbus_connection_add_filter (listener->priv->connection, listener_dbus_filter_function, listener, NULL);
 
955
 
 
956
        dbus_bus_add_match (listener->priv->connection,
 
957
                            "type='signal'"
 
958
                            ",interface='"DBUS_INTERFACE_DBUS"'"
 
959
                            ",sender='"DBUS_SERVICE_DBUS"'"
 
960
                            ",member='NameOwnerChanged'",
 
961
                            NULL);
 
962
 
 
963
        return acquired;
 
964
}
 
965
 
 
966
static void
 
967
gs_listener_init (GSListener *listener)
 
968
{
 
969
        DBusError error;
 
970
 
 
971
        listener->priv = GS_LISTENER_GET_PRIVATE (listener);
 
972
 
 
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",
 
977
                            error.message);
 
978
        } else {
 
979
                dbus_connection_setup_with_g_main (listener->priv->connection, NULL);
 
980
        }
 
981
 
 
982
        dbus_error_free (&error);
 
983
}
 
984
 
 
985
static void
 
986
gs_listener_finalize (GObject *object)
 
987
{
 
988
        GSListener *listener;
 
989
 
 
990
        g_return_if_fail (object != NULL);
 
991
        g_return_if_fail (GS_IS_LISTENER (object));
 
992
 
 
993
        listener = GS_LISTENER (object);
 
994
 
 
995
        g_return_if_fail (listener->priv != NULL);
 
996
 
 
997
        /*dbus_connection_unref (listener->priv->connection);*/
 
998
 
 
999
        if (listener->priv->inhibitors)
 
1000
                g_hash_table_destroy (listener->priv->inhibitors);
 
1001
 
 
1002
        G_OBJECT_CLASS (parent_class)->finalize (object);
 
1003
}
 
1004
 
 
1005
GSListener *
 
1006
gs_listener_new (void)
 
1007
{
 
1008
        GSListener *listener;
 
1009
 
 
1010
        listener = g_object_new (GS_TYPE_LISTENER, NULL);
 
1011
 
 
1012
        return GS_LISTENER (listener);
 
1013
}