1*2912Sartem /***************************************************************************
2*2912Sartem * CVSID: $Id$
3*2912Sartem *
4*2912Sartem * device_store.c : HalDeviceStore methods
5*2912Sartem *
6*2912Sartem * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
7*2912Sartem * Copyright (C) 2004 Novell, Inc.
8*2912Sartem *
9*2912Sartem * Licensed under the Academic Free License version 2.1
10*2912Sartem *
11*2912Sartem * This program is free software; you can redistribute it and/or modify
12*2912Sartem * it under the terms of the GNU General Public License as published by
13*2912Sartem * the Free Software Foundation; either version 2 of the License, or
14*2912Sartem * (at your option) any later version.
15*2912Sartem *
16*2912Sartem * This program is distributed in the hope that it will be useful,
17*2912Sartem * but WITHOUT ANY WARRANTY; without even the implied warranty of
18*2912Sartem * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19*2912Sartem * GNU General Public License for more details.
20*2912Sartem *
21*2912Sartem * You should have received a copy of the GNU General Public License
22*2912Sartem * along with this program; if not, write to the Free Software
23*2912Sartem * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*2912Sartem *
25*2912Sartem **************************************************************************/
26*2912Sartem
27*2912Sartem #ifdef HAVE_CONFIG_H
28*2912Sartem # include <config.h>
29*2912Sartem #endif
30*2912Sartem
31*2912Sartem #include <stdio.h>
32*2912Sartem #include <string.h>
33*2912Sartem
34*2912Sartem #include "device_store.h"
35*2912Sartem #include "hald_marshal.h"
36*2912Sartem #include "logger.h"
37*2912Sartem
38*2912Sartem static GObjectClass *parent_class;
39*2912Sartem
40*2912Sartem enum {
41*2912Sartem STORE_CHANGED,
42*2912Sartem DEVICE_PROPERTY_CHANGED,
43*2912Sartem DEVICE_CAPABILITY_ADDED,
44*2912Sartem LAST_SIGNAL
45*2912Sartem };
46*2912Sartem
47*2912Sartem static guint signals[LAST_SIGNAL] = { 0 };
48*2912Sartem
49*2912Sartem static void
hal_device_store_finalize(GObject * obj)50*2912Sartem hal_device_store_finalize (GObject *obj)
51*2912Sartem {
52*2912Sartem HalDeviceStore *store = HAL_DEVICE_STORE (obj);
53*2912Sartem
54*2912Sartem g_slist_foreach (store->devices, (GFunc) g_object_unref, NULL);
55*2912Sartem
56*2912Sartem if (parent_class->finalize)
57*2912Sartem parent_class->finalize (obj);
58*2912Sartem }
59*2912Sartem
60*2912Sartem static void
hal_device_store_class_init(HalDeviceStoreClass * klass)61*2912Sartem hal_device_store_class_init (HalDeviceStoreClass *klass)
62*2912Sartem {
63*2912Sartem GObjectClass *obj_class = (GObjectClass *) klass;
64*2912Sartem
65*2912Sartem parent_class = g_type_class_peek_parent (klass);
66*2912Sartem
67*2912Sartem obj_class->finalize = hal_device_store_finalize;
68*2912Sartem
69*2912Sartem signals[STORE_CHANGED] =
70*2912Sartem g_signal_new ("store_changed",
71*2912Sartem G_TYPE_FROM_CLASS (klass),
72*2912Sartem G_SIGNAL_RUN_LAST,
73*2912Sartem G_STRUCT_OFFSET (HalDeviceStoreClass,
74*2912Sartem store_changed),
75*2912Sartem NULL, NULL,
76*2912Sartem hald_marshal_VOID__OBJECT_BOOL,
77*2912Sartem G_TYPE_NONE, 2,
78*2912Sartem G_TYPE_OBJECT,
79*2912Sartem G_TYPE_BOOLEAN);
80*2912Sartem
81*2912Sartem signals[DEVICE_PROPERTY_CHANGED] =
82*2912Sartem g_signal_new ("device_property_changed",
83*2912Sartem G_TYPE_FROM_CLASS (klass),
84*2912Sartem G_SIGNAL_RUN_LAST,
85*2912Sartem G_STRUCT_OFFSET (HalDeviceStoreClass,
86*2912Sartem device_property_changed),
87*2912Sartem NULL, NULL,
88*2912Sartem hald_marshal_VOID__OBJECT_STRING_BOOL_BOOL,
89*2912Sartem G_TYPE_NONE, 4,
90*2912Sartem G_TYPE_OBJECT,
91*2912Sartem G_TYPE_STRING,
92*2912Sartem G_TYPE_BOOLEAN,
93*2912Sartem G_TYPE_BOOLEAN);
94*2912Sartem
95*2912Sartem signals[DEVICE_CAPABILITY_ADDED] =
96*2912Sartem g_signal_new ("device_capability_added",
97*2912Sartem G_TYPE_FROM_CLASS (klass),
98*2912Sartem G_SIGNAL_RUN_LAST,
99*2912Sartem G_STRUCT_OFFSET (HalDeviceStoreClass,
100*2912Sartem device_capability_added),
101*2912Sartem NULL, NULL,
102*2912Sartem hald_marshal_VOID__OBJECT_STRING,
103*2912Sartem G_TYPE_NONE, 2,
104*2912Sartem G_TYPE_OBJECT,
105*2912Sartem G_TYPE_STRING);
106*2912Sartem }
107*2912Sartem
108*2912Sartem static void
hal_device_store_init(HalDeviceStore * device)109*2912Sartem hal_device_store_init (HalDeviceStore *device)
110*2912Sartem {
111*2912Sartem }
112*2912Sartem
113*2912Sartem GType
hal_device_store_get_type(void)114*2912Sartem hal_device_store_get_type (void)
115*2912Sartem {
116*2912Sartem static GType type = 0;
117*2912Sartem
118*2912Sartem if (!type) {
119*2912Sartem static GTypeInfo type_info = {
120*2912Sartem sizeof (HalDeviceStoreClass),
121*2912Sartem NULL, NULL,
122*2912Sartem (GClassInitFunc) hal_device_store_class_init,
123*2912Sartem NULL, NULL,
124*2912Sartem sizeof (HalDeviceStore),
125*2912Sartem 0,
126*2912Sartem (GInstanceInitFunc) hal_device_store_init
127*2912Sartem };
128*2912Sartem
129*2912Sartem type = g_type_register_static (G_TYPE_OBJECT,
130*2912Sartem "HalDeviceStore",
131*2912Sartem &type_info,
132*2912Sartem 0);
133*2912Sartem }
134*2912Sartem
135*2912Sartem return type;
136*2912Sartem }
137*2912Sartem
138*2912Sartem HalDeviceStore *
hal_device_store_new(void)139*2912Sartem hal_device_store_new (void)
140*2912Sartem {
141*2912Sartem HalDeviceStore *store;
142*2912Sartem
143*2912Sartem store = g_object_new (HAL_TYPE_DEVICE_STORE, NULL, NULL);
144*2912Sartem
145*2912Sartem return store;
146*2912Sartem }
147*2912Sartem
148*2912Sartem static void
emit_device_property_changed(HalDevice * device,const char * key,gboolean added,gboolean removed,gpointer data)149*2912Sartem emit_device_property_changed (HalDevice *device,
150*2912Sartem const char *key,
151*2912Sartem gboolean added,
152*2912Sartem gboolean removed,
153*2912Sartem gpointer data)
154*2912Sartem {
155*2912Sartem HalDeviceStore *store = HAL_DEVICE_STORE (data);
156*2912Sartem
157*2912Sartem g_signal_emit (store, signals[DEVICE_PROPERTY_CHANGED], 0,
158*2912Sartem device, key, added, removed);
159*2912Sartem }
160*2912Sartem
161*2912Sartem static void
emit_device_capability_added(HalDevice * device,const char * capability,gpointer data)162*2912Sartem emit_device_capability_added (HalDevice *device,
163*2912Sartem const char *capability,
164*2912Sartem gpointer data)
165*2912Sartem {
166*2912Sartem HalDeviceStore *store = HAL_DEVICE_STORE (data);
167*2912Sartem
168*2912Sartem g_signal_emit (store, signals[DEVICE_CAPABILITY_ADDED], 0,
169*2912Sartem device, capability);
170*2912Sartem }
171*2912Sartem
172*2912Sartem void
hal_device_store_add(HalDeviceStore * store,HalDevice * device)173*2912Sartem hal_device_store_add (HalDeviceStore *store, HalDevice *device)
174*2912Sartem {
175*2912Sartem const char buf[] = "/org/freedesktop/Hal/devices/";
176*2912Sartem
177*2912Sartem if (strncmp(device->udi, buf, sizeof (buf) - 1) != 0) {
178*2912Sartem
179*2912Sartem HAL_ERROR(("Can't add HalDevice with incorrect UDI. Valid "
180*2912Sartem "UDI must start with '/org/freedesktop/Hal/devices/'"));
181*2912Sartem goto out;
182*2912Sartem }
183*2912Sartem store->devices = g_slist_prepend (store->devices,
184*2912Sartem g_object_ref (device));
185*2912Sartem
186*2912Sartem g_signal_connect (device, "property_changed",
187*2912Sartem G_CALLBACK (emit_device_property_changed), store);
188*2912Sartem g_signal_connect (device, "capability_added",
189*2912Sartem G_CALLBACK (emit_device_capability_added), store);
190*2912Sartem
191*2912Sartem g_signal_emit (store, signals[STORE_CHANGED], 0, device, TRUE);
192*2912Sartem
193*2912Sartem out:
194*2912Sartem ;
195*2912Sartem }
196*2912Sartem
197*2912Sartem gboolean
hal_device_store_remove(HalDeviceStore * store,HalDevice * device)198*2912Sartem hal_device_store_remove (HalDeviceStore *store, HalDevice *device)
199*2912Sartem {
200*2912Sartem if (!g_slist_find (store->devices, device))
201*2912Sartem return FALSE;
202*2912Sartem
203*2912Sartem store->devices = g_slist_remove (store->devices, device);
204*2912Sartem
205*2912Sartem g_signal_handlers_disconnect_by_func (device,
206*2912Sartem (gpointer)emit_device_property_changed,
207*2912Sartem store);
208*2912Sartem g_signal_handlers_disconnect_by_func (device,
209*2912Sartem (gpointer)emit_device_capability_added,
210*2912Sartem store);
211*2912Sartem
212*2912Sartem g_signal_emit (store, signals[STORE_CHANGED], 0, device, FALSE);
213*2912Sartem
214*2912Sartem g_object_unref (device);
215*2912Sartem
216*2912Sartem return TRUE;
217*2912Sartem }
218*2912Sartem
219*2912Sartem HalDevice *
hal_device_store_find(HalDeviceStore * store,const char * udi)220*2912Sartem hal_device_store_find (HalDeviceStore *store, const char *udi)
221*2912Sartem {
222*2912Sartem GSList *iter;
223*2912Sartem
224*2912Sartem for (iter = store->devices; iter != NULL; iter = iter->next) {
225*2912Sartem HalDevice *d = iter->data;
226*2912Sartem
227*2912Sartem if (strcmp (hal_device_get_udi (d), udi) == 0)
228*2912Sartem return d;
229*2912Sartem }
230*2912Sartem
231*2912Sartem return NULL;
232*2912Sartem }
233*2912Sartem
234*2912Sartem void
hal_device_store_foreach(HalDeviceStore * store,HalDeviceStoreForeachFn callback,gpointer user_data)235*2912Sartem hal_device_store_foreach (HalDeviceStore *store,
236*2912Sartem HalDeviceStoreForeachFn callback,
237*2912Sartem gpointer user_data)
238*2912Sartem {
239*2912Sartem GSList *iter;
240*2912Sartem
241*2912Sartem g_return_if_fail (store != NULL);
242*2912Sartem g_return_if_fail (callback != NULL);
243*2912Sartem
244*2912Sartem for (iter = store->devices; iter != NULL; iter = iter->next) {
245*2912Sartem HalDevice *d = HAL_DEVICE (iter->data);
246*2912Sartem gboolean cont;
247*2912Sartem
248*2912Sartem cont = callback (store, d, user_data);
249*2912Sartem
250*2912Sartem if (cont == FALSE)
251*2912Sartem return;
252*2912Sartem }
253*2912Sartem }
254*2912Sartem
255*2912Sartem static gboolean
hal_device_store_print_foreach_fn(HalDeviceStore * store,HalDevice * device,gpointer user_data)256*2912Sartem hal_device_store_print_foreach_fn (HalDeviceStore *store,
257*2912Sartem HalDevice *device,
258*2912Sartem gpointer user_data)
259*2912Sartem {
260*2912Sartem fprintf (stderr, "----\n");
261*2912Sartem hal_device_print (device);
262*2912Sartem fprintf (stderr, "----\n");
263*2912Sartem return TRUE;
264*2912Sartem }
265*2912Sartem
266*2912Sartem void
hal_device_store_print(HalDeviceStore * store)267*2912Sartem hal_device_store_print (HalDeviceStore *store)
268*2912Sartem {
269*2912Sartem fprintf (stderr, "===============================================\n");
270*2912Sartem fprintf (stderr, "Dumping %d devices\n",
271*2912Sartem g_slist_length (store->devices));
272*2912Sartem fprintf (stderr, "===============================================\n");
273*2912Sartem hal_device_store_foreach (store,
274*2912Sartem hal_device_store_print_foreach_fn,
275*2912Sartem NULL);
276*2912Sartem fprintf (stderr, "===============================================\n");
277*2912Sartem }
278*2912Sartem
279*2912Sartem HalDevice *
hal_device_store_match_key_value_string(HalDeviceStore * store,const char * key,const char * value)280*2912Sartem hal_device_store_match_key_value_string (HalDeviceStore *store,
281*2912Sartem const char *key,
282*2912Sartem const char *value)
283*2912Sartem {
284*2912Sartem GSList *iter;
285*2912Sartem
286*2912Sartem g_return_val_if_fail (store != NULL, NULL);
287*2912Sartem g_return_val_if_fail (key != NULL, NULL);
288*2912Sartem g_return_val_if_fail (value != NULL, NULL);
289*2912Sartem
290*2912Sartem for (iter = store->devices; iter != NULL; iter = iter->next) {
291*2912Sartem HalDevice *d = HAL_DEVICE (iter->data);
292*2912Sartem int type;
293*2912Sartem
294*2912Sartem if (!hal_device_has_property (d, key))
295*2912Sartem continue;
296*2912Sartem
297*2912Sartem type = hal_device_property_get_type (d, key);
298*2912Sartem if (type != HAL_PROPERTY_TYPE_STRING)
299*2912Sartem continue;
300*2912Sartem
301*2912Sartem if (strcmp (hal_device_property_get_string (d, key),
302*2912Sartem value) == 0)
303*2912Sartem return d;
304*2912Sartem }
305*2912Sartem
306*2912Sartem return NULL;
307*2912Sartem }
308*2912Sartem
309*2912Sartem HalDevice *
hal_device_store_match_key_value_int(HalDeviceStore * store,const char * key,int value)310*2912Sartem hal_device_store_match_key_value_int (HalDeviceStore *store,
311*2912Sartem const char *key,
312*2912Sartem int value)
313*2912Sartem {
314*2912Sartem GSList *iter;
315*2912Sartem
316*2912Sartem g_return_val_if_fail (store != NULL, NULL);
317*2912Sartem g_return_val_if_fail (key != NULL, NULL);
318*2912Sartem
319*2912Sartem for (iter = store->devices; iter != NULL; iter = iter->next) {
320*2912Sartem HalDevice *d = HAL_DEVICE (iter->data);
321*2912Sartem int type;
322*2912Sartem
323*2912Sartem if (!hal_device_has_property (d, key))
324*2912Sartem continue;
325*2912Sartem
326*2912Sartem type = hal_device_property_get_type (d, key);
327*2912Sartem if (type != HAL_PROPERTY_TYPE_INT32)
328*2912Sartem continue;
329*2912Sartem
330*2912Sartem if (hal_device_property_get_int (d, key) == value)
331*2912Sartem return d;
332*2912Sartem }
333*2912Sartem
334*2912Sartem return NULL;
335*2912Sartem }
336*2912Sartem
337*2912Sartem GSList *
hal_device_store_match_multiple_key_value_string(HalDeviceStore * store,const char * key,const char * value)338*2912Sartem hal_device_store_match_multiple_key_value_string (HalDeviceStore *store,
339*2912Sartem const char *key,
340*2912Sartem const char *value)
341*2912Sartem {
342*2912Sartem GSList *iter;
343*2912Sartem GSList *matches = NULL;
344*2912Sartem
345*2912Sartem g_return_val_if_fail (store != NULL, NULL);
346*2912Sartem g_return_val_if_fail (key != NULL, NULL);
347*2912Sartem g_return_val_if_fail (value != NULL, NULL);
348*2912Sartem
349*2912Sartem for (iter = store->devices; iter != NULL; iter = iter->next) {
350*2912Sartem HalDevice *d = HAL_DEVICE (iter->data);
351*2912Sartem int type;
352*2912Sartem
353*2912Sartem if (!hal_device_has_property (d, key))
354*2912Sartem continue;
355*2912Sartem
356*2912Sartem type = hal_device_property_get_type (d, key);
357*2912Sartem if (type != HAL_PROPERTY_TYPE_STRING)
358*2912Sartem continue;
359*2912Sartem
360*2912Sartem if (strcmp (hal_device_property_get_string (d, key),
361*2912Sartem value) == 0)
362*2912Sartem matches = g_slist_prepend (matches, d);
363*2912Sartem }
364*2912Sartem
365*2912Sartem return matches;
366*2912Sartem }
367*2912Sartem
368*2912Sartem typedef struct {
369*2912Sartem HalDeviceStore *store;
370*2912Sartem char *key;
371*2912Sartem char *value;
372*2912Sartem HalDeviceStoreAsyncCallback callback;
373*2912Sartem gpointer user_data;
374*2912Sartem
375*2912Sartem guint prop_signal_id;
376*2912Sartem guint store_signal_id;
377*2912Sartem guint timeout_id;
378*2912Sartem } AsyncMatchInfo;
379*2912Sartem
380*2912Sartem static void
destroy_async_match_info(AsyncMatchInfo * info)381*2912Sartem destroy_async_match_info (AsyncMatchInfo *info)
382*2912Sartem {
383*2912Sartem g_object_unref (info->store);
384*2912Sartem
385*2912Sartem g_free (info->key);
386*2912Sartem g_free (info->value);
387*2912Sartem
388*2912Sartem g_signal_handler_disconnect (info->store, info->prop_signal_id);
389*2912Sartem g_signal_handler_disconnect (info->store, info->store_signal_id);
390*2912Sartem g_source_remove (info->timeout_id);
391*2912Sartem
392*2912Sartem g_free (info);
393*2912Sartem }
394*2912Sartem
395*2912Sartem static void
match_device_async(HalDeviceStore * store,HalDevice * device,const char * key,gboolean removed,gboolean added,gpointer user_data)396*2912Sartem match_device_async (HalDeviceStore *store, HalDevice *device,
397*2912Sartem const char *key, gboolean removed, gboolean added,
398*2912Sartem gpointer user_data)
399*2912Sartem {
400*2912Sartem AsyncMatchInfo *info = (AsyncMatchInfo *) user_data;
401*2912Sartem
402*2912Sartem /* Only want to do it for added or changed properties */
403*2912Sartem if (removed)
404*2912Sartem return;
405*2912Sartem
406*2912Sartem /* Keys have to match */
407*2912Sartem if (strcmp (info->key, key) != 0)
408*2912Sartem return;
409*2912Sartem
410*2912Sartem /* Values have to match */
411*2912Sartem if (strcmp (hal_device_property_get_string (device, key),
412*2912Sartem info->value) != 0)
413*2912Sartem return;
414*2912Sartem
415*2912Sartem info->callback (store, device, info->user_data);
416*2912Sartem
417*2912Sartem destroy_async_match_info (info);
418*2912Sartem }
419*2912Sartem
420*2912Sartem static void
store_changed(HalDeviceStore * store,HalDevice * device,gboolean added,gpointer user_data)421*2912Sartem store_changed (HalDeviceStore *store, HalDevice *device,
422*2912Sartem gboolean added, gpointer user_data)
423*2912Sartem {
424*2912Sartem AsyncMatchInfo *info = (AsyncMatchInfo *) user_data;
425*2912Sartem
426*2912Sartem if (!added)
427*2912Sartem return;
428*2912Sartem
429*2912Sartem if (!hal_device_has_property (device, info->key))
430*2912Sartem return;
431*2912Sartem
432*2912Sartem if (strcmp (hal_device_property_get_string (device, info->key),
433*2912Sartem info->value) != 0)
434*2912Sartem return;
435*2912Sartem
436*2912Sartem info->callback (store, device, info->user_data);
437*2912Sartem
438*2912Sartem destroy_async_match_info (info);
439*2912Sartem }
440*2912Sartem
441*2912Sartem static gboolean
match_device_async_timeout(gpointer user_data)442*2912Sartem match_device_async_timeout (gpointer user_data)
443*2912Sartem {
444*2912Sartem AsyncMatchInfo *info = (AsyncMatchInfo *) user_data;
445*2912Sartem
446*2912Sartem info->callback (info->store, NULL, info->user_data);
447*2912Sartem
448*2912Sartem destroy_async_match_info (info);
449*2912Sartem
450*2912Sartem return FALSE;
451*2912Sartem }
452*2912Sartem
453*2912Sartem void
hal_device_store_match_key_value_string_async(HalDeviceStore * store,const char * key,const char * value,HalDeviceStoreAsyncCallback callback,gpointer user_data,int timeout)454*2912Sartem hal_device_store_match_key_value_string_async (HalDeviceStore *store,
455*2912Sartem const char *key,
456*2912Sartem const char *value,
457*2912Sartem HalDeviceStoreAsyncCallback callback,
458*2912Sartem gpointer user_data,
459*2912Sartem int timeout)
460*2912Sartem {
461*2912Sartem HalDevice *device;
462*2912Sartem AsyncMatchInfo *info;
463*2912Sartem
464*2912Sartem /* First check to see if it's already there */
465*2912Sartem device = hal_device_store_match_key_value_string (store, key, value);
466*2912Sartem
467*2912Sartem if (device != NULL || timeout == 0) {
468*2912Sartem callback (store, device, user_data);
469*2912Sartem
470*2912Sartem return;
471*2912Sartem }
472*2912Sartem
473*2912Sartem info = g_new0 (AsyncMatchInfo, 1);
474*2912Sartem
475*2912Sartem info->store = g_object_ref (store);
476*2912Sartem info->key = g_strdup (key);
477*2912Sartem info->value = g_strdup (value);
478*2912Sartem info->callback = callback;
479*2912Sartem info->user_data = user_data;
480*2912Sartem
481*2912Sartem info->prop_signal_id = g_signal_connect (store,
482*2912Sartem "device_property_changed",
483*2912Sartem G_CALLBACK (match_device_async),
484*2912Sartem info);
485*2912Sartem info->store_signal_id = g_signal_connect (store,
486*2912Sartem "store_changed",
487*2912Sartem G_CALLBACK (store_changed),
488*2912Sartem info);
489*2912Sartem
490*2912Sartem info->timeout_id = g_timeout_add (timeout,
491*2912Sartem match_device_async_timeout,
492*2912Sartem info);
493*2912Sartem }
494