2005-03-24 Daniel Reed <n@ml.org>
[platform/upstream/dbus.git] / tools / dbus-names-model.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-names-model.c GtkTreeModel for names on the bus
3  *
4  * Copyright (C) 2005 Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #include "dbus-names-model.h"
24 #include <glib/gi18n.h>
25 #include <string.h>
26
27 enum
28 {
29   MODEL_COLUMN_NAME,
30   
31   MODEL_COLUMN_LAST
32 };
33
34
35 typedef struct NamesModel NamesModel;
36 typedef struct NamesModelClass NamesModelClass;
37
38 GType names_model_get_type (void);
39
40 struct NamesModel
41 {
42   GtkListStore parent;
43   DBusGConnection *connection;
44   DBusGProxy *driver_proxy;
45   DBusGPendingCall *pending_list_names;
46 };
47
48 struct NamesModelClass
49 {
50   GtkListStoreClass parent;
51 };
52
53 #define TYPE_NAMES_MODEL              (names_model_get_type ())
54 #define NAMES_MODEL(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), TYPE_NAMES_MODEL, NamesModel))
55 #define NAMES_MODEL_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NAMES_MODEL, NamesModelClass))
56 #define IS_NAMES_MODEL(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), TYPE_NAMES_MODEL))
57 #define IS_NAMES_MODEL_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_NAMES_MODEL))
58 #define NAMES_MODEL_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_NAMES_MODEL, NamesModelClass))
59
60 static void
61 have_names_notify (DBusGPendingCall *call,
62                    void             *data)
63 {
64   NamesModel *names_model;
65   GError *error;
66   char **names;
67   int n_elements;
68   int i;
69
70   names_model = NAMES_MODEL (data);
71
72   g_assert (names_model->pending_list_names);
73   g_assert (names_model->driver_proxy);
74
75   names = NULL;
76   error = NULL;
77   if (!dbus_g_proxy_end_call (names_model->driver_proxy,
78                               names_model->pending_list_names,
79                               &error, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
80                               &names, &n_elements, DBUS_TYPE_INVALID))
81     {
82       g_assert (names == NULL);
83       g_assert (error != NULL);
84       
85       g_printerr (_("Failed to load names on the bus: %s\n"), error->message);
86       g_error_free (error);
87       return;
88     }
89
90   i = 0;
91   while (names[i])
92     {
93       GtkTreeIter iter;
94
95       g_assert (i < n_elements);
96
97 #if 0
98       g_printerr ("%d of %d: %s\n",
99                   i, n_elements, names[i]);
100 #endif
101       
102       gtk_list_store_append (GTK_LIST_STORE (names_model),
103                              &iter);
104
105       gtk_list_store_set (GTK_LIST_STORE (names_model),
106                           &iter,
107                           MODEL_COLUMN_NAME, names[i],
108                           -1);
109       
110       ++i;
111     }
112   
113   g_strfreev (names);
114 }
115
116 static gboolean
117 names_model_find_name (NamesModel  *names_model,
118                        const char  *name,
119                        GtkTreeIter *iter_p)
120 {
121   GtkTreeIter iter;
122   
123   if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (names_model),
124                                       &iter))
125     return FALSE;
126   
127   do
128     {
129       char *s;
130       
131       gtk_tree_model_get (GTK_TREE_MODEL (names_model),
132                           &iter,
133                           MODEL_COLUMN_NAME, &s,
134                           -1);
135       if (s && strcmp (s, name) == 0)
136         {
137           *iter_p = iter;
138           g_free (s);
139           return TRUE;
140         }
141       
142       g_free (s);
143     }
144   while (gtk_tree_model_iter_next (GTK_TREE_MODEL (names_model),
145                                    &iter));
146
147   return FALSE;
148 }
149
150 static void
151 name_owner_changed (DBusGProxy *driver_proxy,
152                     const char *name,
153                     const char *old_owner,
154                     const char *new_owner,
155                     void       *data)
156 {
157   NamesModel *names_model = NAMES_MODEL (data);
158
159 #if 0
160   g_printerr ("Name '%s' changed owner '%s' -> '%s'\n",
161               name, old_owner, new_owner);
162 #endif
163
164   if (*new_owner == '\0')
165     {
166       /* this name has vanished */
167       GtkTreeIter iter;
168
169       if (names_model_find_name (names_model, name, &iter))
170         gtk_list_store_remove (GTK_LIST_STORE (names_model),
171                                &iter);
172     }
173   else if (*old_owner == '\0')
174     {
175       /* this name has been added */
176       GtkTreeIter iter;
177       
178       if (!names_model_find_name (names_model, name, &iter))
179         {
180           gtk_list_store_append (GTK_LIST_STORE (names_model),
181                                  &iter);
182           
183           gtk_list_store_set (GTK_LIST_STORE (names_model),
184                               &iter,
185                               MODEL_COLUMN_NAME, name,
186                               -1);
187         }
188     }
189 }
190
191 static void
192 names_model_reload (NamesModel *names_model)
193 {
194   GtkListStore *list_store;
195
196   list_store = GTK_LIST_STORE (names_model);
197
198   if (names_model->pending_list_names)
199     {
200       dbus_g_pending_call_cancel (names_model->pending_list_names);
201       dbus_g_pending_call_unref (names_model->pending_list_names);
202       names_model->pending_list_names = NULL;
203     }
204   
205   gtk_list_store_clear (list_store);
206   
207   if (names_model->connection == NULL)
208     return;
209   
210   names_model->pending_list_names =
211     dbus_g_proxy_begin_call (names_model->driver_proxy,
212                              "ListNames",
213                              DBUS_TYPE_INVALID);
214
215   dbus_g_pending_call_set_notify (names_model->pending_list_names,
216                                   have_names_notify, names_model, NULL);
217 }
218
219 static void
220 names_model_set_connection (NamesModel      *names_model,
221                             DBusGConnection *connection)
222 {
223   g_return_if_fail (IS_NAMES_MODEL (names_model));
224   
225   if (connection == names_model->connection)
226     return;
227
228   if (names_model->connection)
229     {
230       dbus_g_proxy_disconnect_signal (names_model->driver_proxy,
231                                       "NameOwnerChanged",
232                                       G_CALLBACK (name_owner_changed),
233                                       names_model);
234       
235       g_object_unref (names_model->driver_proxy);
236       names_model->driver_proxy = NULL;
237       dbus_g_connection_unref (names_model->connection);
238       names_model->connection = NULL;
239     }
240   
241   if (connection)
242     {
243       names_model->connection = connection;
244       dbus_g_connection_ref (names_model->connection);
245       
246       names_model->driver_proxy =
247         dbus_g_proxy_new_for_name (names_model->connection,
248                                    DBUS_SERVICE_DBUS,
249                                    DBUS_PATH_DBUS,
250                                    DBUS_INTERFACE_DBUS);
251       g_assert (names_model->driver_proxy);
252
253       dbus_g_proxy_add_signal (names_model->driver_proxy,
254                                "NameOwnerChanged",
255                                DBUS_TYPE_STRING_AS_STRING
256                                DBUS_TYPE_STRING_AS_STRING
257                                DBUS_TYPE_STRING_AS_STRING);
258       
259       dbus_g_proxy_connect_signal (names_model->driver_proxy,
260                                    "NameOwnerChanged", 
261                                    G_CALLBACK (name_owner_changed),
262                                    names_model,
263                                    NULL);
264     }
265
266   names_model_reload (names_model);
267 }
268
269 G_DEFINE_TYPE(NamesModel, names_model, GTK_TYPE_LIST_STORE)
270
271 /* Properties */
272 enum
273 {
274   PROP_0,
275   PROP_CONNECTION
276 };
277
278 static void
279 names_model_dispose (GObject *object)
280 {
281   NamesModel *names_model = NAMES_MODEL (object);
282
283   names_model_set_connection (names_model, NULL);
284
285   g_assert (names_model->connection == NULL);
286   g_assert (names_model->driver_proxy == NULL);
287   g_assert (names_model->pending_list_names == NULL);
288
289   (G_OBJECT_CLASS (names_model_parent_class)->dispose) (object);
290 }
291
292 static void
293 names_model_finalize (GObject *object)
294 {
295   NamesModel *names_model = NAMES_MODEL (object);
296
297   g_assert (names_model->connection == NULL);
298   g_assert (names_model->driver_proxy == NULL);
299   g_assert (names_model->pending_list_names == NULL);
300
301   (G_OBJECT_CLASS (names_model_parent_class)->finalize) (object);
302 }
303
304 static void
305 names_model_set_property (GObject      *object,
306                           guint         prop_id,
307                           const GValue *value,
308                           GParamSpec   *pspec)
309 {
310   NamesModel *names_model;
311
312   names_model = NAMES_MODEL (object);
313
314   switch (prop_id)
315     {
316     case PROP_CONNECTION:
317       names_model_set_connection (names_model, g_value_get_boxed (value));
318       break;
319
320     default:
321       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
322       break;
323     }
324 }
325
326 static void
327 names_model_get_property (GObject      *object,
328                           guint         prop_id,
329                           GValue       *value,
330                           GParamSpec   *pspec)
331 {
332   NamesModel *names_model;
333
334   names_model = NAMES_MODEL (object);
335
336   switch (prop_id)
337     {
338     case PROP_CONNECTION:
339       g_value_set_boxed (value, names_model->connection);
340       break;
341
342     default:
343       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
344       break;
345     }
346 }
347
348 static void
349 names_model_init (NamesModel *names_model)
350 {
351   GtkListStore *list_store;
352   GType types[MODEL_COLUMN_LAST];
353
354   list_store = GTK_LIST_STORE (names_model);
355
356   types[0] = G_TYPE_STRING; /* name */
357   gtk_list_store_set_column_types (list_store, MODEL_COLUMN_LAST, types);
358 }
359
360 static void
361 names_model_class_init (NamesModelClass *names_model_class)
362 {
363   GObjectClass *gobject_class = G_OBJECT_CLASS (names_model_class);
364
365   gobject_class->finalize = names_model_finalize;
366   gobject_class->dispose = names_model_dispose;
367   gobject_class->set_property = names_model_set_property;
368   gobject_class->get_property = names_model_get_property;
369
370   g_object_class_install_property (gobject_class,
371                                    PROP_CONNECTION,
372                                    g_param_spec_boxed ("connection",
373                                                        _("Bus connection"),
374                                                        _("Connection to the message bus"),
375                                                        DBUS_TYPE_G_CONNECTION,
376                                                        G_PARAM_READWRITE));
377 }
378
379 GtkTreeModel*
380 names_model_new (DBusGConnection *connection)
381 {
382   NamesModel *names_model;
383
384   names_model = g_object_new (TYPE_NAMES_MODEL,
385                               "connection", connection,
386                               NULL);
387
388   return GTK_TREE_MODEL (names_model);
389 }
390