~ubuntu-branches/ubuntu/precise/libzeitgeist/precise-proposed

« back to all changes in this revision

Viewing changes to src/zeitgeist-data-source-registry.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2010-08-02 18:22:32 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20100802182232-47ohrpyfxep802pr
Tags: 0.2.3-0ubuntu1
* New upstream release.
  - New API to talk to the Data Source Registry extension of Zeitgeist
    (Michal Hruby)
  - A new "connected" property on ZeitgeistLog telling you whether or
    not the Zeitgeist daemon is running (Michal Hruby)
  - Fix a crasher when finalizing a ZeitgeistLog with active monitors
    installed (Michal Hruby)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2010 Canonical, Ltd.
 
3
 *
 
4
 * This library is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU Lesser General Public License
 
6
 * version 3.0 as published by the Free Software Foundation.
 
7
 *
 
8
 * This library is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
 * GNU Lesser General Public License version 3.0 for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU Lesser General Public
 
14
 * License along with this library. If not, see
 
15
 * <http://www.gnu.org/licenses/>.
 
16
 *
 
17
 * Authored by: Michal Hruby <michal.mhr@gmail.com>
 
18
 */
 
19
 
 
20
#if HAVE_CONFIG_H
 
21
#include <config.h>
 
22
#endif
 
23
 
 
24
#include "zeitgeist-data-source-registry.h"
 
25
#include "zeitgeist-eggdbusconversions.h"
 
26
#include "zeitgeist-marshal.h"
 
27
#include "eggzeitgeistbindings.h"
 
28
 
 
29
/**
 
30
 * SECTION:zeitgeist-data-source-registry
 
31
 * @short_description: Query the Zeitgeist Data Source Registry extension
 
32
 * @include: zeitgeist.h
 
33
 *
 
34
 * The Zeitgeist engine maintains a publicly available list of recognized
 
35
 * data-sources (components inserting information into Zeitgeist).
 
36
 * #ZeitgeistDataSourceRegistry is used to register new data sources,
 
37
 * get information about them and gives the ability to enable or disable
 
38
 * the data sources.
 
39
 */
 
40
 
 
41
G_DEFINE_TYPE (ZeitgeistDataSourceRegistry,
 
42
               zeitgeist_data_source_registry,
 
43
               G_TYPE_OBJECT);
 
44
#define ZEITGEIST_DATA_SOURCE_REGISTRY_GET_PRIVATE(obj) \
 
45
  (G_TYPE_INSTANCE_GET_PRIVATE(obj, ZEITGEIST_TYPE_DATA_SOURCE_REGISTRY, \
 
46
                               ZeitgeistDataSourceRegistryPrivate))
 
47
 
 
48
typedef struct
 
49
{
 
50
  /* The connection to the ZG daemon
 
51
   * Note: The EggZeitgeistDataSourceRegistry is owned by 
 
52
   * the EggDBusObjectProxy!
 
53
   */
 
54
  EggDBusObjectProxy *registry_proxy;
 
55
  EggZeitgeistDataSourceRegistry *registry;
 
56
 
 
57
  gulong src_registered_id;
 
58
  gulong src_disconnected_id;
 
59
  gulong src_enabled_id;
 
60
 
 
61
} ZeitgeistDataSourceRegistryPrivate;
 
62
 
 
63
/* Property ids */
 
64
enum
 
65
{
 
66
        PROP_0,
 
67
 
 
68
        LAST_PROPERTY
 
69
};
 
70
 
 
71
enum
 
72
{
 
73
  SOURCE_REGISTERED,
 
74
  SOURCE_ENABLED,
 
75
  SOURCE_DISCONNECTED,
 
76
 
 
77
  LAST_SIGNAL
 
78
};
 
79
static guint _registry_signals[LAST_SIGNAL] = { 0 };
 
80
 
 
81
static void
 
82
zeitgeist_data_source_registry_init (ZeitgeistDataSourceRegistry *self)
 
83
{
 
84
  ZeitgeistDataSourceRegistryPrivate *priv;
 
85
  EggDBusConnection   *conn;
 
86
 
 
87
  priv = ZEITGEIST_DATA_SOURCE_REGISTRY_GET_PRIVATE (self);
 
88
  
 
89
  /* Set up the connection to the ZG daemon */  
 
90
  conn = egg_dbus_connection_get_for_bus (EGG_DBUS_BUS_TYPE_SESSION);
 
91
  priv->registry_proxy = 
 
92
    egg_dbus_connection_get_object_proxy (conn,
 
93
                                          "org.gnome.zeitgeist.Engine",
 
94
                                          "/org/gnome/zeitgeist/data_source_registry");
 
95
  
 
96
  priv->registry =
 
97
    EGG_ZEITGEIST_QUERY_INTERFACE_DATA_SOURCE_REGISTRY (priv->registry_proxy);
 
98
  g_object_unref (conn);
 
99
}
 
100
 
 
101
static void
 
102
zeitgeist_data_source_registry_finalize (GObject *object)
 
103
{
 
104
  ZeitgeistDataSourceRegistry *registry;
 
105
  ZeitgeistDataSourceRegistryPrivate *priv;
 
106
  
 
107
  registry = ZEITGEIST_DATA_SOURCE_REGISTRY (object);
 
108
  priv = ZEITGEIST_DATA_SOURCE_REGISTRY_GET_PRIVATE (registry);
 
109
 
 
110
  if (priv->src_registered_id)
 
111
    {
 
112
      g_signal_handler_disconnect (priv->registry, priv->src_registered_id);
 
113
    }
 
114
 
 
115
  if (priv->src_disconnected_id)
 
116
    {
 
117
      g_signal_handler_disconnect (priv->registry, priv->src_disconnected_id);
 
118
    }
 
119
 
 
120
  if (priv->src_enabled_id)
 
121
    {
 
122
      g_signal_handler_disconnect (priv->registry, priv->src_enabled_id);
 
123
    }
 
124
 
 
125
  /* Note: priv->registry is owned by priv->registry_proxy */
 
126
  if (priv->registry_proxy)
 
127
    {
 
128
      g_object_unref (priv->registry_proxy);
 
129
    }
 
130
  
 
131
  G_OBJECT_CLASS (zeitgeist_data_source_registry_parent_class)->finalize (object);
 
132
}
 
133
 
 
134
static void
 
135
zeitgeist_data_source_registry_get_property (GObject    *object,
 
136
                                             guint       prop_id,
 
137
                                             GValue     *value,
 
138
                                             GParamSpec *pspec)
 
139
{
 
140
  ZeitgeistDataSourceRegistryPrivate *priv;
 
141
 
 
142
  priv = ZEITGEIST_DATA_SOURCE_REGISTRY_GET_PRIVATE (object);
 
143
 
 
144
  switch (prop_id)
 
145
    {
 
146
      default:
 
147
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
148
        return;
 
149
        break;
 
150
    }
 
151
}
 
152
 
 
153
static void
 
154
zeitgeist_data_source_registry_set_property (GObject      *object,
 
155
                                             guint         prop_id,
 
156
                                             const GValue *value,
 
157
                                             GParamSpec   *pspec)
 
158
{
 
159
  ZeitgeistDataSourceRegistryPrivate *priv;
 
160
 
 
161
  priv = ZEITGEIST_DATA_SOURCE_REGISTRY_GET_PRIVATE (object);
 
162
 
 
163
  switch (prop_id)
 
164
    {
 
165
      default:
 
166
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
167
        return;
 
168
        break;
 
169
    }
 
170
}
 
171
 
 
172
static void
 
173
zeitgeist_data_source_registry_src_registered (
 
174
    ZeitgeistDataSourceRegistry *registry,
 
175
    EggZeitgeistDataSource *source)
 
176
{
 
177
  ZeitgeistDataSource *data_source;
 
178
 
 
179
  data_source = _egg_zeitgeist_data_source_to_zeitgeist_data_source (source);
 
180
 
 
181
  g_signal_emit (registry, _registry_signals[SOURCE_REGISTERED],
 
182
                 0, data_source);
 
183
 
 
184
  g_object_unref (data_source);
 
185
}
 
186
 
 
187
static void
 
188
zeitgeist_data_source_registry_src_disconnected (
 
189
    ZeitgeistDataSourceRegistry *registry,
 
190
    EggZeitgeistDataSource *source)
 
191
{
 
192
  ZeitgeistDataSource *data_source;
 
193
 
 
194
  data_source = _egg_zeitgeist_data_source_to_zeitgeist_data_source (source);
 
195
 
 
196
  g_signal_emit (registry, _registry_signals[SOURCE_DISCONNECTED],
 
197
                 0, data_source);
 
198
 
 
199
  g_object_unref (data_source);
 
200
}
 
201
 
 
202
static void
 
203
zeitgeist_data_source_registry_src_enabled (
 
204
    ZeitgeistDataSourceRegistry *registry,
 
205
    gchar *unique_id,
 
206
    gboolean enabled)
 
207
{
 
208
  g_signal_emit (registry, _registry_signals[SOURCE_ENABLED],
 
209
                 0, unique_id, enabled);
 
210
}
 
211
 
 
212
static void
 
213
zeitgeist_data_source_registry_constructed (GObject *object)
 
214
{
 
215
  ZeitgeistDataSourceRegistryPrivate *priv;
 
216
 
 
217
  priv = ZEITGEIST_DATA_SOURCE_REGISTRY_GET_PRIVATE (object);
 
218
 
 
219
  priv->src_registered_id = g_signal_connect_swapped (
 
220
      priv->registry, "data-source-registered",
 
221
      G_CALLBACK (zeitgeist_data_source_registry_src_registered),
 
222
      object);
 
223
  priv->src_disconnected_id = g_signal_connect_swapped (
 
224
      priv->registry, "data-source-disconnected",
 
225
      G_CALLBACK (zeitgeist_data_source_registry_src_disconnected),
 
226
      object);
 
227
  priv->src_enabled_id = g_signal_connect_swapped (
 
228
      priv->registry, "data-source-enabled",
 
229
      G_CALLBACK (zeitgeist_data_source_registry_src_enabled),
 
230
      object);
 
231
}
 
232
 
 
233
static void
 
234
zeitgeist_data_source_registry_class_init (ZeitgeistDataSourceRegistryClass *klass)
 
235
{
 
236
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
237
  GParamSpec   *pspec;
 
238
  
 
239
  object_class->finalize     = zeitgeist_data_source_registry_finalize;
 
240
  object_class->get_property = zeitgeist_data_source_registry_get_property;
 
241
  object_class->set_property = zeitgeist_data_source_registry_set_property;
 
242
  object_class->constructed  = zeitgeist_data_source_registry_constructed;
 
243
 
 
244
  _registry_signals[SOURCE_REGISTERED] =
 
245
    g_signal_new ("source-registered",
 
246
                  G_OBJECT_CLASS_TYPE (object_class),
 
247
                  G_SIGNAL_RUN_FIRST,
 
248
                  G_STRUCT_OFFSET (ZeitgeistDataSourceRegistryClass, source_registered),
 
249
                  NULL, NULL,
 
250
                  g_cclosure_marshal_VOID__OBJECT,
 
251
                  G_TYPE_NONE, 1, ZEITGEIST_TYPE_DATA_SOURCE);
 
252
 
 
253
  _registry_signals[SOURCE_DISCONNECTED] =
 
254
    g_signal_new ("source-disconnected",
 
255
                  G_OBJECT_CLASS_TYPE (object_class),
 
256
                  G_SIGNAL_RUN_FIRST,
 
257
                  G_STRUCT_OFFSET (ZeitgeistDataSourceRegistryClass, source_disconnected),
 
258
                  NULL, NULL,
 
259
                  g_cclosure_marshal_VOID__OBJECT,
 
260
                  G_TYPE_NONE, 1, ZEITGEIST_TYPE_DATA_SOURCE);
 
261
 
 
262
  _registry_signals[SOURCE_ENABLED] =
 
263
    g_signal_new ("source-enabled",
 
264
                  G_OBJECT_CLASS_TYPE (object_class),
 
265
                  G_SIGNAL_RUN_FIRST,
 
266
                  G_STRUCT_OFFSET (ZeitgeistDataSourceRegistryClass, source_enabled),
 
267
                  NULL, NULL,
 
268
                  _zeitgeist_cclosure_marshal_VOID__STRING_BOOLEAN,
 
269
                  G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN);
 
270
 
 
271
  g_type_class_add_private (object_class,
 
272
                            sizeof (ZeitgeistDataSourceRegistryPrivate));
 
273
}
 
274
 
 
275
/* Used to marshal the async callbacks from EggDBus into ones
 
276
 * coming from this DataSourceRegistry instance */
 
277
static void
 
278
dispatch_async_callback (GObject      *source_object,
 
279
                         GAsyncResult *res,
 
280
                         gpointer      user_data)
 
281
 
282
  gpointer                    *data = (gpointer*) user_data;
 
283
  ZeitgeistDataSourceRegistry *self = ZEITGEIST_DATA_SOURCE_REGISTRY (data[0]);
 
284
  GAsyncReadyCallback          callback = (GAsyncReadyCallback) data[1];
 
285
  gpointer                     _user_data = data[2];
 
286
 
 
287
  if (callback != NULL)
 
288
    {
 
289
      callback (G_OBJECT (self), res, _user_data);
 
290
    }
 
291
  
 
292
  g_object_unref (self);
 
293
  g_free (user_data);
 
294
}
 
295
 
 
296
/*
 
297
 * API BELOW HERE
 
298
 */
 
299
 
 
300
/**
 
301
 * zeitgeist_data_source_registry_new:
 
302
 *
 
303
 * Create a new data source registry instance.
 
304
 *
 
305
 * DataSourceRegistry instances are not overly expensive for neither 
 
306
 * client or the Zeitgeist daemon so there's no need to go to lengths
 
307
 * to keep singleton instances around.
 
308
 *
 
309
 * Returns: A reference to a newly allocated registry.
 
310
 */
 
311
ZeitgeistDataSourceRegistry*
 
312
zeitgeist_data_source_registry_new (void)
 
313
{
 
314
  ZeitgeistDataSourceRegistry *registry;
 
315
 
 
316
  registry = (ZeitgeistDataSourceRegistry*)
 
317
    g_object_new (ZEITGEIST_TYPE_DATA_SOURCE_REGISTRY, NULL);
 
318
 
 
319
  return registry;
 
320
}
 
321
 
 
322
void
 
323
zeitgeist_data_source_registry_get_data_sources (
 
324
                                     ZeitgeistDataSourceRegistry *self,
 
325
                                     GCancellable                *cancellable,
 
326
                                     GAsyncReadyCallback          callback,
 
327
                                     gpointer                     user_data)
 
328
{
 
329
  ZeitgeistDataSourceRegistryPrivate *priv;
 
330
  gpointer                           *dispatch_data;
 
331
 
 
332
  g_return_if_fail (ZEITGEIST_IS_DATA_SOURCE_REGISTRY (self));
 
333
  g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
334
 
 
335
  priv = ZEITGEIST_DATA_SOURCE_REGISTRY_GET_PRIVATE (self);
 
336
 
 
337
  dispatch_data = g_new (gpointer, 3);
 
338
  dispatch_data[0] = g_object_ref (self);
 
339
  dispatch_data[1] = callback;
 
340
  dispatch_data[2] = user_data;
 
341
 
 
342
  egg_zeitgeist_data_source_registry_get_data_sources (
 
343
      priv->registry,
 
344
      EGG_DBUS_CALL_FLAGS_NONE,
 
345
      cancellable,
 
346
      dispatch_async_callback,
 
347
      dispatch_data);
 
348
}
 
349
 
 
350
/**
 
351
 * zeitgeist_data_source_registry_get_data_sources_finish:
 
352
 * @self: Instance of #ZeitgeistDataSourceRegistry.
 
353
 * @res: a #GAsyncResult.
 
354
 * @error: a #GError or #NULL.
 
355
 *
 
356
 * Returns: Newly created #GPtrArray containing #ZeitgeistDataSource<!-- -->(s)
 
357
 *          registered in Zeitgeist. Free using g_ptr_array_unref() once
 
358
 *          you're done using it.
 
359
 */
 
360
GPtrArray*
 
361
zeitgeist_data_source_registry_get_data_sources_finish (
 
362
                                     ZeitgeistDataSourceRegistry *self,
 
363
                                     GAsyncResult                *res,
 
364
                                     GError                      **error)
 
365
{
 
366
  ZeitgeistDataSourceRegistryPrivate *priv;
 
367
  EggDBusArraySeq                    *array_seq;
 
368
  gboolean                            call_result;
 
369
  GPtrArray                          *data_sources = NULL;
 
370
 
 
371
  g_return_val_if_fail (ZEITGEIST_IS_DATA_SOURCE_REGISTRY (self), NULL);
 
372
 
 
373
  priv = ZEITGEIST_DATA_SOURCE_REGISTRY_GET_PRIVATE (self);
 
374
 
 
375
  call_result = egg_zeitgeist_data_source_registry_get_data_sources_finish (
 
376
      priv->registry,
 
377
      &array_seq,
 
378
      res,
 
379
      error);
 
380
 
 
381
  data_sources =
 
382
    _egg_zeitgeist_data_sources_to_zeitgeist_data_sources (array_seq);
 
383
  g_ptr_array_set_free_func (data_sources, g_object_unref);
 
384
 
 
385
  g_object_unref (array_seq);
 
386
 
 
387
  return data_sources;
 
388
}
 
389
 
 
390
/**
 
391
 * zeitgeist_data_source_registry_register_data_source:
 
392
 * @self: Instance of #ZeitgeistDataSourceRegistry.
 
393
 * @source: Data source to register.
 
394
 * @cancellable: a #GCancellable or #NULL.
 
395
 * @callback: a GAsyncReadyCallback to call when the request is finished.
 
396
 * @user_data: the data to pass to callback function.
 
397
 *
 
398
 * Registers new data source in the registry, the @source parameter needs to
 
399
 * have unique-id, name, description and optionally event_templates set,
 
400
 * therefore it is useful to pass #ZeitgeistDataSource instance created using
 
401
 * zeitgeist_data_source_new_full(). The registry will assume its ownership.
 
402
 */
 
403
void
 
404
zeitgeist_data_source_registry_register_data_source (
 
405
    ZeitgeistDataSourceRegistry *self,
 
406
    ZeitgeistDataSource         *source,
 
407
    GCancellable                *cancellable,
 
408
    GAsyncReadyCallback          callback,
 
409
    gpointer                     user_data)
 
410
{
 
411
  ZeitgeistDataSourceRegistryPrivate *priv;
 
412
  gpointer                           *dispatch_data;
 
413
  EggDBusArraySeq                    *templates;
 
414
 
 
415
  g_return_if_fail (ZEITGEIST_IS_DATA_SOURCE_REGISTRY (self));
 
416
  g_return_if_fail (ZEITGEIST_IS_DATA_SOURCE (source));
 
417
  g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
418
 
 
419
  priv = ZEITGEIST_DATA_SOURCE_REGISTRY_GET_PRIVATE (self);
 
420
 
 
421
  g_object_ref_sink (G_OBJECT (source));
 
422
  
 
423
  dispatch_data = g_new (gpointer, 3);
 
424
  dispatch_data[0] = g_object_ref (self);
 
425
  dispatch_data[1] = callback;
 
426
  dispatch_data[2] = user_data;
 
427
 
 
428
  templates = _zeitgeist_events_to_egg_zeitgeist_events (
 
429
      zeitgeist_data_source_get_event_templates (source)
 
430
  );
 
431
 
 
432
  egg_zeitgeist_data_source_registry_register_data_source (
 
433
      priv->registry,
 
434
      EGG_DBUS_CALL_FLAGS_NONE,
 
435
      zeitgeist_data_source_get_unique_id (source),
 
436
      zeitgeist_data_source_get_name (source),
 
437
      zeitgeist_data_source_get_description (source),
 
438
      templates,
 
439
      cancellable,
 
440
      dispatch_async_callback,
 
441
      dispatch_data);
 
442
 
 
443
  g_object_unref (templates);
 
444
  g_object_unref (source);
 
445
}
 
446
 
 
447
/**
 
448
 * zeitgeist_data_source_registry_register_data_source_finish:
 
449
 * @self: Instance of #ZeitgeistDataSourceRegistry.
 
450
 * @res: Result of the asynchronous operation.
 
451
 * @error: a #GError or NULL.
 
452
 *
 
453
 * Returns: If error is unset, returns whether this data source is enabled.
 
454
 */
 
455
gboolean
 
456
zeitgeist_data_source_registry_register_data_source_finish (
 
457
    ZeitgeistDataSourceRegistry *self,
 
458
    GAsyncResult                *res,
 
459
    GError                     **error)
 
460
{
 
461
  ZeitgeistDataSourceRegistryPrivate *priv;
 
462
  gboolean                            result = FALSE;
 
463
 
 
464
  g_return_val_if_fail (ZEITGEIST_IS_DATA_SOURCE_REGISTRY (self), FALSE);
 
465
 
 
466
  priv = ZEITGEIST_DATA_SOURCE_REGISTRY_GET_PRIVATE (self);
 
467
 
 
468
  egg_zeitgeist_data_source_registry_register_data_source_finish (
 
469
      priv->registry,
 
470
      &result,
 
471
      res,
 
472
      error);
 
473
 
 
474
  return result;
 
475
}
 
476
 
 
477
void
 
478
zeitgeist_data_source_registry_set_data_source_enabled (
 
479
    ZeitgeistDataSourceRegistry *self,
 
480
    const gchar                 *unique_id,
 
481
    gboolean                     enabled,
 
482
    GCancellable                *cancellable,
 
483
    GAsyncReadyCallback          callback,
 
484
    gpointer                     user_data)
 
485
{
 
486
  ZeitgeistDataSourceRegistryPrivate *priv;
 
487
  gpointer                           *dispatch_data;
 
488
 
 
489
  g_return_if_fail (ZEITGEIST_IS_DATA_SOURCE_REGISTRY (self));
 
490
  g_return_if_fail (unique_id != NULL);
 
491
  g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
492
 
 
493
  priv = ZEITGEIST_DATA_SOURCE_REGISTRY_GET_PRIVATE (self);
 
494
 
 
495
  dispatch_data = g_new (gpointer, 3);
 
496
  dispatch_data[0] = g_object_ref (self);
 
497
  dispatch_data[1] = callback;
 
498
  dispatch_data[2] = user_data;
 
499
 
 
500
  egg_zeitgeist_data_source_registry_set_data_source_enabled (
 
501
      priv->registry,
 
502
      EGG_DBUS_CALL_FLAGS_NONE,
 
503
      unique_id,
 
504
      enabled,
 
505
      cancellable,
 
506
      dispatch_async_callback,
 
507
      dispatch_data);
 
508
}
 
509
 
 
510
void
 
511
zeitgeist_data_source_registry_set_data_source_enabled_finish (
 
512
    ZeitgeistDataSourceRegistry *self,
 
513
    GAsyncResult                *res,
 
514
    GError                     **error)
 
515
{
 
516
  ZeitgeistDataSourceRegistryPrivate *priv;
 
517
 
 
518
  g_return_if_fail (ZEITGEIST_IS_DATA_SOURCE_REGISTRY (self));
 
519
 
 
520
  priv = ZEITGEIST_DATA_SOURCE_REGISTRY_GET_PRIVATE (self);
 
521
 
 
522
  egg_zeitgeist_data_source_registry_set_data_source_enabled_finish (
 
523
      priv->registry,
 
524
      res,
 
525
      error);
 
526
}
 
527