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, *node = NULL;
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
00223 g_assert (entry);
00224 g_assert (entry->handler);
00225
00226 entry->handler (object, data, entry->userdata);
00227
00228 list2 = g_list_delete_link (list2, list2);
00229 }
00230 }
00231
00232
00233
00234
00235
00236 void
00237 xmms_object_cmd_arg_init (xmms_object_cmd_arg_t *arg)
00238 {
00239 g_return_if_fail (arg);
00240
00241 memset (arg, 0, sizeof (xmms_object_cmd_arg_t));
00242 xmms_error_reset (&arg->error);
00243 }
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256 void
00257 xmms_object_emit_f (xmms_object_t *object, guint32 signalid,
00258 xmmsv_type_t type, ...)
00259 {
00260 va_list ap;
00261 xmmsv_t *arg;
00262
00263 va_start (ap, type);
00264
00265 switch (type) {
00266 case XMMSV_TYPE_NONE:
00267 arg = xmmsv_new_none ();
00268 break;
00269 case XMMSV_TYPE_INT32:
00270 arg = xmmsv_new_int (va_arg (ap, gint32));
00271 break;
00272 case XMMSV_TYPE_STRING:
00273 arg = xmmsv_new_string (va_arg (ap, gchar *));
00274 break;
00275 case XMMSV_TYPE_DICT:
00276 arg = xmms_create_xmmsv_dict (va_arg (ap, GTree *));
00277 break;
00278 case XMMSV_TYPE_END:
00279 default:
00280 XMMS_DBG ("OBJECT: trying to emit value of unsupported type (%d)!", (int)type);
00281 g_assert_not_reached ();
00282 break;
00283 }
00284 va_end (ap);
00285
00286 xmms_object_emit (object, signalid, arg);
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296 xmmsv_unref (arg);
00297 }
00298
00299 static gint
00300 compare_cmd_key (gconstpointer a, gconstpointer b)
00301 {
00302 guint aa = GPOINTER_TO_INT (a);
00303 guint bb = GPOINTER_TO_INT (b);
00304
00305 if (aa < bb)
00306 return -1;
00307 else if (aa > bb)
00308 return 1;
00309 else
00310 return 0;
00311 }
00312
00313
00314
00315
00316
00317
00318
00319
00320 void
00321 xmms_object_cmd_add (xmms_object_t *object, guint cmdid,
00322 const xmms_object_cmd_desc_t *desc)
00323 {
00324 g_return_if_fail (object);
00325 g_return_if_fail (desc);
00326
00327 if (!object->cmds)
00328 object->cmds = g_tree_new (compare_cmd_key);
00329
00330 g_tree_insert (object->cmds, GUINT_TO_POINTER (cmdid),
00331 (gpointer) desc);
00332 }
00333
00334
00335
00336
00337
00338 void
00339 xmms_object_cmd_call (xmms_object_t *object, guint cmdid, xmms_object_cmd_arg_t *arg)
00340 {
00341 xmms_object_cmd_desc_t *desc = NULL;
00342
00343 g_return_if_fail (object);
00344
00345 if (object->cmds) {
00346 desc = g_tree_lookup (object->cmds, GUINT_TO_POINTER (cmdid));
00347
00348 if (desc && desc->func)
00349 desc->func (object, arg);
00350 }
00351 }
00352
00353
00354
00355
00356
00357
00358
00359 static xmmsv_t *
00360 xmms_create_xmmsv_list (GList *list)
00361 {
00362 xmmsv_t *v = xmmsv_new_list ();
00363 g_list_foreach (list, create_xmmsv_list_foreach, (gpointer) v);
00364 return v;
00365 }
00366
00367 xmmsv_t *
00368 xmms_convert_and_kill_list (GList *list)
00369 {
00370 xmmsv_t *v;
00371
00372 v = xmms_create_xmmsv_list (list);
00373 g_list_free (list);
00374
00375 return v;
00376 }
00377
00378
00379
00380
00381
00382
00383 static xmmsv_t *
00384 xmms_create_xmmsv_dict (GTree *dict)
00385 {
00386 xmmsv_t *v = NULL;
00387 if (dict) {
00388 v = xmmsv_new_dict ();
00389 g_tree_foreach (dict, create_xmmsv_dict_foreach, (gpointer) v);
00390 }
00391 return v;
00392 }
00393
00394 xmmsv_t *
00395 xmms_convert_and_kill_dict (GTree *dict)
00396 {
00397 xmmsv_t *v;
00398
00399 v = xmms_create_xmmsv_dict (dict);
00400
00401 if (dict) {
00402 g_tree_destroy (dict);
00403 }
00404
00405 return v;
00406 }
00407
00408 xmmsv_t *
00409 xmms_convert_and_kill_string (gchar *str)
00410 {
00411 xmmsv_t *v = NULL;
00412
00413 if (str) {
00414 v = xmmsv_new_string (str);
00415 g_free (str);
00416 }
00417
00418 return v;
00419 }
00420
00421
00422
00423 static void
00424 create_xmmsv_list_foreach (gpointer data, gpointer userdata)
00425 {
00426 xmmsv_t *v = (xmmsv_t *) data;
00427 xmmsv_t *l = (xmmsv_t *) userdata;
00428
00429 xmmsv_list_append (l, v);
00430
00431
00432
00433
00434 xmmsv_unref (v);
00435 }
00436
00437 static gboolean
00438 create_xmmsv_dict_foreach (gpointer key, gpointer data, gpointer userdata)
00439 {
00440 const char *k = (const char *) key;
00441 xmmsv_t *v = (xmmsv_t *) data;
00442 xmmsv_t *l = (xmmsv_t *) userdata;
00443 xmmsv_dict_set (l, k, v);
00444 return FALSE;
00445 }
00446
00447 int
00448 xmms_bin_to_gstring (xmmsv_t *value, GString **gs)
00449 {
00450 const guchar *str;
00451 guint len;
00452 if (!xmmsv_get_bin (value, &str, &len)) {
00453 return 0;
00454 }
00455 *gs = g_string_new_len (str, len);
00456 return 1;
00457 }
00458
00459 int
00460 dummy_identity (xmmsv_t *value, xmmsv_t **arg)
00461 {
00462 *arg = value;
00463 return 1;
00464 }
00465
00466
00467
00468
00469 gboolean
00470 check_string_list (xmmsv_t *list)
00471 {
00472 xmmsv_t *valstr;
00473 xmmsv_list_iter_t *it;
00474
00475 for (xmmsv_get_list_iter (list, &it);
00476 xmmsv_list_iter_valid (it);
00477 xmmsv_list_iter_next (it)) {
00478 xmmsv_list_iter_entry (it, &valstr);
00479 if (xmmsv_get_type (valstr) != XMMSV_TYPE_STRING) {
00480 return FALSE;
00481 }
00482 }
00483
00484 return TRUE;
00485 }
00486
00487
00488 void
00489 __int_xmms_object_unref (xmms_object_t *object)
00490 {
00491 g_return_if_fail (object->ref > 0);
00492 if (g_atomic_int_dec_and_test (&(object->ref))) {
00493 if (object->destroy_func)
00494 object->destroy_func (object);
00495 xmms_object_cleanup (object);
00496 g_free (object);
00497 }
00498 }
00499
00500 xmms_object_t *
00501 __int_xmms_object_new (gint size, xmms_object_destroy_func_t destfunc)
00502 {
00503 xmms_object_t *ret;
00504
00505 ret = g_malloc0 (size);
00506 ret->destroy_func = destfunc;
00507 ret->id = XMMS_OBJECT_MID;
00508
00509 ret->mutex = g_mutex_new ();
00510
00511
00512
00513
00514
00515
00516 xmms_object_ref (ret);
00517
00518 return ret;
00519 }
00520