00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "xmms/xmms_object.h"
00018 #include "xmms/xmms_log.h"
00019 #include "xmmsc/xmmsc_idnumbers.h"
00020
00021 #include <stdarg.h>
00022 #include <string.h>
00023
00024 static xmmsv_t *xmms_create_xmmsv_list (GList *list);
00025 static xmmsv_t *xmms_create_xmmsv_dict (GTree *dict);
00026 static xmmsv_t *xmms_create_xmmsv_bin (GString *gs);
00027 static void create_xmmsv_list_foreach (gpointer data, gpointer userdata);
00028 static gboolean create_xmmsv_dict_foreach (gpointer key, gpointer data, gpointer userdata);
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 typedef struct {
00042 xmms_object_handler_t handler;
00043 gpointer userdata;
00044 } xmms_object_handler_entry_t;
00045
00046 static gboolean
00047 cleanup_signal_list (gpointer key, gpointer value, gpointer data)
00048 {
00049 GList *list = value;
00050
00051 while (list) {
00052 g_free (list->data);
00053 list = g_list_delete_link (list, list);
00054 }
00055
00056 return FALSE;
00057 }
00058
00059
00060
00061
00062 void
00063 xmms_object_cleanup (xmms_object_t *object)
00064 {
00065 g_return_if_fail (object);
00066 g_return_if_fail (XMMS_IS_OBJECT (object));
00067
00068 if (object->signals) {
00069
00070
00071
00072
00073
00074 g_tree_foreach (object->signals, cleanup_signal_list, NULL);
00075 g_tree_destroy (object->signals);
00076 }
00077
00078 if (object->cmds) {
00079
00080
00081
00082 g_tree_destroy (object->cmds);
00083 }
00084
00085 g_mutex_free (object->mutex);
00086 }
00087
00088 static gint
00089 compare_signal_key (gconstpointer a, gconstpointer b)
00090 {
00091 gint aa = GPOINTER_TO_INT (a);
00092 gint bb = GPOINTER_TO_INT (b);
00093
00094 if (aa < bb)
00095 return -1;
00096 else if (aa > bb)
00097 return 1;
00098 else
00099 return 0;
00100 }
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115 void
00116 xmms_object_connect (xmms_object_t *object, guint32 signalid,
00117 xmms_object_handler_t handler, gpointer userdata)
00118 {
00119 GList *list = NULL;
00120 xmms_object_handler_entry_t *entry;
00121
00122 g_return_if_fail (object);
00123 g_return_if_fail (XMMS_IS_OBJECT (object));
00124 g_return_if_fail (handler);
00125
00126 entry = g_new0 (xmms_object_handler_entry_t, 1);
00127 entry->handler = handler;
00128 entry->userdata = userdata;
00129
00130 if (!object->signals)
00131 object->signals = g_tree_new (compare_signal_key);
00132 else
00133 list = g_tree_lookup (object->signals,
00134 GINT_TO_POINTER (signalid));
00135
00136 list = g_list_prepend (list, entry);
00137
00138
00139 g_tree_insert (object->signals, GINT_TO_POINTER (signalid), list);
00140 }
00141
00142
00143
00144
00145
00146 void
00147 xmms_object_disconnect (xmms_object_t *object, guint32 signalid,
00148 xmms_object_handler_t handler, gpointer userdata)
00149 {
00150 GList *list = NULL, *node;
00151 xmms_object_handler_entry_t *entry;
00152
00153 g_return_if_fail (object);
00154 g_return_if_fail (XMMS_IS_OBJECT (object));
00155 g_return_if_fail (handler);
00156
00157 g_mutex_lock (object->mutex);
00158
00159 if (object->signals) {
00160 list = g_tree_lookup (object->signals,
00161 GINT_TO_POINTER (signalid));
00162
00163 for (node = list; node; node = g_list_next (node)) {
00164 entry = node->data;
00165
00166 if (entry->handler == handler && entry->userdata == userdata)
00167 break;
00168 }
00169
00170 if (node) {
00171 list = g_list_remove_link (list, node);
00172
00173
00174 g_tree_insert (object->signals,
00175 GINT_TO_POINTER (signalid), list);
00176 }
00177 }
00178
00179 g_mutex_unlock (object->mutex);
00180
00181 g_return_if_fail (node);
00182
00183 g_free (node->data);
00184 g_list_free_1 (node);
00185 }
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195 void
00196 xmms_object_emit (xmms_object_t *object, guint32 signalid, xmmsv_t *data)
00197 {
00198 GList *list, *node, *list2 = NULL;
00199 xmms_object_handler_entry_t *entry;
00200
00201 g_return_if_fail (object);
00202 g_return_if_fail (XMMS_IS_OBJECT (object));
00203
00204 g_mutex_lock (object->mutex);
00205
00206 if (object->signals) {
00207 list = g_tree_lookup (object->signals,
00208 GINT_TO_POINTER (signalid));
00209
00210 for (node = list; node; node = g_list_next (node)) {
00211 entry = node->data;
00212
00213 list2 = g_list_prepend (list2, entry);
00214 }
00215 }
00216
00217 g_mutex_unlock (object->mutex);
00218
00219 while (list2) {
00220 entry = list2->data;
00221
00222 if (entry && entry->handler)
00223 entry->handler (object, data, entry->userdata);
00224
00225 list2 = g_list_delete_link (list2, list2);
00226 }
00227 }
00228
00229
00230
00231
00232
00233 void
00234 xmms_object_cmd_arg_init (xmms_object_cmd_arg_t *arg)
00235 {
00236 g_return_if_fail (arg);
00237
00238 memset (arg, 0, sizeof (xmms_object_cmd_arg_t));
00239 xmms_error_reset (&arg->error);
00240 }
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253 void
00254 xmms_object_emit_f (xmms_object_t *object, guint32 signalid,
00255 xmmsv_type_t type, ...)
00256 {
00257 va_list ap;
00258 xmmsv_t *arg;
00259
00260 va_start (ap, type);
00261
00262 switch (type) {
00263 case XMMSV_TYPE_NONE:
00264 arg = xmmsv_new_none ();
00265 break;
00266 case XMMSV_TYPE_INT32:
00267 arg = xmmsv_new_int (va_arg (ap, gint32));
00268 break;
00269 case XMMSV_TYPE_STRING:
00270 arg = xmmsv_new_string (va_arg (ap, gchar *));
00271 break;
00272 case XMMSV_TYPE_DICT:
00273 arg = xmms_create_xmmsv_dict (va_arg (ap, GTree *));
00274 break;
00275 case XMMSV_TYPE_END:
00276 default:
00277 XMMS_DBG ("OBJECT: trying to emit value of unsupported type (%d)!", (int)type);
00278 g_assert_not_reached ();
00279 break;
00280 }
00281 va_end (ap);
00282
00283 xmms_object_emit (object, signalid, arg);
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293 xmmsv_unref (arg);
00294 }
00295
00296 static gint
00297 compare_cmd_key (gconstpointer a, gconstpointer b)
00298 {
00299 guint aa = GPOINTER_TO_INT (a);
00300 guint bb = GPOINTER_TO_INT (b);
00301
00302 if (aa < bb)
00303 return -1;
00304 else if (aa > bb)
00305 return 1;
00306 else
00307 return 0;
00308 }
00309
00310
00311
00312
00313
00314
00315
00316
00317 void
00318 xmms_object_cmd_add (xmms_object_t *object, guint cmdid,
00319 xmms_object_cmd_desc_t *desc)
00320 {
00321 g_return_if_fail (object);
00322 g_return_if_fail (desc);
00323
00324 if (!object->cmds)
00325 object->cmds = g_tree_new (compare_cmd_key);
00326
00327 g_tree_insert (object->cmds, GUINT_TO_POINTER (cmdid), desc);
00328 }
00329
00330
00331
00332
00333
00334 void
00335 xmms_object_cmd_call (xmms_object_t *object, guint cmdid, xmms_object_cmd_arg_t *arg)
00336 {
00337 xmms_object_cmd_desc_t *desc = NULL;
00338
00339 g_return_if_fail (object);
00340
00341 if (object->cmds)
00342 desc = g_tree_lookup (object->cmds, GUINT_TO_POINTER (cmdid));
00343
00344 if (desc->func)
00345 desc->func (object, arg);
00346 }
00347
00348
00349
00350
00351
00352
00353
00354 static xmmsv_t *
00355 xmms_create_xmmsv_list (GList *list)
00356 {
00357 xmmsv_t *v = xmmsv_new_list ();
00358 g_list_foreach (list, create_xmmsv_list_foreach, (gpointer) v);
00359 return v;
00360 }
00361
00362 xmmsv_t *
00363 xmms_convert_and_kill_list (GList *list)
00364 {
00365 xmmsv_t *v;
00366
00367 v = xmms_create_xmmsv_list (list);
00368 g_list_free (list);
00369
00370 return v;
00371 }
00372
00373
00374
00375
00376
00377
00378 static xmmsv_t *
00379 xmms_create_xmmsv_dict (GTree *dict)
00380 {
00381 xmmsv_t *v = NULL;
00382 if (dict) {
00383 v = xmmsv_new_dict ();
00384 g_tree_foreach (dict, create_xmmsv_dict_foreach, (gpointer) v);
00385 }
00386 return v;
00387 }
00388
00389 xmmsv_t *
00390 xmms_convert_and_kill_dict (GTree *dict)
00391 {
00392 xmmsv_t *v;
00393
00394 v = xmms_create_xmmsv_dict (dict);
00395
00396 if (dict) {
00397 g_tree_destroy (dict);
00398 }
00399
00400 return v;
00401 }
00402
00403 xmmsv_t *
00404 xmms_convert_and_kill_string (gchar *str)
00405 {
00406 xmmsv_t *v = NULL;
00407
00408 if (str) {
00409 v = xmmsv_new_string (str);
00410 g_free (str);
00411 }
00412
00413 return v;
00414 }
00415
00416
00417
00418 static void
00419 create_xmmsv_list_foreach (gpointer data, gpointer userdata)
00420 {
00421 xmmsv_t *v = (xmmsv_t *) data;
00422 xmmsv_t *l = (xmmsv_t *) userdata;
00423
00424 xmmsv_list_append (l, v);
00425
00426
00427
00428
00429 xmmsv_unref (v);
00430 }
00431
00432 static gboolean
00433 create_xmmsv_dict_foreach (gpointer key, gpointer data, gpointer userdata)
00434 {
00435 const char *k = (const char *) key;
00436 xmmsv_t *v = (xmmsv_t *) data;
00437 xmmsv_t *l = (xmmsv_t *) userdata;
00438 xmmsv_dict_set (l, k, v);
00439 return FALSE;
00440 }
00441
00442 int
00443 xmms_bin_to_gstring (xmmsv_t *value, GString **gs)
00444 {
00445 const guchar *str;
00446 guint len;
00447 if (!xmmsv_get_bin (value, &str, &len)) {
00448 return 0;
00449 }
00450 *gs = g_string_new_len (str, len);
00451 return 1;
00452 }
00453
00454 int
00455 dummy_identity (xmmsv_t *value, xmmsv_t **arg)
00456 {
00457 *arg = value;
00458 return 1;
00459 }
00460
00461
00462
00463
00464 gboolean
00465 check_string_list (xmmsv_t *list)
00466 {
00467 xmmsv_t *valstr;
00468 xmmsv_list_iter_t *it;
00469
00470 for (xmmsv_get_list_iter (list, &it);
00471 xmmsv_list_iter_valid (it);
00472 xmmsv_list_iter_next (it)) {
00473 xmmsv_list_iter_entry (it, &valstr);
00474 if (xmmsv_get_type (valstr) != XMMSV_TYPE_STRING) {
00475 return FALSE;
00476 }
00477 }
00478
00479 return TRUE;
00480 }
00481
00482
00483 void
00484 __int_xmms_object_unref (xmms_object_t *object)
00485 {
00486 g_return_if_fail (object->ref > 0);
00487 object->ref--;
00488 if (object->ref == 0) {
00489 if (object->destroy_func)
00490 object->destroy_func (object);
00491 xmms_object_cleanup (object);
00492 g_free (object);
00493 }
00494 }
00495
00496 xmms_object_t *
00497 __int_xmms_object_new (gint size, xmms_object_destroy_func_t destfunc)
00498 {
00499 xmms_object_t *ret;
00500
00501 ret = g_malloc0 (size);
00502 ret->destroy_func = destfunc;
00503 ret->id = XMMS_OBJECT_MID;
00504
00505 ret->mutex = g_mutex_new ();
00506
00507
00508
00509
00510
00511
00512 xmms_object_ref (ret);
00513
00514 return ret;
00515 }
00516