00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #ifdef HAVE_CONFIG_H
00028 # include <config.h>
00029 #endif
00030
00031 #include <stdio.h>
00032 #include <string.h>
00033
00034 #include "device_store.h"
00035 #include "hald_marshal.h"
00036 #include "logger.h"
00037
00038 static GObjectClass *parent_class;
00039
00040 enum {
00041 STORE_CHANGED,
00042 DEVICE_PROPERTY_CHANGED,
00043 DEVICE_CAPABILITY_ADDED,
00044 LAST_SIGNAL
00045 };
00046
00047 static guint signals[LAST_SIGNAL] = { 0 };
00048
00049 static void
00050 hal_device_store_finalize (GObject *obj)
00051 {
00052 HalDeviceStore *store = HAL_DEVICE_STORE (obj);
00053
00054 g_slist_foreach (store->devices, (GFunc) g_object_unref, NULL);
00055
00056 if (parent_class->finalize)
00057 parent_class->finalize (obj);
00058 }
00059
00060 static void
00061 hal_device_store_class_init (HalDeviceStoreClass *klass)
00062 {
00063 GObjectClass *obj_class = (GObjectClass *) klass;
00064
00065 parent_class = g_type_class_peek_parent (klass);
00066
00067 obj_class->finalize = hal_device_store_finalize;
00068
00069 signals[STORE_CHANGED] =
00070 g_signal_new ("store_changed",
00071 G_TYPE_FROM_CLASS (klass),
00072 G_SIGNAL_RUN_LAST,
00073 G_STRUCT_OFFSET (HalDeviceStoreClass,
00074 store_changed),
00075 NULL, NULL,
00076 hald_marshal_VOID__OBJECT_BOOL,
00077 G_TYPE_NONE, 2,
00078 G_TYPE_OBJECT,
00079 G_TYPE_BOOLEAN);
00080
00081 signals[DEVICE_PROPERTY_CHANGED] =
00082 g_signal_new ("device_property_changed",
00083 G_TYPE_FROM_CLASS (klass),
00084 G_SIGNAL_RUN_LAST,
00085 G_STRUCT_OFFSET (HalDeviceStoreClass,
00086 device_property_changed),
00087 NULL, NULL,
00088 hald_marshal_VOID__OBJECT_STRING_BOOL_BOOL,
00089 G_TYPE_NONE, 4,
00090 G_TYPE_OBJECT,
00091 G_TYPE_STRING,
00092 G_TYPE_BOOLEAN,
00093 G_TYPE_BOOLEAN);
00094
00095 signals[DEVICE_CAPABILITY_ADDED] =
00096 g_signal_new ("device_capability_added",
00097 G_TYPE_FROM_CLASS (klass),
00098 G_SIGNAL_RUN_LAST,
00099 G_STRUCT_OFFSET (HalDeviceStoreClass,
00100 device_capability_added),
00101 NULL, NULL,
00102 hald_marshal_VOID__OBJECT_STRING,
00103 G_TYPE_NONE, 2,
00104 G_TYPE_OBJECT,
00105 G_TYPE_STRING);
00106 }
00107
00108 static void
00109 hal_device_store_init (HalDeviceStore *device)
00110 {
00111 }
00112
00113 GType
00114 hal_device_store_get_type (void)
00115 {
00116 static GType type = 0;
00117
00118 if (!type) {
00119 static GTypeInfo type_info = {
00120 sizeof (HalDeviceStoreClass),
00121 NULL, NULL,
00122 (GClassInitFunc) hal_device_store_class_init,
00123 NULL, NULL,
00124 sizeof (HalDeviceStore),
00125 0,
00126 (GInstanceInitFunc) hal_device_store_init
00127 };
00128
00129 type = g_type_register_static (G_TYPE_OBJECT,
00130 "HalDeviceStore",
00131 &type_info,
00132 0);
00133 }
00134
00135 return type;
00136 }
00137
00138 HalDeviceStore *
00139 hal_device_store_new (void)
00140 {
00141 HalDeviceStore *store;
00142
00143 store = g_object_new (HAL_TYPE_DEVICE_STORE, NULL);
00144
00145 return store;
00146 }
00147
00148 static void
00149 emit_device_property_changed (HalDevice *device,
00150 const char *key,
00151 gboolean added,
00152 gboolean removed,
00153 gpointer data)
00154 {
00155 HalDeviceStore *store = HAL_DEVICE_STORE (data);
00156
00157 g_signal_emit (store, signals[DEVICE_PROPERTY_CHANGED], 0,
00158 device, key, added, removed);
00159 }
00160
00161 static void
00162 emit_device_capability_added (HalDevice *device,
00163 const char *capability,
00164 gpointer data)
00165 {
00166 HalDeviceStore *store = HAL_DEVICE_STORE (data);
00167
00168 g_signal_emit (store, signals[DEVICE_CAPABILITY_ADDED], 0,
00169 device, capability);
00170 }
00171
00172 void
00173 hal_device_store_add (HalDeviceStore *store, HalDevice *device)
00174 {
00175 store->devices = g_slist_prepend (store->devices,
00176 g_object_ref (device));
00177
00178 g_signal_connect (device, "property_changed",
00179 G_CALLBACK (emit_device_property_changed), store);
00180 g_signal_connect (device, "capability_added",
00181 G_CALLBACK (emit_device_capability_added), store);
00182
00183 g_signal_emit (store, signals[STORE_CHANGED], 0, device, TRUE);
00184 }
00185
00186 gboolean
00187 hal_device_store_remove (HalDeviceStore *store, HalDevice *device)
00188 {
00189 if (!g_slist_find (store->devices, device))
00190 return FALSE;
00191
00192 store->devices = g_slist_remove (store->devices, device);
00193
00194 g_signal_handlers_disconnect_by_func (device,
00195 emit_device_property_changed,
00196 store);
00197 g_signal_handlers_disconnect_by_func (device,
00198 emit_device_capability_added,
00199 store);
00200
00201 g_signal_emit (store, signals[STORE_CHANGED], 0, device, FALSE);
00202
00203 g_object_unref (device);
00204
00205 return TRUE;
00206 }
00207
00208 HalDevice *
00209 hal_device_store_find (HalDeviceStore *store, const char *udi)
00210 {
00211 GSList *iter;
00212
00213 for (iter = store->devices; iter != NULL; iter = iter->next) {
00214 HalDevice *d = iter->data;
00215
00216 if (strcmp (hal_device_get_udi (d), udi) == 0)
00217 return d;
00218 }
00219
00220 return NULL;
00221 }
00222
00223 void
00224 hal_device_store_foreach (HalDeviceStore *store,
00225 HalDeviceStoreForeachFn callback,
00226 gpointer user_data)
00227 {
00228 GSList *iter;
00229
00230 g_return_if_fail (store != NULL);
00231 g_return_if_fail (callback != NULL);
00232
00233 for (iter = store->devices; iter != NULL; iter = iter->next) {
00234 HalDevice *d = HAL_DEVICE (iter->data);
00235 gboolean cont;
00236
00237 cont = callback (store, d, user_data);
00238
00239 if (cont == FALSE)
00240 return;
00241 }
00242 }
00243
00244 HalDevice *
00245 hal_device_store_match_key_value_string (HalDeviceStore *store,
00246 const char *key,
00247 const char *value)
00248 {
00249 GSList *iter;
00250
00251 g_return_val_if_fail (store != NULL, NULL);
00252 g_return_val_if_fail (key != NULL, NULL);
00253 g_return_val_if_fail (value != NULL, NULL);
00254
00255 for (iter = store->devices; iter != NULL; iter = iter->next) {
00256 HalDevice *d = HAL_DEVICE (iter->data);
00257 int type;
00258
00259 if (!hal_device_has_property (d, key))
00260 continue;
00261
00262 type = hal_device_property_get_type (d, key);
00263 if (type != DBUS_TYPE_STRING)
00264 continue;
00265
00266 if (strcmp (hal_device_property_get_string (d, key),
00267 value) == 0)
00268 return d;
00269 }
00270
00271 return NULL;
00272 }
00273
00274 GSList *
00275 hal_device_store_match_multiple_key_value_string (HalDeviceStore *store,
00276 const char *key,
00277 const char *value)
00278 {
00279 GSList *iter;
00280 GSList *matches = NULL;
00281
00282 g_return_val_if_fail (store != NULL, NULL);
00283 g_return_val_if_fail (key != NULL, NULL);
00284 g_return_val_if_fail (value != NULL, NULL);
00285
00286 for (iter = store->devices; iter != NULL; iter = iter->next) {
00287 HalDevice *d = HAL_DEVICE (iter->data);
00288 int type;
00289
00290 if (!hal_device_has_property (d, key))
00291 continue;
00292
00293 type = hal_device_property_get_type (d, key);
00294 if (type != DBUS_TYPE_STRING)
00295 continue;
00296
00297 if (strcmp (hal_device_property_get_string (d, key),
00298 value) == 0)
00299 matches = g_slist_prepend (matches, d);
00300 }
00301
00302 return matches;
00303 }
00304
00305 typedef struct {
00306 HalDeviceStore *store;
00307 char *key;
00308 char *value;
00309 HalDeviceStoreAsyncCallback callback;
00310 gpointer user_data;
00311
00312 guint prop_signal_id;
00313 guint store_signal_id;
00314 guint timeout_id;
00315 } AsyncMatchInfo;
00316
00317 static void
00318 destroy_async_match_info (AsyncMatchInfo *info)
00319 {
00320 g_object_unref (info->store);
00321
00322 g_free (info->key);
00323 g_free (info->value);
00324
00325 g_signal_handler_disconnect (info->store, info->prop_signal_id);
00326 g_signal_handler_disconnect (info->store, info->store_signal_id);
00327 g_source_remove (info->timeout_id);
00328
00329 g_free (info);
00330 }
00331
00332 static void
00333 match_device_async (HalDeviceStore *store, HalDevice *device,
00334 const char *key, gboolean removed, gboolean added,
00335 gpointer user_data)
00336 {
00337 AsyncMatchInfo *info = (AsyncMatchInfo *) user_data;
00338
00339
00340 if (removed)
00341 return;
00342
00343
00344 if (strcmp (info->key, key) != 0)
00345 return;
00346
00347
00348 if (strcmp (hal_device_property_get_string (device, key),
00349 info->value) != 0)
00350 return;
00351
00352 info->callback (store, device, info->user_data);
00353
00354 destroy_async_match_info (info);
00355 }
00356
00357 static void
00358 store_changed (HalDeviceStore *store, HalDevice *device,
00359 gboolean added, gpointer user_data)
00360 {
00361 AsyncMatchInfo *info = (AsyncMatchInfo *) user_data;
00362
00363 if (!added)
00364 return;
00365
00366 if (!hal_device_has_property (device, info->key))
00367 return;
00368
00369 if (strcmp (hal_device_property_get_string (device, info->key),
00370 info->value) != 0)
00371 return;
00372
00373 info->callback (store, device, info->user_data);
00374
00375 destroy_async_match_info (info);
00376 }
00377
00378 static gboolean
00379 match_device_async_timeout (gpointer user_data)
00380 {
00381 AsyncMatchInfo *info = (AsyncMatchInfo *) user_data;
00382
00383 info->callback (info->store, NULL, info->user_data);
00384
00385 destroy_async_match_info (info);
00386
00387 return FALSE;
00388 }
00389
00390 void
00391 hal_device_store_match_key_value_string_async (HalDeviceStore *store,
00392 const char *key,
00393 const char *value,
00394 HalDeviceStoreAsyncCallback callback,
00395 gpointer user_data,
00396 int timeout)
00397 {
00398 HalDevice *device;
00399 AsyncMatchInfo *info;
00400
00401
00402 device = hal_device_store_match_key_value_string (store, key, value);
00403
00404 if (device != NULL || timeout == 0) {
00405 callback (store, device, user_data);
00406
00407 return;
00408 }
00409
00410 info = g_new0 (AsyncMatchInfo, 1);
00411
00412 info->store = g_object_ref (store);
00413 info->key = g_strdup (key);
00414 info->value = g_strdup (value);
00415 info->callback = callback;
00416 info->user_data = user_data;
00417
00418 info->prop_signal_id = g_signal_connect (store,
00419 "device_property_changed",
00420 G_CALLBACK (match_device_async),
00421 info);
00422 info->store_signal_id = g_signal_connect (store,
00423 "store_changed",
00424 G_CALLBACK (store_changed),
00425 info);
00426
00427 info->timeout_id = g_timeout_add (timeout, match_device_async_timeout,
00428 info);
00429 }