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