XMMS2
playlist.c
Go to the documentation of this file.
1 /* XMMS2 - X Music Multiplexer System
2  * Copyright (C) 2003-2009 XMMS2 Team
3  *
4  * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  */
16 
17 
18 /** @file
19  * Controls playlist
20  */
21 
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <glib.h>
27 #include <math.h>
28 #include <ctype.h>
29 
30 #include "xmmspriv/xmms_playlist.h"
31 #include "xmms/xmms_ipc.h"
32 #include "xmms/xmms_config.h"
33 #include "xmmspriv/xmms_medialib.h"
35 #include "xmms/xmms_log.h"
36 /*
37 #include "xmms/plsplugins.h"
38 #include "xmms/util.h"
39 #include "xmms/signal_xmms.h"
40 #include "xmms/ipc.h"
41 #include "xmms/mediainfo.h"
42 #include "xmms/magic.h"
43 */
44 static void xmms_playlist_destroy (xmms_object_t *object);
45 static void xmms_playlist_client_shuffle (xmms_playlist_t *playlist, const gchar *plname, xmms_error_t *err);
46 static void xmms_playlist_client_clear (xmms_playlist_t *playlist, const gchar *plname, xmms_error_t *err);
47 static void xmms_playlist_client_sort (xmms_playlist_t *playlist, const gchar *plname, xmmsv_t *property, xmms_error_t *err);
48 static GList * xmms_playlist_client_list_entries (xmms_playlist_t *playlist, const gchar *plname, xmms_error_t *err);
49 static gchar *xmms_playlist_client_current_active (xmms_playlist_t *playlist, xmms_error_t *err);
50 static void xmms_playlist_destroy (xmms_object_t *object);
51 
52 static void xmms_playlist_client_add_id (xmms_playlist_t *playlist, const gchar *plname, xmms_medialib_entry_t file, xmms_error_t *error);
53 static void xmms_playlist_client_add_url (xmms_playlist_t *playlist, const gchar *plname, const gchar *nurl, xmms_error_t *err);
54 static void xmms_playlist_client_add_idlist (xmms_playlist_t *playlist, const gchar *plname, xmmsv_coll_t *coll, xmms_error_t *err);
55 static void xmms_playlist_client_add_collection (xmms_playlist_t *playlist, const gchar *plname, xmmsv_coll_t *coll, xmmsv_t *order, xmms_error_t *err);
56 static GTree * xmms_playlist_client_current_pos (xmms_playlist_t *playlist, const gchar *plname, xmms_error_t *err);
57 static gint xmms_playlist_client_set_current_position (xmms_playlist_t *playlist, gint32 pos, xmms_error_t *error);
58 static void xmms_playlist_client_remove (xmms_playlist_t *playlist, const gchar *plname, gint32 pos, xmms_error_t *err);
59 static gboolean xmms_playlist_remove_unlocked (xmms_playlist_t *playlist, const gchar *plname, xmmsv_coll_t *plcoll, guint pos, xmms_error_t *err);
60 static void xmms_playlist_client_move (xmms_playlist_t *playlist, const gchar *plname, gint32 pos, gint32 newpos, xmms_error_t *err);
61 static gint xmms_playlist_client_set_current_position_rel (xmms_playlist_t *playlist, gint32 pos, xmms_error_t *error);
62 static gint xmms_playlist_set_current_position_do (xmms_playlist_t *playlist, guint32 pos, xmms_error_t *err);
63 
64 static void xmms_playlist_client_insert_url (xmms_playlist_t *playlist, const gchar *plname, gint32 pos, const gchar *url, xmms_error_t *error);
65 static void xmms_playlist_client_insert_id (xmms_playlist_t *playlist, const gchar *plname, gint32 pos, xmms_medialib_entry_t file, xmms_error_t *error);
66 static void xmms_playlist_client_insert_collection (xmms_playlist_t *playlist, const gchar *plname, gint32 pos, xmmsv_coll_t *coll, xmmsv_t *order, xmms_error_t *error);
67 static void xmms_playlist_client_radd (xmms_playlist_t *playlist, const gchar *plname, const gchar *path, xmms_error_t *error);
68 static void xmms_playlist_client_rinsert (xmms_playlist_t *playlist, const gchar *plname, gint32 pos, const gchar *path, xmms_error_t *error);
69 
70 static void xmms_playlist_client_load (xmms_playlist_t *, const gchar *, xmms_error_t *);
71 
72 static xmmsv_coll_t *xmms_playlist_get_coll (xmms_playlist_t *playlist, const gchar *plname, xmms_error_t *error);
73 static const gchar *xmms_playlist_canonical_name (xmms_playlist_t *playlist, const gchar *plname);
74 static gint xmms_playlist_coll_get_currpos (xmmsv_coll_t *plcoll);
75 static gint xmms_playlist_coll_get_size (xmmsv_coll_t *plcoll);
76 
77 static void xmms_playlist_update_queue (xmms_playlist_t *playlist, const gchar *plname, xmmsv_coll_t *coll);
78 static void xmms_playlist_update_partyshuffle (xmms_playlist_t *playlist, const gchar *plname, xmmsv_coll_t *coll);
79 
80 static void xmms_playlist_current_pos_msg_send (xmms_playlist_t *playlist, GTree *dict);
81 static GTree * xmms_playlist_current_pos_msg_new (xmms_playlist_t *playlist, guint32 pos, const gchar *plname);
82 
83 XMMS_CMD_DEFINE (load, xmms_playlist_client_load, xmms_playlist_t *, NONE, STRING, NONE);
84 XMMS_CMD_DEFINE3 (insert_url, xmms_playlist_client_insert_url, xmms_playlist_t *, NONE, STRING, INT32, STRING);
85 XMMS_CMD_DEFINE3 (insert_id, xmms_playlist_client_insert_id, xmms_playlist_t *, NONE, STRING, INT32, INT32);
86 XMMS_CMD_DEFINE4 (insert_coll, xmms_playlist_client_insert_collection, xmms_playlist_t *, NONE, STRING, INT32, COLL, LIST);
87 XMMS_CMD_DEFINE (shuffle, xmms_playlist_client_shuffle, xmms_playlist_t *, NONE, STRING, NONE);
88 XMMS_CMD_DEFINE (remove, xmms_playlist_client_remove, xmms_playlist_t *, NONE, STRING, INT32);
89 XMMS_CMD_DEFINE3 (move, xmms_playlist_client_move, xmms_playlist_t *, NONE, STRING, INT32, INT32);
90 XMMS_CMD_DEFINE (add_url, xmms_playlist_client_add_url, xmms_playlist_t *, NONE, STRING, STRING);
91 XMMS_CMD_DEFINE (add_id, xmms_playlist_client_add_id, xmms_playlist_t *, NONE, STRING, INT32);
92 XMMS_CMD_DEFINE (add_idlist, xmms_playlist_client_add_idlist, xmms_playlist_t *, NONE, STRING, COLL);
93 XMMS_CMD_DEFINE3 (add_coll, xmms_playlist_client_add_collection, xmms_playlist_t *, NONE, STRING, COLL, LIST);
94 XMMS_CMD_DEFINE (clear, xmms_playlist_client_clear, xmms_playlist_t *, NONE, STRING, NONE);
95 XMMS_CMD_DEFINE (sort, xmms_playlist_client_sort, xmms_playlist_t *, NONE, STRING, LIST);
96 XMMS_CMD_DEFINE (list_entries, xmms_playlist_client_list_entries, xmms_playlist_t *, LIST, STRING, NONE);
97 XMMS_CMD_DEFINE (current_pos, xmms_playlist_client_current_pos, xmms_playlist_t *, DICT, STRING, NONE);
98 XMMS_CMD_DEFINE (current_active, xmms_playlist_client_current_active, xmms_playlist_t *, STRING, NONE, NONE);
99 XMMS_CMD_DEFINE (set_pos, xmms_playlist_client_set_current_position, xmms_playlist_t *, INT32, INT32, NONE);
100 XMMS_CMD_DEFINE (set_pos_rel, xmms_playlist_client_set_current_position_rel, xmms_playlist_t *, INT32, INT32, NONE);
101 XMMS_CMD_DEFINE (radd, xmms_playlist_client_radd, xmms_playlist_t *, NONE, STRING, STRING);
102 XMMS_CMD_DEFINE3 (rinsert, xmms_playlist_client_rinsert, xmms_playlist_t *, NONE, STRING, INT32, STRING);
103 
104 #define XMMS_PLAYLIST_CHANGED_MSG(type, id, name) xmms_playlist_changed_msg_send (playlist, xmms_playlist_changed_msg_new (playlist, type, id, name))
105 #define XMMS_PLAYLIST_CURRPOS_MSG(pos, name) xmms_playlist_current_pos_msg_send (playlist, xmms_playlist_current_pos_msg_new (playlist, pos, name))
106 
107 
108 /** @defgroup Playlist Playlist
109  * @ingroup XMMSServer
110  * @brief This is the playlist control.
111  *
112  * A playlist is a central thing in the XMMS server, it
113  * tells us what to do after we played the following entry
114  * @{
115  */
116 
117 /** Playlist structure */
118 struct xmms_playlist_St {
119  xmms_object_t object;
120 
121  /* playlists are in the collection DAG */
122  xmms_coll_dag_t *colldag;
123 
124  gboolean repeat_one;
125  gboolean repeat_all;
126 
127  GMutex *mutex;
128 
129  xmms_mediainfo_reader_t *mediainfordr;
130 
131  gboolean update_flag;
132  xmms_medialib_t *medialib;
133 };
134 
135 
136 static void
137 on_playlist_r_all_changed (xmms_object_t *object, xmmsv_t *_data,
138  gpointer udata)
139 {
140  xmms_playlist_t *playlist = udata;
141  gint value;
142 
144 
145  g_mutex_lock (playlist->mutex);
146  playlist->repeat_all = !!value;
147  g_mutex_unlock (playlist->mutex);
148 }
149 
150 static void
151 on_playlist_r_one_changed (xmms_object_t *object, xmmsv_t *_data,
152  gpointer udata)
153 {
154  xmms_playlist_t *playlist = udata;
155  gint value;
156 
158 
159  g_mutex_lock (playlist->mutex);
160  playlist->repeat_one = !!value;
161  g_mutex_unlock (playlist->mutex);
162 }
163 
164 
165 static void
166 on_playlist_updated (xmms_object_t *object, const gchar *plname)
167 {
168  xmmsv_coll_t *plcoll;
169  xmms_playlist_t *playlist = (xmms_playlist_t*)object;
170 
171  /* Already in an update process, quit */
172  if (playlist->update_flag) {
173  return;
174  }
175 
176  plcoll = xmms_playlist_get_coll (playlist, plname, NULL);
177  if (plcoll == NULL) {
178  return;
179  } else {
180  /* Run the update function if appropriate */
181  switch (xmmsv_coll_get_type (plcoll)) {
183  xmms_playlist_update_queue (playlist, plname, plcoll);
184  break;
185 
187  xmms_playlist_update_partyshuffle (playlist, plname, plcoll);
188  break;
189 
190  default:
191  break;
192  }
193  }
194 }
195 
196 static void
197 on_playlist_updated_pos (xmms_object_t *object, xmmsv_t *val, gpointer udata)
198 {
199  XMMS_DBG ("PLAYLIST: updated pos!");
200  on_playlist_updated (object, XMMS_ACTIVE_PLAYLIST);
201 }
202 
203 static void
204 on_playlist_updated_chg (xmms_object_t *object, xmmsv_t *val, gpointer udata)
205 {
206  const gchar *plname = NULL;
207  xmmsv_t *pl_val;
208 
209  XMMS_DBG ("PLAYLIST: updated chg!");
210 
211  xmmsv_dict_get (val, "name", &pl_val);
212  if (pl_val != NULL) {
213  xmmsv_get_string (pl_val, &plname);
214  } else {
215  /* FIXME: occurs? */
216  XMMS_DBG ("PLAYLIST: updated_chg, NULL playlist!");
217  g_assert_not_reached ();
218  }
219 
220  on_playlist_updated (object, plname);
221 }
222 
223 static void
224 xmms_playlist_update_queue (xmms_playlist_t *playlist, const gchar *plname,
225  xmmsv_coll_t *coll)
226 {
227  gint history, currpos;
228 
229  XMMS_DBG ("PLAYLIST: update-queue!");
230 
231  if (!xmms_collection_get_int_attr (coll, "history", &history)) {
232  history = 0;
233  }
234 
235  playlist->update_flag = TRUE;
236  currpos = xmms_playlist_coll_get_currpos (coll);
237  while (currpos > history) {
238  xmms_playlist_remove_unlocked (playlist, plname, coll, 0, NULL);
239  currpos = xmms_playlist_coll_get_currpos (coll);
240  }
241  playlist->update_flag = FALSE;
242 }
243 
244 static void
245 xmms_playlist_update_partyshuffle (xmms_playlist_t *playlist,
246  const gchar *plname, xmmsv_coll_t *coll)
247 {
248  gint history, upcoming, currpos, size;
249  xmmsv_coll_t *src;
250  xmmsv_t *tmp;
251 
252  XMMS_DBG ("PLAYLIST: update-partyshuffle!");
253 
254  if (!xmms_collection_get_int_attr (coll, "history", &history)) {
255  history = 0;
256  }
257 
258  if (!xmms_collection_get_int_attr (coll, "upcoming", &upcoming)) {
260  }
261 
262  playlist->update_flag = TRUE;
263  currpos = xmms_playlist_coll_get_currpos (coll);
264  while (currpos > history) {
265  xmms_playlist_remove_unlocked (playlist, plname, coll, 0, NULL);
266  currpos = xmms_playlist_coll_get_currpos (coll);
267  }
268 
269  if (!xmmsv_list_get (xmmsv_coll_operands_get (coll), 0, &tmp)) {
270  XMMS_DBG ("Cannot find party shuffle operand!");
271  return;
272  }
273  xmmsv_get_coll (tmp, &src);
274 
275  currpos = xmms_playlist_coll_get_currpos (coll);
276  size = xmms_playlist_coll_get_size (coll);
277  while (size < currpos + 1 + upcoming) {
278  xmms_medialib_entry_t randentry;
279  randentry = xmms_collection_get_random_media (playlist->colldag, src);
280  if (randentry == 0) {
281  break; /* No media found in the collection, give up */
282  }
283  /* FIXME: add_collection might yield better perf here. */
284  xmms_playlist_add_entry_unlocked (playlist, plname, coll, randentry, NULL);
285 
286  currpos = xmms_playlist_coll_get_currpos (coll);
287  size = xmms_playlist_coll_get_size (coll);
288  }
289  playlist->update_flag = FALSE;
290 }
291 
292 
293 /**
294  * Initializes a new xmms_playlist_t.
295  */
298 {
299  xmms_playlist_t *ret;
301 
302  ret = xmms_object_new (xmms_playlist_t, xmms_playlist_destroy);
303  ret->mutex = g_mutex_new ();
304 
306 
313 
314  val = xmms_config_property_register ("playlist.repeat_one", "0",
315  on_playlist_r_one_changed, ret);
316  ret->repeat_one = xmms_config_property_get_int (val);
317 
318  val = xmms_config_property_register ("playlist.repeat_all", "0",
319  on_playlist_r_all_changed, ret);
320  ret->repeat_all = xmms_config_property_get_int (val);
321 
322  ret->update_flag = FALSE;
323 
326  on_playlist_updated_chg, ret);
327 
330  on_playlist_updated_pos, ret);
331 
332 
335  XMMS_CMD_FUNC (current_pos));
336 
339  XMMS_CMD_FUNC (current_active));
340 
343  XMMS_CMD_FUNC (load));
344 
347  XMMS_CMD_FUNC (shuffle));
348 
351  XMMS_CMD_FUNC (set_pos));
352 
355  XMMS_CMD_FUNC (set_pos_rel));
356 
359  XMMS_CMD_FUNC (add_url));
360 
363  XMMS_CMD_FUNC (add_id));
364 
367  XMMS_CMD_FUNC (add_idlist));
368 
371  XMMS_CMD_FUNC (add_coll));
372 
375  XMMS_CMD_FUNC (remove));
376 
379  XMMS_CMD_FUNC (move));
380 
383  XMMS_CMD_FUNC (clear));
384 
387  XMMS_CMD_FUNC (sort));
388 
391  XMMS_CMD_FUNC (list_entries));
392 
395  XMMS_CMD_FUNC (insert_url));
396 
399  XMMS_CMD_FUNC (insert_id));
400 
403  XMMS_CMD_FUNC (insert_coll));
404 
407  XMMS_CMD_FUNC (radd));
408 
411  XMMS_CMD_FUNC (rinsert));
412 
413  ret->medialib = xmms_medialib_init (ret);
414  ret->colldag = xmms_collection_init (ret);
415  ret->mediainfordr = xmms_mediainfo_reader_start ();
416 
417  return ret;
418 }
419 
420 static gboolean
421 xmms_playlist_advance_do (xmms_playlist_t *playlist)
422 {
423  gint size, currpos;
424  gboolean ret = TRUE;
425  xmmsv_coll_t *plcoll;
426  char *jumplist;
427  xmms_error_t err;
428  xmms_playlist_t *buffer = playlist;
429  guint newpos;
430 
431  xmms_error_reset (&err);
432 
433  plcoll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, NULL);
434  if (plcoll == NULL) {
435  ret = FALSE;
436  } else if ((size = xmms_playlist_coll_get_size (plcoll)) == 0) {
437  if (xmmsv_coll_attribute_get (plcoll, "jumplist", &jumplist)) {
438  xmms_playlist_client_load (buffer, jumplist, &err);
439  if (xmms_error_isok (&err)) {
440  ret = xmms_playlist_advance_do (playlist);
441  } else {
442  ret = FALSE;
443  }
444  } else {
445  ret = FALSE;
446  }
447  } else if (!playlist->repeat_one) {
448  currpos = xmms_playlist_coll_get_currpos (plcoll);
449  currpos++;
450 
451  if (currpos == size && !playlist->repeat_all &&
452  xmmsv_coll_attribute_get (plcoll, "jumplist", &jumplist)) {
453 
454  xmms_collection_set_int_attr (plcoll, "position", 0);
456 
457  xmms_playlist_client_load (buffer, jumplist, &err);
458  if (xmms_error_isok (&err)) {
459  ret = xmms_playlist_advance_do (playlist);
460  } else {
461  ret = FALSE;
462  }
463  } else {
464  newpos = currpos%size;
465  xmms_collection_set_int_attr (plcoll, "position", newpos);
467  ret = (currpos != size) || playlist->repeat_all;
468  }
469  }
470 
471  return ret;
472 }
473 
474 /**
475  * Go to next song in playlist according to current playlist mode.
476  * xmms_playlist_current_entry is to be used to retrieve the entry.
477  *
478  * @sa xmms_playlist_current_entry
479  *
480  * @returns FALSE if end of playlist is reached, TRUE otherwise.
481  */
482 gboolean
484 {
485  gboolean ret;
486 
487  g_return_val_if_fail (playlist, FALSE);
488 
489  g_mutex_lock (playlist->mutex);
490  ret = xmms_playlist_advance_do (playlist);
491  g_mutex_unlock (playlist->mutex);
492 
493  return ret;
494 }
495 
496 /**
497  * Retrieve the currently active xmms_medialib_entry_t.
498  *
499  */
502 {
503  gint size, currpos;
504  xmmsv_coll_t *plcoll;
505  xmms_medialib_entry_t ent = 0;
506 
507  g_return_val_if_fail (playlist, 0);
508 
509  g_mutex_lock (playlist->mutex);
510 
511  plcoll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, NULL);
512  if (plcoll == NULL) {
513  /* FIXME: What happens? */
514  g_mutex_unlock (playlist->mutex);
515  return 0;
516  }
517 
518  currpos = xmms_playlist_coll_get_currpos (plcoll);
519  size = xmms_playlist_coll_get_size (plcoll);
520 
521  if (currpos == -1 && (size > 0)) {
522  currpos = 0;
523  xmms_collection_set_int_attr (plcoll, "position", currpos);
525  }
526 
527  if (currpos < size) {
528  guint *idlist;
529  idlist = xmmsv_coll_get_idlist (plcoll);
530  ent = idlist[currpos];
531  } else {
532  ent = 0;
533  }
534 
535  g_mutex_unlock (playlist->mutex);
536 
537  return ent;
538 }
539 
540 
541 /**
542  * Retrieve the position of the currently active xmms_medialib_entry_t
543  *
544  */
545 GTree *
546 xmms_playlist_client_current_pos (xmms_playlist_t *playlist, const gchar *plname,
547  xmms_error_t *err)
548 {
549  guint32 pos;
550  xmmsv_coll_t *plcoll;
551  GTree *dict;
552 
553  g_return_val_if_fail (playlist, 0);
554 
555  g_mutex_lock (playlist->mutex);
556 
557  plcoll = xmms_playlist_get_coll (playlist, plname, err);
558  if (plcoll == NULL) {
559  g_mutex_unlock (playlist->mutex);
560  xmms_error_set (err, XMMS_ERROR_INVAL, "no such playlist");
561  return 0;
562  }
563 
564  pos = xmms_playlist_coll_get_currpos (plcoll);
565  if (pos == -1) {
566  xmms_error_set (err, XMMS_ERROR_GENERIC, "no current entry");
567  }
568 
569  g_mutex_unlock (playlist->mutex);
570 
571  dict = xmms_playlist_current_pos_msg_new (playlist, pos, plname);
572 
573  return dict;
574 }
575 
576 /**
577  * Retrieve a copy of the name of the currently active playlist.
578  *
579  */
580 static gchar *
581 xmms_playlist_client_current_active (xmms_playlist_t *playlist, xmms_error_t *err)
582 {
583  gchar *name = NULL;
584  xmmsv_coll_t *active_coll;
585 
586  g_return_val_if_fail (playlist, 0);
587 
588  g_mutex_lock (playlist->mutex);
589 
590  active_coll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, err);
591  if (active_coll != NULL) {
592  const gchar *alias;
593 
594  alias = xmms_collection_find_alias (playlist->colldag,
596  active_coll, XMMS_ACTIVE_PLAYLIST);
597  if (alias == NULL) {
598  xmms_error_set (err, XMMS_ERROR_GENERIC, "active playlist not referenced!");
599  } else {
600  name = g_strdup (alias);
601  }
602  } else {
603  xmms_error_set (err, XMMS_ERROR_GENERIC, "no active playlist");
604  }
605 
606  g_mutex_unlock (playlist->mutex);
607 
608  return name;
609 }
610 
611 
612 static void
613 xmms_playlist_client_load (xmms_playlist_t *playlist, const gchar *name, xmms_error_t *err)
614 {
615  xmmsv_coll_t *plcoll, *active_coll;
616 
617  if (strcmp (name, XMMS_ACTIVE_PLAYLIST) == 0) {
618  xmms_error_set (err, XMMS_ERROR_INVAL, "invalid playlist to load");
619  return;
620  }
621 
622  active_coll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, err);
623  if (active_coll == NULL) {
624  xmms_error_set (err, XMMS_ERROR_GENERIC, "no active playlist");
625  return;
626  }
627 
628  plcoll = xmms_playlist_get_coll (playlist, name, err);
629  if (plcoll == NULL) {
630  xmms_error_set (err, XMMS_ERROR_NOENT, "no such playlist");
631  return;
632  }
633 
634  if (active_coll == plcoll) {
635  XMMS_DBG ("Not loading %s playlist, already active!", name);
636  return;
637  }
638 
639  XMMS_DBG ("Loading new playlist! %s", name);
642 
643  xmms_object_emit_f (XMMS_OBJECT (playlist),
646  name);
647 }
648 
649 static inline void
650 swap_entries (xmmsv_coll_t *coll, gint i, gint j)
651 {
652  guint32 tmp, tmp2;
653 
654  xmmsv_coll_idlist_get_index (coll, i, &tmp);
655  xmmsv_coll_idlist_get_index (coll, j, &tmp2);
656 
657  xmmsv_coll_idlist_set_index (coll, i, tmp2);
658  xmmsv_coll_idlist_set_index (coll, j, tmp);
659 }
660 
661 
662 /**
663  * Shuffle the playlist.
664  *
665  */
666 static void
667 xmms_playlist_client_shuffle (xmms_playlist_t *playlist, const gchar *plname,
668  xmms_error_t *err)
669 {
670  guint j,i;
671  gint len, currpos;
672  xmmsv_coll_t *plcoll;
673 
674  g_return_if_fail (playlist);
675 
676  g_mutex_lock (playlist->mutex);
677 
678  plcoll = xmms_playlist_get_coll (playlist, plname, err);
679  if (plcoll == NULL) {
680  xmms_error_set (err, XMMS_ERROR_NOENT, "no such playlist");
681  g_mutex_unlock (playlist->mutex);
682  return;
683  }
684 
685  currpos = xmms_playlist_coll_get_currpos (plcoll);
686  len = xmms_playlist_coll_get_size (plcoll);
687  if (len > 1) {
688  /* put current at top and exclude from shuffling */
689  if (currpos != -1) {
690  swap_entries (plcoll, 0, currpos);
691  currpos = 0;
692  xmms_collection_set_int_attr (plcoll, "position", currpos);
693  }
694 
695  /* knuth <3 */
696  for (i = currpos + 1; i < len; i++) {
697  j = g_random_int_range (i, len);
698 
699  if (i != j) {
700  swap_entries (plcoll, i, j);
701  }
702  }
703 
704  }
705 
707  XMMS_PLAYLIST_CURRPOS_MSG (currpos, plname);
708 
709  g_mutex_unlock (playlist->mutex);
710 }
711 
712 static gboolean
713 xmms_playlist_remove_unlocked (xmms_playlist_t *playlist, const gchar *plname,
714  xmmsv_coll_t *plcoll, guint pos, xmms_error_t *err)
715 {
716  gint currpos;
717  GTree *dict;
718 
719  g_return_val_if_fail (playlist, FALSE);
720 
721  currpos = xmms_playlist_coll_get_currpos (plcoll);
722 
723  if (!xmmsv_coll_idlist_remove (plcoll, pos)) {
724  if (err) xmms_error_set (err, XMMS_ERROR_NOENT, "Entry was not in list!");
725  return FALSE;
726  }
727 
728  dict = xmms_playlist_changed_msg_new (playlist, XMMS_PLAYLIST_CHANGED_REMOVE, 0, plname);
729  g_tree_insert (dict, (gpointer) "position", xmmsv_new_int (pos));
730  xmms_playlist_changed_msg_send (playlist, dict);
731 
732  /* decrease currentpos if removed entry was before or if it's
733  * the current entry, but only if currentpos is a valid entry.
734  */
735  if (currpos != -1 && pos <= currpos) {
736  currpos--;
737  xmms_collection_set_int_attr (plcoll, "position", currpos);
738  XMMS_PLAYLIST_CURRPOS_MSG (currpos, plname);
739  }
740 
741  return TRUE;
742 }
743 
744 typedef struct {
745  xmms_playlist_t *pls;
746  xmms_medialib_entry_t entry;
747 } playlist_remove_info_t;
748 
749 static void
750 remove_from_playlist (gpointer key, gpointer value, gpointer udata)
751 {
752  playlist_remove_info_t *rminfo = (playlist_remove_info_t *) udata;
753  guint32 i, val;
754  gint size;
755  xmmsv_coll_t *plcoll = (xmmsv_coll_t *) value;
756 
757  size = xmms_playlist_coll_get_size (plcoll);
758  for (i = 0; i < size; i++) {
759  if (xmmsv_coll_idlist_get_index (plcoll, i, &val) && val == rminfo->entry) {
760  XMMS_DBG ("removing entry on pos %d in %s", i, (gchar *)key);
761  xmms_playlist_remove_unlocked (rminfo->pls, (gchar *)key, plcoll, i, NULL);
762  i--; /* reset it */
763  }
764  }
765 }
766 
767 
768 
769 /**
770  * Remove all additions of entry in the playlist
771  *
772  * @param playlist the playlist to remove entries from
773  * @param entry the playlist entry to remove
774  *
775  * @sa xmms_playlist_remove
776  */
777 gboolean
779  xmms_medialib_entry_t entry)
780 {
781  playlist_remove_info_t rminfo;
782  g_return_val_if_fail (playlist, FALSE);
783 
784  g_mutex_lock (playlist->mutex);
785 
786  rminfo.pls = playlist;
787  rminfo.entry = entry;
788 
789  xmms_collection_foreach_in_namespace (playlist->colldag,
791  remove_from_playlist, &rminfo);
792 
793  g_mutex_unlock (playlist->mutex);
794 
795  return TRUE;
796 }
797 
798 /**
799  * Remove an entry from playlist.
800  *
801  */
802 void
803 xmms_playlist_client_remove (xmms_playlist_t *playlist, const gchar *plname,
804  gint32 pos, xmms_error_t *err)
805 {
806  gboolean ret = FALSE;
807  xmmsv_coll_t *plcoll;
808 
809  g_return_if_fail (playlist);
810 
811  g_mutex_lock (playlist->mutex);
812  plcoll = xmms_playlist_get_coll (playlist, plname, err);
813  if (plcoll != NULL) {
814  ret = xmms_playlist_remove_unlocked (playlist, plname, plcoll, pos, err);
815  }
816  g_mutex_unlock (playlist->mutex);
817 }
818 
819 
820 /**
821  * Move an entry in playlist
822  *
823  */
824 static void
825 xmms_playlist_client_move (xmms_playlist_t *playlist, const gchar *plname, gint32 pos,
826  gint32 newpos, xmms_error_t *err)
827 {
828  GTree *dict;
829  guint32 id;
830  gint currpos, size;
831  gint64 ipos, inewpos;
832  xmmsv_coll_t *plcoll;
833 
834  g_return_if_fail (playlist);
835 
836  XMMS_DBG ("Moving %d, to %d", pos, newpos);
837 
838  g_mutex_lock (playlist->mutex);
839 
840  plcoll = xmms_playlist_get_coll (playlist, plname, err);
841  if (plcoll == NULL) {
842  /* FIXME: happens ? */
843  g_mutex_unlock (playlist->mutex);
844  return;
845  }
846 
847  currpos = xmms_playlist_coll_get_currpos (plcoll);
848  size = xmms_playlist_coll_get_size (plcoll);
849 
850  if (size == 0 || newpos > (size - 1)) {
851  xmms_error_set (err, XMMS_ERROR_NOENT,
852  "Cannot move entry outside playlist");
853  g_mutex_unlock (playlist->mutex);
854  return;
855  }
856 
857  if (!xmmsv_coll_idlist_move (plcoll, pos, newpos)) {
858  xmms_error_set (err, XMMS_ERROR_NOENT, "Entry was not in list!");
859  g_mutex_unlock (playlist->mutex);
860  return;
861  }
862 
863  /* Update the current position pointer */
864  ipos = pos;
865  inewpos = newpos;
866  if (inewpos <= currpos && ipos > currpos)
867  currpos++;
868  else if (inewpos >= currpos && ipos < currpos)
869  currpos--;
870  else if (ipos == currpos)
871  currpos = inewpos;
872 
873  xmms_collection_set_int_attr (plcoll, "position", currpos);
874 
875  xmmsv_coll_idlist_get_index (plcoll, newpos, &id);
876 
877  dict = xmms_playlist_changed_msg_new (playlist, XMMS_PLAYLIST_CHANGED_MOVE, id, plname);
878  g_tree_insert (dict, (gpointer) "position", xmmsv_new_int (pos));
879  g_tree_insert (dict, (gpointer) "newposition", xmmsv_new_int (newpos));
880  xmms_playlist_changed_msg_send (playlist, dict);
881 
882  XMMS_PLAYLIST_CURRPOS_MSG (currpos, plname);
883 
884  g_mutex_unlock (playlist->mutex);
885 
886  return;
887 
888 }
889 
890 /**
891  * Insert an entry into the playlist at given position.
892  * Creates a #xmms_medialib_entry for you and insert it
893  * in the list.
894  *
895  * @param playlist the playlist to add it URL to.
896  * @param pos the position where the entry is inserted.
897  * @param url the URL to add.
898  * @param err an #xmms_error_t that should be defined upon error.
899  * @return TRUE on success and FALSE otherwise.
900  *
901  */
902 static void
903 xmms_playlist_client_insert_url (xmms_playlist_t *playlist, const gchar *plname,
904  gint32 pos, const gchar *url, xmms_error_t *err)
905 {
906  xmms_medialib_entry_t entry = 0;
908 
909  entry = xmms_medialib_entry_new_encoded (session, url, err);
910  xmms_medialib_end (session);
911 
912  if (!entry) {
913  return;
914  }
915 
916  xmms_playlist_client_insert_id (playlist, plname, pos, entry, err);
917 }
918 
919 /**
920  * Convenient function for inserting a directory at a given position
921  * in the playlist, It will dive down the URL you feed it and
922  * recursivly insert all files.
923  *
924  * @param playlist the playlist to add it URL to.
925  * @param plname the name of the playlist to modify.
926  * @param pos a position in the playlist.
927  * @param nurl the URL of an directory you want to add
928  * @param err an #xmms_error_t that should be defined upon error.
929  */
930 static void
931 xmms_playlist_client_rinsert (xmms_playlist_t *playlist, const gchar *plname, gint32 pos,
932  const gchar *path, xmms_error_t *err)
933 {
934  /* we actually just call the medialib function, but keep
935  * the ipc method here for not confusing users / developers
936  */
937  xmms_medialib_insert_recursive (playlist->medialib, plname, pos, path, err);
938 }
939 
940 /**
941  * Insert an xmms_medialib_entry to the playlist at given position.
942  *
943  * @param playlist the playlist to add the entry to.
944  * @param pos the position where the entry is inserted.
945  * @param file the #xmms_medialib_entry to add.
946  * @param error Upon error this will be set.
947  * @returns TRUE on success and FALSE otherwise.
948  */
949 static void
950 xmms_playlist_client_insert_id (xmms_playlist_t *playlist, const gchar *plname,
951  gint32 pos, xmms_medialib_entry_t file,
952  xmms_error_t *err)
953 {
954  if (!xmms_medialib_check_id (file)) {
955  xmms_error_set (err, XMMS_ERROR_NOENT,
956  "That is not a valid medialib id!");
957  }
958 
959  xmms_playlist_insert_entry (playlist, plname, pos, file, err);
960 }
961 
962 static void
963 xmms_playlist_client_insert_collection (xmms_playlist_t *playlist, const gchar *plname,
964  gint32 pos, xmmsv_coll_t *coll,
965  xmmsv_t *order, xmms_error_t *err)
966 {
967  GList *res;
968 
969  res = xmms_collection_query_ids (playlist->colldag, coll, 0, 0, order, err);
970 
971  while (res) {
972  xmmsv_t *val = (xmmsv_t*) res->data;
973  gint id;
974  xmmsv_get_int (val, &id);
975  xmms_playlist_client_insert_id (playlist, plname, pos, id, err);
976  xmmsv_unref (val);
977 
978  res = g_list_delete_link (res, res);
979  pos++;
980  }
981 
982 }
983 
984 /**
985  * Insert an entry at a given position in the playlist without
986  * validating it.
987  *
988  * @internal
989  */
990 void
991 xmms_playlist_insert_entry (xmms_playlist_t *playlist, const gchar *plname,
992  guint32 pos, xmms_medialib_entry_t file,
993  xmms_error_t *err)
994 {
995  GTree *dict;
996  gint currpos;
997  gint len;
998  xmmsv_coll_t *plcoll;
999 
1000  g_mutex_lock (playlist->mutex);
1001 
1002  plcoll = xmms_playlist_get_coll (playlist, plname, err);
1003  if (plcoll == NULL) {
1004  /* FIXME: happens ? */
1005  g_mutex_unlock (playlist->mutex);
1006  return;
1007  }
1008 
1009  len = xmms_playlist_coll_get_size (plcoll);
1010  if (pos > len) {
1011  xmms_error_set (err, XMMS_ERROR_GENERIC,
1012  "Could not insert entry outside of playlist!");
1013  g_mutex_unlock (playlist->mutex);
1014  return;
1015  }
1016  xmmsv_coll_idlist_insert (plcoll, pos, file);
1017 
1018  /** propagate the MID ! */
1019  dict = xmms_playlist_changed_msg_new (playlist, XMMS_PLAYLIST_CHANGED_INSERT, file, plname);
1020  g_tree_insert (dict, (gpointer) "position", xmmsv_new_int (pos));
1021  xmms_playlist_changed_msg_send (playlist, dict);
1022 
1023  /** update position once client is familiar with the new item. */
1024  currpos = xmms_playlist_coll_get_currpos (plcoll);
1025  if (pos <= currpos) {
1026  currpos++;
1027  xmms_collection_set_int_attr (plcoll, "position", currpos);
1028  XMMS_PLAYLIST_CURRPOS_MSG (currpos, plname);
1029  }
1030 
1031  g_mutex_unlock (playlist->mutex);
1032 }
1033 
1034 /**
1035  * Convenient function for adding a URL to the playlist,
1036  * Creates a #xmms_medialib_entry_t for you and adds it
1037  * to the list.
1038  *
1039  * @param playlist the playlist to add it URL to.
1040  * @param plname the name of the playlist to modify.
1041  * @param nurl the URL to add
1042  * @param err an #xmms_error_t that should be defined upon error.
1043  * @return TRUE on success and FALSE otherwise.
1044  */
1045 void
1046 xmms_playlist_client_add_url (xmms_playlist_t *playlist, const gchar *plname,
1047  const gchar *nurl, xmms_error_t *err)
1048 {
1049  xmms_medialib_entry_t entry = 0;
1051 
1052  entry = xmms_medialib_entry_new_encoded (session, nurl, err);
1053  xmms_medialib_end (session);
1054 
1055  if (entry) {
1056  xmms_playlist_add_entry (playlist, plname, entry, err);
1057  }
1058 
1059 }
1060 
1061 /**
1062  * Convenient function for adding a directory to the playlist,
1063  * It will dive down the URL you feed it and recursivly add
1064  * all files there.
1065  *
1066  * @param playlist the playlist to add it URL to.
1067  * @param plname the name of the playlist to modify.
1068  * @param nurl the URL of an directory you want to add
1069  * @param err an #xmms_error_t that should be defined upon error.
1070  */
1071 static void
1072 xmms_playlist_client_radd (xmms_playlist_t *playlist, const gchar *plname,
1073  const gchar *path, xmms_error_t *err)
1074 {
1075  /* we actually just call the medialib function, but keep
1076  * the ipc method here for not confusing users / developers
1077  */
1078  xmms_medialib_add_recursive (playlist->medialib, plname, path, err);
1079 }
1080 
1081 /** Adds a xmms_medialib_entry to the playlist.
1082  *
1083  * This will append or prepend the entry according to
1084  * the option.
1085  * This function will wake xmms_playlist_wait.
1086  *
1087  * @param playlist the playlist to add the entry to.
1088  * @param plname the name of the playlist to modify.
1089  * @param file the #xmms_medialib_entry_t to add
1090  * @param err Upon error this will be set.
1091  * @returns TRUE on success
1092  */
1093 
1094 void
1095 xmms_playlist_client_add_id (xmms_playlist_t *playlist, const gchar *plname,
1097 {
1098  if (!xmms_medialib_check_id (file)) {
1099  xmms_error_set (err, XMMS_ERROR_NOENT,
1100  "That is not a valid medialib id!");
1101  return;
1102  }
1103 
1104  xmms_playlist_add_entry (playlist, plname, file, err);
1105 }
1106 
1107 void
1108 xmms_playlist_client_add_idlist (xmms_playlist_t *playlist, const gchar *plname,
1109  xmmsv_coll_t *coll, xmms_error_t *err)
1110 {
1111  uint32_t *idlist;
1112 
1113  for (idlist = xmmsv_coll_get_idlist (coll); *idlist; idlist++) {
1114  if (!xmms_medialib_check_id (*idlist)) {
1115  xmms_error_set (err, XMMS_ERROR_NOENT,
1116  "Idlist contains invalid medialib id!");
1117  return;
1118  }
1119  }
1120 
1121  for (idlist = xmmsv_coll_get_idlist (coll); *idlist; idlist++) {
1122  xmms_playlist_add_entry (playlist, plname, *idlist, err);
1123  }
1124 
1125 }
1126 
1127 void
1128 xmms_playlist_client_add_collection (xmms_playlist_t *playlist, const gchar *plname,
1129  xmmsv_coll_t *coll, xmmsv_t *order,
1130  xmms_error_t *err)
1131 {
1132  GList *res;
1133 
1134  res = xmms_collection_query_ids (playlist->colldag, coll, 0, 0, order, err);
1135 
1136  while (res) {
1137  xmmsv_t *val = (xmmsv_t*) res->data;
1138  gint id;
1139  xmmsv_get_int (val, &id);
1140  xmms_playlist_add_entry (playlist, plname, id, err);
1141  xmmsv_unref (val);
1142 
1143  res = g_list_delete_link (res, res);
1144  }
1145 
1146 }
1147 
1148 /**
1149  * Add an entry to the playlist without validating it.
1150  *
1151  * @internal
1152  */
1153 void
1154 xmms_playlist_add_entry (xmms_playlist_t *playlist, const gchar *plname,
1156 {
1157  xmmsv_coll_t *plcoll;
1158 
1159  g_mutex_lock (playlist->mutex);
1160 
1161  plcoll = xmms_playlist_get_coll (playlist, plname, err);
1162  if (plcoll != NULL) {
1163  xmms_playlist_add_entry_unlocked (playlist, plname, plcoll, file, err);
1164  }
1165 
1166  g_mutex_unlock (playlist->mutex);
1167 
1168 }
1169 
1170 /**
1171  * Add an entry to the playlist without locking the mutex.
1172  */
1173 void
1175  const gchar *plname,
1176  xmmsv_coll_t *plcoll,
1177  xmms_medialib_entry_t file,
1178  xmms_error_t *err)
1179 {
1180  gint prev_size;
1181  GTree *dict;
1182 
1183  prev_size = xmms_playlist_coll_get_size (plcoll);
1184  xmmsv_coll_idlist_append (plcoll, file);
1185 
1186  /** propagate the MID ! */
1187  dict = xmms_playlist_changed_msg_new (playlist, XMMS_PLAYLIST_CHANGED_ADD, file, plname);
1188  g_tree_insert (dict, (gpointer) "position", xmmsv_new_int (prev_size));
1189  xmms_playlist_changed_msg_send (playlist, dict);
1190 }
1191 
1192 /** Clear the playlist */
1193 static void
1194 xmms_playlist_client_clear (xmms_playlist_t *playlist, const gchar *plname,
1195  xmms_error_t *err)
1196 {
1197  xmmsv_coll_t *plcoll;
1198 
1199  g_return_if_fail (playlist);
1200 
1201  g_mutex_lock (playlist->mutex);
1202 
1203  plcoll = xmms_playlist_get_coll (playlist, plname, err);
1204  if (plcoll == NULL) {
1205  g_mutex_unlock (playlist->mutex);
1206  return;
1207  }
1208 
1209  xmmsv_coll_idlist_clear (plcoll);
1210  xmms_collection_set_int_attr (plcoll, "position", -1);
1211 
1213  g_mutex_unlock (playlist->mutex);
1214 
1215 }
1216 
1217 
1218 /** Set the nextentry pointer in the playlist.
1219  *
1220  * This will set the pointer for the next entry to be
1221  * returned by xmms_playlist_advance. This function
1222  * will also wake xmms_playlist_wait
1223  */
1224 
1225 static gint
1226 xmms_playlist_set_current_position_do (xmms_playlist_t *playlist, guint32 pos,
1227  xmms_error_t *err)
1228 {
1229  gint size;
1230  guint mid;
1231  guint *idlist;
1232  xmmsv_coll_t *plcoll;
1233  char *jumplist;
1234 
1235  g_return_val_if_fail (playlist, FALSE);
1236 
1237  plcoll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, err);
1238  if (plcoll == NULL) {
1239  return 0;
1240  }
1241 
1242  size = xmms_playlist_coll_get_size (plcoll);
1243 
1244  if (pos == size &&
1245  xmmsv_coll_attribute_get (plcoll, "jumplist", &jumplist)) {
1246 
1247  xmms_collection_set_int_attr (plcoll, "position", 0);
1249 
1250  xmms_playlist_client_load (playlist, jumplist, err);
1251  if (xmms_error_iserror (err)) {
1252  return 0;
1253  }
1254 
1255  plcoll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, err);
1256  if (plcoll == NULL) {
1257  return 0;
1258  }
1259  } else if (pos < size) {
1260  XMMS_DBG ("newpos! %d", pos);
1261  xmms_collection_set_int_attr (plcoll, "position", pos);
1263  } else {
1264  xmms_error_set (err, XMMS_ERROR_INVAL,
1265  "Can't set pos outside the current playlist!");
1266  return 0;
1267  }
1268 
1269  idlist = xmmsv_coll_get_idlist (plcoll);
1270  mid = idlist[pos];
1271 
1272  return mid;
1273 }
1274 
1275 gint
1276 xmms_playlist_client_set_current_position (xmms_playlist_t *playlist, gint32 pos,
1277  xmms_error_t *err)
1278 {
1279  guint mid;
1280  g_return_val_if_fail (playlist, FALSE);
1281 
1282  g_mutex_lock (playlist->mutex);
1283  mid = xmms_playlist_set_current_position_do (playlist, pos, err);
1284  g_mutex_unlock (playlist->mutex);
1285 
1286  return mid;
1287 }
1288 
1289 static gint
1290 xmms_playlist_client_set_current_position_rel (xmms_playlist_t *playlist, gint32 pos,
1291  xmms_error_t *err)
1292 {
1293  gint currpos, newpos;
1294  guint mid = 0;
1295  xmmsv_coll_t *plcoll;
1296 
1297  g_return_val_if_fail (playlist, FALSE);
1298 
1299  g_mutex_lock (playlist->mutex);
1300 
1301  plcoll = xmms_playlist_get_coll (playlist, XMMS_ACTIVE_PLAYLIST, err);
1302  if (plcoll != NULL) {
1303  currpos = xmms_playlist_coll_get_currpos (plcoll);
1304 
1305  if (playlist->repeat_all) {
1306  newpos = (pos+currpos) % (gint)xmmsv_coll_idlist_get_size (plcoll);
1307 
1308  if (newpos < 0) {
1309  newpos += xmmsv_coll_idlist_get_size (plcoll);
1310  }
1311 
1312  mid = xmms_playlist_set_current_position_do (playlist, newpos, err);
1313  } else {
1314  if (currpos + pos >= 0) {
1315  mid = xmms_playlist_set_current_position_do (playlist,
1316  currpos + pos,
1317  err);
1318  } else {
1319  xmms_error_set (err, XMMS_ERROR_INVAL,
1320  "Can't set pos outside the current playlist!");
1321  }
1322  }
1323  }
1324 
1325  g_mutex_unlock (playlist->mutex);
1326 
1327  return mid;
1328 }
1329 
1330 typedef struct {
1331  guint id;
1332  guint position;
1333  GList *val; /* List of (xmmsv_t *) prop values */
1334  gboolean current;
1335 } sortdata_t;
1336 
1337 
1338 /**
1339  * Sort helper function.
1340  * Performs a case insesitive comparation between two entries.
1341  * We compare each pair of values in the list of prop values.
1342  */
1343 static gint
1344 xmms_playlist_entry_compare (gconstpointer a, gconstpointer b, gpointer user_data)
1345 {
1346  GList *n1, *n2;
1347  xmmsv_t *val1, *val2, *properties, *propval;
1348  xmmsv_list_iter_t *propit;
1349  sortdata_t *data1 = (sortdata_t *) a;
1350  sortdata_t *data2 = (sortdata_t *) b;
1351  int s1, s2, res;
1352  const gchar *propstr, *str1, *str2;
1353 
1354  properties = (xmmsv_t *) user_data;
1355  for (n1 = data1->val, n2 = data2->val, xmmsv_get_list_iter (properties, &propit);
1356  n1 && n2 && xmmsv_list_iter_valid (propit);
1357  n1 = n1->next, n2 = n2->next, xmmsv_list_iter_next (propit)) {
1358 
1359  xmmsv_list_iter_entry (propit, &propval);
1360  xmmsv_get_string (propval, &propstr);
1361  if (propstr[0] == '-') {
1362  val2 = n1->data;
1363  val1 = n2->data;
1364  } else {
1365  val1 = n1->data;
1366  val2 = n2->data;
1367  }
1368 
1369  if (!val1) {
1370  if (!val2)
1371  continue;
1372  else
1373  return -1;
1374  }
1375 
1376  if (!val2) {
1377  return 1;
1378  }
1379 
1380  if (xmmsv_get_type (val1) == XMMSV_TYPE_STRING &&
1381  xmmsv_get_type (val2) == XMMSV_TYPE_STRING) {
1382  xmmsv_get_string (val1, &str1);
1383  xmmsv_get_string (val2, &str2);
1384  res = g_utf8_collate (str1, str2);
1385  /* keep comparing next pair if equal */
1386  if (res == 0)
1387  continue;
1388  else
1389  return res;
1390  }
1391 
1392  if (xmmsv_get_type (val1) == XMMSV_TYPE_INT32 &&
1393  xmmsv_get_type (val2) == XMMSV_TYPE_INT32)
1394  {
1395  xmmsv_get_int (val1, &s1);
1396  xmmsv_get_int (val2, &s2);
1397 
1398  if (s1 < s2)
1399  return -1;
1400  else if (s1 > s2)
1401  return 1;
1402  else
1403  continue; /* equal, compare next pair of properties */
1404  }
1405 
1406  XMMS_DBG ("Types in compare function differ to much");
1407 
1408  return 0;
1409  }
1410 
1411  /* all pairs matched, really equal! */
1412  return 0;
1413 }
1414 
1415 /**
1416  * Unwind helper function.
1417  * Frees the sortdata elements.
1418  */
1419 static void
1420 xmms_playlist_sorted_free (gpointer data, gpointer userdata)
1421 {
1422  GList *n;
1423  sortdata_t *sorted = (sortdata_t *) data;
1424 
1425  for (n = sorted->val; n; n = n->next) {
1426  if (n->data) {
1427  xmmsv_unref (n->data);
1428  }
1429  }
1430  g_list_free (sorted->val);
1431  g_free (sorted);
1432 }
1433 
1434 /**
1435  * Unwind helper function.
1436  * Fills the playlist with the new sorted data.
1437  */
1438 static void
1439 xmms_playlist_sorted_unwind (gpointer data, gpointer userdata)
1440 {
1441  gint size;
1442  sortdata_t *sorted = (sortdata_t *) data;
1443  xmmsv_coll_t *playlist = (xmmsv_coll_t *)userdata;
1444 
1445  xmmsv_coll_idlist_append (playlist, sorted->id);
1446 
1447  if (sorted->current) {
1448  size = xmmsv_coll_idlist_get_size (playlist);
1449  xmms_collection_set_int_attr (playlist, "position", size - 1);
1450  }
1451 
1452  xmms_playlist_sorted_free (sorted, NULL);
1453 }
1454 
1455 /** Sorts the playlist by properties.
1456  *
1457  * This will sort the list.
1458  * @param playlist The playlist to sort.
1459  * @param properties Tells xmms_playlist_sort which properties it
1460  * should use when sorting.
1461  * @param err An #xmms_error_t - needed since xmms_playlist_sort is an ipc
1462  * method handler.
1463  */
1464 
1465 static void
1466 xmms_playlist_client_sort (xmms_playlist_t *playlist, const gchar *plname,
1467  xmmsv_t *properties, xmms_error_t *err)
1468 {
1469  guint32 i;
1470  GList *tmp = NULL, *n;
1471  sortdata_t *data;
1472  const gchar *str;
1473  xmmsv_t *val;
1474  xmms_medialib_session_t *session;
1475  gboolean list_changed = FALSE;
1476  xmmsv_coll_t *plcoll;
1477  gint currpos, size;
1478  xmmsv_t *valstr;
1479  xmmsv_list_iter_t *propit;
1480 
1481  g_return_if_fail (playlist);
1482  g_return_if_fail (properties);
1483 
1484  g_mutex_lock (playlist->mutex);
1485 
1486  plcoll = xmms_playlist_get_coll (playlist, plname, err);
1487  if (plcoll == NULL) {
1488  xmms_error_set (err, XMMS_ERROR_NOENT, "no such playlist!");
1489  g_mutex_unlock (playlist->mutex);
1490  return;
1491  }
1492 
1493  /* check for invalid property strings */
1494  if (!check_string_list (properties)) {
1495  xmms_error_set (err, XMMS_ERROR_NOENT,
1496  "invalid list of properties to sort by!");
1497  g_mutex_unlock (playlist->mutex);
1498  return;
1499  }
1500 
1501  if (xmmsv_list_get_size (properties) < 1) {
1502  xmms_error_set (err, XMMS_ERROR_NOENT,
1503  "empty list of properties to sort by!");
1504  g_mutex_unlock (playlist->mutex);
1505  return;
1506  }
1507 
1508  /* in debug, show the first ordering property */
1509  xmmsv_list_get (properties, 0, &valstr);
1510  xmmsv_get_string (valstr, &str);
1511  XMMS_DBG ("Sorting on %s (and maybe more)", str);
1512 
1513  currpos = xmms_playlist_coll_get_currpos (plcoll);
1514  size = xmms_playlist_coll_get_size (plcoll);
1515 
1516  /* check whether we need to do any sorting at all */
1517  if (size < 2) {
1518  g_mutex_unlock (playlist->mutex);
1519  return;
1520  }
1521 
1522  session = xmms_medialib_begin ();
1523 
1524  xmmsv_get_list_iter (properties, &propit);
1525  for (i = 0; i < size; i++) {
1526  data = g_new (sortdata_t, 1);
1527 
1528  xmmsv_coll_idlist_get_index (plcoll, i, &data->id);
1529  data->position = i;
1530 
1531  /* save the list of values corresponding to the list of sort props */
1532  data->val = NULL;
1533  for (xmmsv_list_iter_first (propit);
1534  xmmsv_list_iter_valid (propit);
1535  xmmsv_list_iter_next (propit)) {
1536 
1537  xmmsv_list_iter_entry (propit, &valstr);
1538  xmmsv_get_string (valstr, &str);
1539  if (str[0] == '-')
1540  str++;
1541 
1543  data->id,
1544  str);
1545 
1546  if (val && xmmsv_get_type (val) == XMMSV_TYPE_STRING) {
1547  gchar *casefold;
1548  /* replace val by casefolded-string (beware of new/free order)*/
1549  xmmsv_get_string (val, &str);
1550  casefold = g_utf8_casefold (str, strlen (str));
1551  xmmsv_unref (val);
1552 
1553  val = xmmsv_new_string (casefold);
1554  g_free (casefold);
1555  }
1556 
1557  data->val = g_list_prepend (data->val, val);
1558  }
1559  data->val = g_list_reverse (data->val);
1560 
1561  data->current = (currpos == i);
1562 
1563  tmp = g_list_prepend (tmp, data);
1564  }
1565 
1566  xmms_medialib_end (session);
1567 
1568  tmp = g_list_reverse (tmp);
1569  tmp = g_list_sort_with_data (tmp, xmms_playlist_entry_compare, properties);
1570 
1571  /* check whether there was any change */
1572  for (i = 0, n = tmp; n; i++, n = g_list_next (n)) {
1573  if (((sortdata_t*)n->data)->position != i) {
1574  list_changed = TRUE;
1575  break;
1576  }
1577  }
1578 
1579  if (!list_changed) {
1580  g_list_foreach (tmp, xmms_playlist_sorted_free, NULL);
1581  g_list_free (tmp);
1582  g_mutex_unlock (playlist->mutex);
1583  return;
1584  }
1585 
1586  xmmsv_coll_idlist_clear (plcoll);
1587  g_list_foreach (tmp, xmms_playlist_sorted_unwind, plcoll);
1588 
1589  g_list_free (tmp);
1590 
1592  XMMS_PLAYLIST_CURRPOS_MSG (currpos, plname);
1593 
1594  g_mutex_unlock (playlist->mutex);
1595 }
1596 
1597 
1598 /** List a playlist */
1599 static GList *
1600 xmms_playlist_client_list_entries (xmms_playlist_t *playlist, const gchar *plname,
1601  xmms_error_t *err)
1602 {
1603  GList *entries = NULL;
1604  xmmsv_coll_t *plcoll;
1605  guint *idlist;
1606  gint i;
1607 
1608  g_return_val_if_fail (playlist, NULL);
1609 
1610  g_mutex_lock (playlist->mutex);
1611 
1612  plcoll = xmms_playlist_get_coll (playlist, plname, err);
1613  if (plcoll == NULL) {
1614  g_mutex_unlock (playlist->mutex);
1615  return NULL;
1616  }
1617 
1618  idlist = xmmsv_coll_get_idlist (plcoll);
1619 
1620  for (i = 0; idlist[i] != 0; i++) {
1621  entries = g_list_prepend (entries, xmmsv_new_int (idlist[i]));
1622  }
1623 
1624  g_mutex_unlock (playlist->mutex);
1625 
1626  entries = g_list_reverse (entries);
1627 
1628  return entries;
1629 }
1630 
1631 /** returns pointer to mediainfo reader. */
1634 {
1635  g_return_val_if_fail (playlist, NULL);
1636 
1637  return playlist->mediainfordr;
1638 }
1639 
1640 /** @} */
1641 
1642 /** Free the playlist and other memory in the xmms_playlist_t
1643  *
1644  * This will free all entries in the list!
1645  */
1646 
1647 static void
1648 xmms_playlist_destroy (xmms_object_t *object)
1649 {
1651  xmms_playlist_t *playlist = (xmms_playlist_t *)object;
1652 
1653  g_return_if_fail (playlist);
1654 
1655  g_mutex_free (playlist->mutex);
1656 
1657  val = xmms_config_lookup ("playlist.repeat_one");
1658  xmms_config_property_callback_remove (val, on_playlist_r_one_changed, playlist);
1659  val = xmms_config_lookup ("playlist.repeat_all");
1660  xmms_config_property_callback_remove (val, on_playlist_r_all_changed, playlist);
1661 
1662  xmms_object_unref (playlist->colldag);
1663  xmms_object_unref (playlist->mediainfordr);
1664 
1668 }
1669 
1670 
1671 static xmmsv_coll_t *
1672 xmms_playlist_get_coll (xmms_playlist_t *playlist, const gchar *plname,
1673  xmms_error_t *error)
1674 {
1675  xmmsv_coll_t *coll;
1676  coll = xmms_collection_get_pointer (playlist->colldag, plname,
1678 
1679  if (coll == NULL && error != NULL) {
1680  xmms_error_set (error, XMMS_ERROR_INVAL, "invalid playlist name");
1681  }
1682 
1683  return coll;
1684 }
1685 
1686 /**
1687  * Retrieve the canonical name of a playlist. Assumes the playlist
1688  * name is valid.
1689  */
1690 static const gchar *
1691 xmms_playlist_canonical_name (xmms_playlist_t *playlist, const gchar *plname)
1692 {
1693  const gchar *fullname;
1694 
1695  if (strcmp (plname, XMMS_ACTIVE_PLAYLIST) == 0) {
1696  xmmsv_coll_t *coll;
1697  coll = xmms_collection_get_pointer (playlist->colldag, plname,
1699  fullname = xmms_collection_find_alias (playlist->colldag,
1701  coll, plname);
1702  } else {
1703  fullname = plname;
1704  }
1705 
1706  return fullname;
1707 }
1708 
1709 /** Get the current position in the given playlist (set to -1 if absent). */
1710 static gint
1711 xmms_playlist_coll_get_currpos (xmmsv_coll_t *plcoll)
1712 {
1713  gint currpos;
1714 
1715  /* If absent, set to -1 and save it */
1716  if (!xmms_collection_get_int_attr (plcoll, "position", &currpos)) {
1717  currpos = -1;
1718  xmms_collection_set_int_attr (plcoll, "position", currpos);
1719  }
1720 
1721  return currpos;
1722 }
1723 
1724 /** Get the size of the given playlist (compute and update it if absent). */
1725 static gint
1726 xmms_playlist_coll_get_size (xmmsv_coll_t *plcoll)
1727 {
1728  return xmmsv_coll_idlist_get_size (plcoll);
1729 }
1730 
1731 
1732 GTree *
1735  guint32 id, const gchar *plname)
1736 {
1737  GTree *dict;
1738  const gchar *tmp;
1739 
1740  dict = g_tree_new_full ((GCompareDataFunc) strcmp, NULL,
1741  NULL, (GDestroyNotify) xmmsv_unref);
1742 
1743  g_tree_insert (dict, (gpointer) "type", xmmsv_new_int (type));
1744 
1745  if (id) {
1746  g_tree_insert (dict, (gpointer) "id", xmmsv_new_int (id));
1747  }
1748 
1749  tmp = xmms_playlist_canonical_name (playlist, plname);
1750  g_tree_insert (dict, (gpointer) "name", xmmsv_new_string (tmp));
1751 
1752  return dict;
1753 }
1754 
1755 GTree *
1756 xmms_playlist_current_pos_msg_new (xmms_playlist_t *playlist,
1757  guint32 pos, const gchar *plname)
1758 {
1759  GTree *dict;
1760  const gchar *tmp;
1761 
1762  dict = g_tree_new_full ((GCompareDataFunc) strcmp, NULL,
1763  NULL, (GDestroyNotify) xmmsv_unref);
1764 
1765  g_tree_insert (dict, (gpointer) "position", xmmsv_new_int (pos));
1766 
1767  tmp = xmms_playlist_canonical_name (playlist, plname);
1768  g_tree_insert (dict, (gpointer) "name", xmmsv_new_string (tmp));
1769 
1770  return dict;
1771 }
1772 
1773 void
1775 {
1776  xmmsv_t *type_val;
1777  xmmsv_t *pl_val;
1778  gint type;
1779  const gchar *plname;
1780 
1781  g_return_if_fail (playlist);
1782  g_return_if_fail (dict);
1783 
1784  /* If local playlist change, trigger a COLL_CHANGED signal */
1785  type_val = g_tree_lookup (dict, "type");
1786  pl_val = g_tree_lookup (dict, "name");
1787  if (type_val != NULL && xmmsv_get_int (type_val, &type) &&
1788  type != XMMS_PLAYLIST_CHANGED_UPDATE &&
1789  pl_val != NULL && xmmsv_get_string (pl_val, &plname)) {
1790  XMMS_COLLECTION_PLAYLIST_CHANGED_MSG (playlist->colldag, plname);
1791  }
1792 
1793  xmms_object_emit_f (XMMS_OBJECT (playlist),
1796  dict);
1797 
1798  g_tree_destroy (dict);
1799 }
1800 
1801 static void
1802 xmms_playlist_current_pos_msg_send (xmms_playlist_t *playlist,
1803  GTree *dict)
1804 {
1805  g_return_if_fail (playlist);
1806 
1807  g_return_if_fail (dict);
1808 
1809  xmms_object_emit_f (XMMS_OBJECT (playlist),
1812  dict);
1813 
1814  g_tree_destroy (dict);
1815 }
struct xmmsv_St xmmsv_t
Definition: xmmsv.h:51
#define XMMS_CMD_FUNC(cmdid)
Definition: xmms_object.h:181
#define xmms_error_isok(e)
Definition: xmms_error.h:58
xmms_mediainfo_reader_t * xmms_mediainfo_reader_start(void)
Start a new mediainfo reader thread.
Definition: mediainfo.c:65
G_BEGIN_DECLS typedef gint32 xmms_medialib_entry_t
Definition: xmms_medialib.h:86
int xmmsv_coll_idlist_append(xmmsv_coll_t *coll, unsigned int id)
Append a value to the idlist.
Definition: coll.c:275
struct xmms_mediainfo_reader_St xmms_mediainfo_reader_t
#define XMMS_OBJECT(p)
Definition: xmms_object.h:84
xmms_medialib_entry_t xmms_collection_get_random_media(xmms_coll_dag_t *dag, xmmsv_coll_t *source)
Get a random media entry from the given collection.
Definition: collection.c:1032
#define XMMS_COLLECTION_PLAYLIST_CHANGED_MSG(dag, name)
void xmmsv_unref(xmmsv_t *val)
Decreases the references for the xmmsv_t When the number of references reaches 0 it will be freed...
Definition: value.c:301
void xmms_medialib_add_recursive(xmms_medialib_t *medialib, const gchar *playlist, const gchar *path, xmms_error_t *error)
Definition: medialib.c:904
#define xmms_object_unref(obj)
Definition: xmms_object.h:193
int xmmsv_coll_attribute_get(xmmsv_coll_t *coll, const char *key, char **value)
Retrieve the value of the attribute of the given collection.
Definition: coll.c:550
void xmms_medialib_insert_recursive(xmms_medialib_t *medialib, const gchar *playlist, gint32 pos, const gchar *path, xmms_error_t *error)
Definition: medialib.c:917
int xmmsv_list_get(xmmsv_t *listv, int pos, xmmsv_t **val)
Get the element at the given position in the list xmmsv_t.
Definition: value.c:1210
int xmmsv_get_list_iter(const xmmsv_t *val, xmmsv_list_iter_t **it)
Retrieves a list iterator from a list xmmsv_t.
Definition: value.c:918
#define xmms_error_iserror(e)
Definition: xmms_error.h:57
void xmms_config_property_callback_remove(xmms_config_property_t *prop, xmms_object_handler_t cb, gpointer userdata)
Remove a callback from a config property.
Definition: config.c:310
void xmms_object_cmd_add(xmms_object_t *object, guint cmdid, const xmms_object_cmd_desc_t *desc)
Add a command that could be called from the client API to a object.
Definition: object.c:321
xmms_config_property_t * xmms_config_lookup(const gchar *path)
Look up a config key from the global config.
Definition: config.c:174
int xmmsv_list_iter_entry(xmmsv_list_iter_t *it, xmmsv_t **val)
Get the element currently pointed at by the iterator.
Definition: value.c:1487
void xmms_ipc_broadcast_register(xmms_object_t *object, xmms_ipc_signals_t signalid)
Register a broadcast signal.
Definition: ipc.c:694
void xmms_playlist_add_entry(xmms_playlist_t *playlist, const gchar *plname, xmms_medialib_entry_t file, xmms_error_t *err)
Add an entry to the playlist without validating it.
Definition: playlist.c:1154
xmmsv_t * xmmsv_new_string(const char *s)
Allocates a new string xmmsv_t.
Definition: value.c:178
void xmmsv_list_iter_first(xmmsv_list_iter_t *it)
Rewind the iterator to the start of the list.
Definition: value.c:1515
xmms_playlist_changed_actions_t
int xmmsv_get_int(const xmmsv_t *val, int32_t *r)
Retrieves a signed integer from the value.
Definition: value.c:815
xmmsv_coll_t * xmms_collection_get_pointer(xmms_coll_dag_t *dag, const gchar *collname, guint nsid)
Find the collection structure corresponding to the given name in the given namespace.
Definition: collection.c:927
gboolean check_string_list(xmmsv_t *list)
Checks that the list only contains string values.
Definition: object.c:470
int xmmsv_coll_idlist_set_index(xmmsv_coll_t *coll, unsigned int index, uint32_t val)
Sets the value at the given position in the idlist.
Definition: coll.c:430
gboolean xmms_playlist_advance(xmms_playlist_t *playlist)
Go to next song in playlist according to current playlist mode.
Definition: playlist.c:483
struct xmmsv_St * xmmsv_coll_operands_get(xmmsv_coll_t *coll)
Definition: coll.c:489
size_t xmmsv_coll_idlist_get_size(xmmsv_coll_t *coll)
Get the size of the idlist.
Definition: coll.c:449
gboolean xmms_collection_get_int_attr(xmmsv_coll_t *coll, const gchar *attrname, gint *val)
Extract an attribute from a collection as an integer.
Definition: collection.c:952
gint xmms_config_property_get_int(const xmms_config_property_t *prop)
Return the value of a config property as an int.
Definition: config.c:258
int xmmsv_dict_get(xmmsv_t *dictv, const char *key, xmmsv_t **val)
Get the element corresponding to the given key in the dict xmmsv_t (if it exists).
Definition: value.c:1709
GTree * xmms_playlist_changed_msg_new(xmms_playlist_t *playlist, xmms_playlist_changed_actions_t type, guint32 id, const gchar *plname)
Definition: playlist.c:1733
XMMS_CMD_DEFINE3(insert_url, xmms_playlist_client_insert_url, xmms_playlist_t *, NONE, STRING, INT32, STRING)
#define XMMS_DEFAULT_PARTYSHUFFLE_UPCOMING
Definition: xmms_playlist.h:37
XMMS_CMD_DEFINE(load, xmms_playlist_client_load, xmms_playlist_t *, NONE, STRING, NONE)
GList * xmms_collection_query_ids(xmms_coll_dag_t *dag, xmmsv_coll_t *coll, gint32 lim_start, gint32 lim_len, xmmsv_t *order, xmms_error_t *err)
Find the ids of the media matched by a collection.
Definition: collection.c:785
int xmmsv_get_coll(const xmmsv_t *val, xmmsv_coll_t **coll)
Retrieves a collection from the value.
Definition: value.c:875
xmmsv_t * xmms_medialib_entry_property_get_value(xmms_medialib_session_t *session, xmms_medialib_entry_t entry, const gchar *property)
Definition: medialib.c:529
void xmms_object_emit_f(xmms_object_t *object, guint32 signalid, xmmsv_type_t type,...)
Emits a signal on the current object.
Definition: object.c:257
xmms_medialib_t * xmms_medialib_init(xmms_playlist_t *playlist)
Initialize the medialib and open the database file.
Definition: medialib.c:327
xmms_medialib_entry_t xmms_medialib_entry_new_encoded(xmms_medialib_session_t *session, const char *url, xmms_error_t *error)
Definition: medialib.c:996
struct xmmsv_coll_St xmmsv_coll_t
Definition: xmmsv_coll.h:28
int xmmsv_list_get_size(xmmsv_t *listv)
Return the size of the list.
Definition: value.c:1395
gboolean xmms_medialib_check_id(xmms_medialib_entry_t entry)
Definition: medialib.c:1444
struct xmms_playlist_St xmms_playlist_t
Definition: xmms_playlist.h:41
#define XMMS_PLAYLIST_CURRPOS_MSG(pos, name)
Definition: playlist.c:105
void xmms_playlist_insert_entry(xmms_playlist_t *playlist, const gchar *plname, guint32 pos, xmms_medialib_entry_t file, xmms_error_t *err)
Insert an entry at a given position in the playlist without validating it.
Definition: playlist.c:991
void xmmsv_list_iter_next(xmmsv_list_iter_t *it)
Advance the iterator to the next element in the list.
Definition: value.c:1545
gboolean xmms_playlist_remove_by_entry(xmms_playlist_t *playlist, xmms_medialib_entry_t entry)
Remove all additions of entry in the playlist.
Definition: playlist.c:778
xmms_mediainfo_reader_t * xmms_playlist_mediainfo_reader_get(xmms_playlist_t *playlist)
returns pointer to mediainfo reader.
Definition: playlist.c:1633
void xmms_collection_update_pointer(xmms_coll_dag_t *dag, const gchar *name, guint nsid, xmmsv_coll_t *newtarget)
Update a reference to point to a new collection.
Definition: collection.c:903
xmmsv_type_t xmmsv_get_type(const xmmsv_t *val)
Get the type of the value.
Definition: value.c:384
xmmsv_t * xmmsv_new_int(int32_t i)
Allocates a new integer xmmsv_t.
Definition: value.c:159
int xmmsv_coll_idlist_get_index(xmmsv_coll_t *coll, unsigned int index, uint32_t *val)
Retrieves the value at the given position in the idlist.
Definition: coll.c:409
void xmms_ipc_object_unregister(xmms_ipc_objects_t objectid)
Remove a object from the IPC core.
Definition: ipc.c:769
gboolean xmms_collection_set_int_attr(xmmsv_coll_t *coll, const gchar *attrname, gint newval)
Set the attribute of a collection as an integer.
Definition: collection.c:980
void xmms_playlist_add_entry_unlocked(xmms_playlist_t *playlist, const gchar *plname, xmmsv_coll_t *plcoll, xmms_medialib_entry_t file, xmms_error_t *err)
Add an entry to the playlist without locking the mutex.
Definition: playlist.c:1174
#define XMMS_ACTIVE_PLAYLIST
const gchar * xmms_collection_find_alias(xmms_coll_dag_t *dag, guint nsid, xmmsv_coll_t *value, const gchar *key)
Reverse-search the list of collections in the given namespace to find the first pair whose value matc...
Definition: collection.c:1009
struct xmms_medialib_session_St xmms_medialib_session_t
Definition: xmms_medialib.h:87
XMMS_CMD_DEFINE4(insert_coll, xmms_playlist_client_insert_collection, xmms_playlist_t *, NONE, STRING, INT32, COLL, LIST)
void xmms_playlist_changed_msg_send(xmms_playlist_t *playlist, GTree *dict)
Definition: playlist.c:1774
#define XMMS_DBG(fmt,...)
Definition: xmms_log.h:32
xmms_playlist_t * xmms_playlist_init(void)
Initializes a new xmms_playlist_t.
Definition: playlist.c:297
#define xmms_medialib_begin_write()
#define xmms_medialib_begin()
struct xmms_medialib_St xmms_medialib_t
Definition: xmms_medialib.h:27
void xmms_object_connect(xmms_object_t *object, guint32 signalid, xmms_object_handler_t handler, gpointer userdata)
Connect to a signal that is emitted by this object.
Definition: object.c:116
void xmms_ipc_broadcast_unregister(xmms_ipc_signals_t signalid)
Unregister a broadcast signal.
Definition: ipc.c:709
int xmmsv_coll_idlist_insert(xmmsv_coll_t *coll, unsigned int index, unsigned int id)
Insert a value at a given position in the idlist.
Definition: coll.c:290
xmms_coll_dag_t * xmms_collection_init(xmms_playlist_t *playlist)
Initializes a new xmms_coll_dag_t.
Definition: collection.c:226
int xmmsv_get_string(const xmmsv_t *val, const char **r)
Retrieves a string from the value.
Definition: value.c:855
void xmms_collection_foreach_in_namespace(xmms_coll_dag_t *dag, guint nsid, GHFunc f, void *udata)
Apply a function to all the collections in a given namespace.
Definition: collection.c:1429
#define xmms_object_new(objtype, destroyfunc)
Definition: xmms_object.h:199
G_BEGIN_DECLS struct xmms_error_St xmms_error_t
xmms_config_property_t * xmms_config_property_register(const gchar *path, const gchar *default_value, xmms_object_handler_t cb, gpointer userdata)
Register a new config property.
Definition: config.c:337
struct xmms_config_property_St xmms_config_property_t
Definition: xmms_config.h:26
int xmmsv_coll_idlist_clear(xmmsv_coll_t *coll)
Empties the idlist.
Definition: coll.c:390
uint32_t * xmmsv_coll_get_idlist(xmmsv_coll_t *coll)
Return the list of ids stored in the collection.
Definition: coll.c:481
void xmms_ipc_object_register(xmms_ipc_objects_t objectid, xmms_object_t *object)
Register a object to the IPC core.
Definition: ipc.c:758
xmms_medialib_entry_t xmms_playlist_current_entry(xmms_playlist_t *playlist)
Retrieve the currently active xmms_medialib_entry_t.
Definition: playlist.c:501
xmmsv_coll_type_t xmmsv_coll_get_type(xmmsv_coll_t *coll)
Return the type of the collection.
Definition: coll.c:464
void xmms_medialib_end(xmms_medialib_session_t *session)
Definition: medialib.c:470
int xmmsv_coll_idlist_move(xmmsv_coll_t *coll, unsigned int index, unsigned int newindex)
Move a value of the idlist to a new position.
Definition: coll.c:325
struct xmmsv_list_iter_St xmmsv_list_iter_t
Definition: xmmsv.h:53
int xmmsv_list_iter_valid(xmmsv_list_iter_t *it)
Check whether the iterator is valid and points to a valid element.
Definition: value.c:1504
struct xmms_coll_dag_St xmms_coll_dag_t
int xmmsv_coll_idlist_remove(xmmsv_coll_t *coll, unsigned int index)
Remove the value at a given index from the idlist.
Definition: coll.c:359
#define XMMS_PLAYLIST_CHANGED_MSG(type, id, name)
Definition: playlist.c:104