Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
dbus.c
Go to the documentation of this file.
1 /*
2  * Audacious: A cross-platform multimedia player
3  * Copyright (c) 2007 Ben Tucker
4  * Copyright 2009-2011 Audacious development team
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; under version 3 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses>.
17  *
18  * The Audacious team does not consider modular code linking to
19  * Audacious or using our public API to be a derived work.
20  */
21 
22 #include "config.h"
23 
24 #include <glib.h>
25 #include <string.h>
26 
27 #include <dbus/dbus.h>
28 #include <dbus/dbus-glib.h>
29 #include <dbus/dbus-glib-bindings.h>
30 #include <dbus/dbus-glib-lowlevel.h>
31 #include "dbus.h"
32 #include "dbus-service.h"
33 #include "dbus-server-bindings.h"
34 
35 #include <math.h>
36 
37 #include <libaudcore/hook.h>
38 
39 #include "debug.h"
40 #include "drct.h"
41 #include "playlist.h"
42 #include "interface.h"
43 #include "misc.h"
44 
45 static DBusGConnection *dbus_conn = NULL;
46 static unsigned int signals[LAST_SIG] = { 0 };
47 static unsigned int tracklist_signals[LAST_TRACKLIST_SIG] = { 0 };
48 
51 
52 G_DEFINE_TYPE (RemoteObject, audacious_rc, G_TYPE_OBJECT)
53 G_DEFINE_TYPE (MprisRoot, mpris_root, G_TYPE_OBJECT)
54 G_DEFINE_TYPE (MprisPlayer, mpris_player, G_TYPE_OBJECT)
55 G_DEFINE_TYPE (MprisTrackList, mpris_tracklist, G_TYPE_OBJECT)
56 
57 #define DBUS_TYPE_G_STRING_VALUE_HASHTABLE (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE))
58 
59 static void mpris_playlist_update_hook(gpointer unused, MprisTrackList *obj);
60 
62 {
63 }
64 
66 {
67 }
68 
70 {
71  signals[CAPS_CHANGE_SIG] = g_signal_new("caps_change", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
73  g_signal_new("track_change",
74  G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0, NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, DBUS_TYPE_G_STRING_VALUE_HASHTABLE);
75 
76  GType status_type = dbus_g_type_get_struct ("GValueArray", G_TYPE_INT,
77  G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INVALID);
79  g_signal_new ("status_change", G_OBJECT_CLASS_TYPE (klass),
80  G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0, NULL, NULL,
81  g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, status_type);
82 }
83 
85 {
86  tracklist_signals[TRACKLIST_CHANGE_SIG] = g_signal_new("track_list_change", G_OBJECT_CLASS_TYPE(klass),
87  G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
88 }
89 
91 {
92  GError *error = NULL;
93  DBusGProxy *driver_proxy;
94  unsigned int request_ret;
95 
96  AUDDBG ("Registering remote D-Bus interfaces.\n");
97 
98  dbus_g_object_type_install_info(audacious_rc_get_type(), &dbus_glib_audacious_rc_object_info);
99 
100  // Register DBUS path
101  dbus_g_connection_register_g_object(dbus_conn, AUDACIOUS_DBUS_PATH, G_OBJECT(object));
102 
103  // Register the service name, the constants here are defined in
104  // dbus-glib-bindings.h
105  driver_proxy = dbus_g_proxy_new_for_name(dbus_conn, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
106 
107  if (!org_freedesktop_DBus_request_name(driver_proxy, AUDACIOUS_DBUS_SERVICE, 0, &request_ret, &error))
108  {
109  g_warning("Unable to register service: %s", error->message);
110  g_error_free(error);
111  }
112 
113  if (!org_freedesktop_DBus_request_name(driver_proxy, AUDACIOUS_DBUS_SERVICE_MPRIS, 0, &request_ret, &error))
114  {
115  g_warning("Unable to register service: %s", error->message);
116  g_error_free(error);
117  }
118 
119  g_object_unref(driver_proxy);
120 }
121 
122 void mpris_root_init(MprisRoot * object)
123 {
124  dbus_g_object_type_install_info(mpris_root_get_type(), &dbus_glib_mpris_root_object_info);
125 
126  // Register DBUS path
127  dbus_g_connection_register_g_object(dbus_conn, AUDACIOUS_DBUS_PATH_MPRIS_ROOT, G_OBJECT(object));
128 }
129 
130 void mpris_player_init(MprisPlayer * object)
131 {
132  dbus_g_object_type_install_info(mpris_player_get_type(), &dbus_glib_mpris_player_object_info);
133 
134  // Register DBUS path
135  dbus_g_connection_register_g_object(dbus_conn, AUDACIOUS_DBUS_PATH_MPRIS_PLAYER, G_OBJECT(object));
136 
137  // Add signals
138  DBusGProxy *proxy = object->proxy;
139  if (proxy != NULL)
140  {
141  dbus_g_proxy_add_signal (proxy, "StatusChange", dbus_g_type_get_struct
142  ("GValueArray", G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT,
143  G_TYPE_INVALID), G_TYPE_INVALID);
144  dbus_g_proxy_add_signal (proxy, "CapsChange", G_TYPE_INT, G_TYPE_INVALID);
145  dbus_g_proxy_add_signal(proxy, "TrackChange", DBUS_TYPE_G_STRING_VALUE_HASHTABLE, G_TYPE_INVALID);
146  }
147  else
148  {
149  /* XXX / FIXME: Why does this happen? -- ccr */
150  AUDDBG ("object->proxy == NULL; not adding some signals.\n");
151  }
152 }
153 
154 void mpris_tracklist_init(MprisTrackList * object)
155 {
156  dbus_g_object_type_install_info(mpris_tracklist_get_type(), &dbus_glib_mpris_tracklist_object_info);
157 
158  // Register DBUS path
159  dbus_g_connection_register_g_object(dbus_conn, AUDACIOUS_DBUS_PATH_MPRIS_TRACKLIST, G_OBJECT(object));
160 
161  // Add signals
162  DBusGProxy *proxy = object->proxy;
163  if (proxy != NULL)
164  {
165  dbus_g_proxy_add_signal(proxy, "TrackListChange", G_TYPE_INT, G_TYPE_INVALID);
166  }
167  else
168  {
169  /* XXX / FIXME: Why does this happen? -- ccr */
170  AUDDBG ("object->proxy == NULL, not adding some signals.\n");
171  }
172 }
173 
174 void init_dbus()
175 {
176  GError *error = NULL;
177  DBusConnection *local_conn;
178 
179  AUDDBG ("Trying to initialize D-Bus.\n");
180  dbus_conn = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
181  if (dbus_conn == NULL)
182  {
183  g_warning("Unable to connect to dbus: %s", error->message);
184  g_error_free(error);
185  return;
186  }
187 
188  g_type_init();
189  g_object_new(audacious_rc_get_type(), NULL);
190  g_object_new(mpris_root_get_type(), NULL);
191  mpris = g_object_new(mpris_player_get_type(), NULL);
192  mpris_tracklist = g_object_new(mpris_tracklist_get_type(), NULL);
193 
194  local_conn = dbus_g_connection_get_connection(dbus_conn);
195  dbus_connection_set_exit_on_disconnect(local_conn, FALSE);
196 
197  hook_associate ("playlist update",
198  (HookFunction) mpris_playlist_update_hook, mpris_tracklist);
199 }
200 
201 void cleanup_dbus (void)
202 {
204 }
205 
206 static GValue *tuple_value_to_gvalue(const Tuple * tuple, const char * key)
207 {
208  GValue *val;
209  TupleValueType type = tuple_get_value_type (tuple, -1, key);
210 
211  if (type == TUPLE_STRING)
212  {
213  val = g_new0(GValue, 1);
214  g_value_init(val, G_TYPE_STRING);
215  char * str = tuple_get_str (tuple, -1, key);
216  g_value_set_string (val, str);
217  str_unref (str);
218  return val;
219  }
220  else if (type == TUPLE_INT)
221  {
222  val = g_new0(GValue, 1);
223  g_value_init(val, G_TYPE_INT);
224  int x = tuple_get_int (tuple, -1, key);
225  g_value_set_int (val, x);
226  return val;
227  }
228  return NULL;
229 }
230 
239 static void tuple_insert_to_hash_full(GHashTable * md, const Tuple * tuple,
240  const char * tuple_key, const char *key)
241 {
242  GValue *value = tuple_value_to_gvalue(tuple, tuple_key);
243  if (value != NULL)
244  g_hash_table_insert (md, (void *) key, value);
245 }
246 
247 static void tuple_insert_to_hash(GHashTable * md, const Tuple * tuple,
248  const char *key)
249 {
250  tuple_insert_to_hash_full(md, tuple, key, key);
251 }
252 
253 static void remove_metadata_value(gpointer value)
254 {
255  g_value_unset((GValue *) value);
256  g_free((GValue *) value);
257 }
258 
259 static GHashTable *make_mpris_metadata(const char * filename, const Tuple * tuple)
260 {
261  GHashTable *md = NULL;
262  gpointer value;
263 
264  md = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, remove_metadata_value);
265 
266  value = g_malloc(sizeof(GValue));
267  memset(value, 0, sizeof(GValue));
268  g_value_init(value, G_TYPE_STRING);
269  g_value_take_string(value, g_strdup(filename));
270  g_hash_table_insert(md, "location", value);
271 
272  if (tuple != NULL)
273  {
274  tuple_insert_to_hash_full(md, tuple, "length", "mtime");
275  tuple_insert_to_hash(md, tuple, "title");
276  tuple_insert_to_hash(md, tuple, "artist");
277  tuple_insert_to_hash(md, tuple, "album");
278  tuple_insert_to_hash(md, tuple, "comment");
279  tuple_insert_to_hash(md, tuple, "genre");
280  tuple_insert_to_hash(md, tuple, "year");
281  tuple_insert_to_hash(md, tuple, "codec");
282  tuple_insert_to_hash(md, tuple, "quality");
283  tuple_insert_to_hash_full(md, tuple, "track-number", "tracknumber");
284  tuple_insert_to_hash_full(md, tuple, "bitrate", "audio-bitrate");
285  }
286 
287  return md;
288 }
289 
290 static GValue * get_field (int playlist, int entry, const char * field)
291 {
292  Tuple * tuple = playlist_entry_get_tuple (playlist, entry, FALSE);
293  GValue * value = tuple ? tuple_value_to_gvalue (tuple, field) : NULL;
294 
295  if (tuple)
296  tuple_unref (tuple);
297 
298  return value;
299 }
300 
301 static GHashTable * get_mpris_metadata (int playlist, int entry)
302 {
303  char * filename = playlist_entry_get_filename (playlist, entry);
304  Tuple * tuple = playlist_entry_get_tuple (playlist, entry, FALSE);
305 
306  GHashTable * metadata = NULL;
307  if (filename && tuple)
308  metadata = make_mpris_metadata (filename, tuple);
309 
310  str_unref (filename);
311  if (tuple)
312  tuple_unref (tuple);
313 
314  return metadata;
315 }
316 
317 /* MPRIS API */
318 // MPRIS /
319 bool_t mpris_root_identity(MprisRoot * obj, char ** identity, GError ** error)
320 {
321  *identity = g_strdup_printf("Audacious %s", VERSION);
322  return TRUE;
323 }
324 
325 bool_t mpris_root_quit(MprisPlayer * obj, GError ** error)
326 {
327  event_queue("quit", NULL);
328  return TRUE;
329 }
330 
331 // MPRIS /Player
332 
333 bool_t mpris_player_next (MprisPlayer * obj, GError * * error)
334 {
335  drct_pl_next ();
336  return TRUE;
337 }
338 
339 bool_t mpris_player_prev (MprisPlayer * obj, GError * * error)
340 {
341  drct_pl_prev ();
342  return TRUE;
343 }
344 
345 bool_t mpris_player_pause (MprisPlayer * obj, GError * * error)
346 {
347  drct_pause ();
348  return TRUE;
349 }
350 
351 bool_t mpris_player_stop (MprisPlayer * obj, GError * * error)
352 {
353  drct_stop ();
354  return TRUE;
355 }
356 
357 bool_t mpris_player_play (MprisPlayer * obj, GError * * error)
358 {
359  drct_play ();
360  return TRUE;
361 }
362 
363 bool_t mpris_player_repeat(MprisPlayer * obj, bool_t rpt, GError ** error)
364 {
365  fprintf (stderr, "implement me\n");
366  return TRUE;
367 }
368 
369 static void append_int_value(GValueArray * ar, int tmp)
370 {
371  GValue value;
372  memset(&value, 0, sizeof(value));
373  g_value_init(&value, G_TYPE_INT);
374  g_value_set_int(&value, tmp);
375  g_value_array_append(ar, &value);
376 }
377 
378 static int get_playback_status (void)
379 {
380  if (! drct_get_playing ())
381  return MPRIS_STATUS_STOP;
382 
384 }
385 
386 bool_t mpris_player_get_status(MprisPlayer * obj, GValueArray * *status, GError * *error)
387 {
388  *status = g_value_array_new(4);
389 
390  append_int_value(*status, (int) get_playback_status());
391  append_int_value (* status, get_bool (NULL, "shuffle"));
392  append_int_value (* status, get_bool (NULL, "no_playlist_advance"));
393  append_int_value (* status, get_bool (NULL, "repeat"));
394  return TRUE;
395 }
396 
397 bool_t mpris_player_get_metadata (MprisPlayer * obj, GHashTable * * metadata,
398  GError * * error)
399 {
401  int entry = (playlist >= 0) ? playlist_get_position (playlist) : -1;
402 
403  * metadata = (entry >= 0) ? get_mpris_metadata (playlist, entry) : NULL;
404  if (! * metadata)
405  * metadata = g_hash_table_new (g_str_hash, g_str_equal);
406 
407  return TRUE;
408 }
409 
410 bool_t mpris_player_get_caps(MprisPlayer * obj, int * capabilities, GError ** error)
411 {
413  return TRUE;
414 }
415 
416 bool_t mpris_player_volume_set(MprisPlayer * obj, int vol, GError ** error)
417 {
418  drct_set_volume_main (vol);
419  return TRUE;
420 }
421 
422 bool_t mpris_player_volume_get(MprisPlayer * obj, int * vol, GError ** error)
423 {
424  drct_get_volume_main (vol);
425  return TRUE;
426 }
427 
428 bool_t mpris_player_position_set (MprisPlayer * obj, int pos, GError * * error)
429 {
430  drct_seek (pos);
431  return TRUE;
432 }
433 
434 bool_t mpris_player_position_get (MprisPlayer * obj, int * pos, GError * * error)
435 {
436  * pos = drct_get_time ();
437  return TRUE;
438 }
439 
440 // MPRIS /Player signals
441 bool_t mpris_emit_caps_change(MprisPlayer * obj)
442 {
443  g_signal_emit(obj, signals[CAPS_CHANGE_SIG], 0, 0);
444  return TRUE;
445 }
446 
447 bool_t mpris_emit_track_change(MprisPlayer * obj)
448 {
449  int playlist, entry;
450  GHashTable *metadata;
451 
452  playlist = playlist_get_playing();
453  entry = playlist_get_position(playlist);
454  char * filename = playlist_entry_get_filename (playlist, entry);
455  Tuple * tuple = playlist_entry_get_tuple (playlist, entry, FALSE);
456 
457  if (filename && tuple)
458  {
459  metadata = make_mpris_metadata (filename, tuple);
460  g_signal_emit (obj, signals[TRACK_CHANGE_SIG], 0, metadata);
461  g_hash_table_destroy (metadata);
462  }
463 
464  str_unref (filename);
465  if (tuple)
466  tuple_unref (tuple);
467 
468  return (filename && tuple);
469 }
470 
472 {
473  GValueArray *ar = g_value_array_new(4);
474 
475  if (status == MPRIS_STATUS_INVALID)
476  status = get_playback_status ();
477 
478  append_int_value(ar, (int) status);
479  append_int_value (ar, get_bool (NULL, "shuffle"));
480  append_int_value (ar, get_bool (NULL, "no_playlist_advance"));
481  append_int_value (ar, get_bool (NULL, "repeat"));
482 
483  g_signal_emit(obj, signals[STATUS_CHANGE_SIG], 0, ar);
484  g_value_array_free(ar);
485  return TRUE;
486 }
487 
488 // MPRIS /TrackList
489 bool_t mpris_emit_tracklist_change(MprisTrackList * obj, int playlist)
490 {
491  g_signal_emit(obj, tracklist_signals[TRACKLIST_CHANGE_SIG], 0, playlist_entry_count(playlist));
492  return TRUE;
493 }
494 
495 static void mpris_playlist_update_hook(gpointer unused, MprisTrackList * obj)
496 {
498 
499  mpris_emit_tracklist_change(obj, playlist);
500 }
501 
502 bool_t mpris_tracklist_get_metadata (MprisTrackList * obj, int pos,
503  GHashTable * * metadata, GError * * error)
504 {
505  * metadata = get_mpris_metadata (playlist_get_active (), pos);
506  if (! * metadata)
507  * metadata = g_hash_table_new (g_str_hash, g_str_equal);
508 
509  return TRUE;
510 }
511 
512 bool_t mpris_tracklist_get_current_track (MprisTrackList * obj, int * pos,
513  GError * * error)
514 {
516  return TRUE;
517 }
518 
519 bool_t mpris_tracklist_get_length (MprisTrackList * obj, int * length, GError * * error)
520 {
522  return TRUE;
523 }
524 
525 bool_t mpris_tracklist_add_track (MprisTrackList * obj, char * uri, bool_t play,
526  GError * * error)
527 {
528  playlist_entry_insert (playlist_get_active (), -1, uri, NULL, play);
529  return TRUE;
530 }
531 
532 bool_t mpris_tracklist_del_track (MprisTrackList * obj, int pos, GError * * error)
533 {
535  return TRUE;
536 }
537 
538 bool_t mpris_tracklist_loop (MprisTrackList * obj, bool_t loop, GError * *
539  error)
540 {
541  set_bool (NULL, "repeat", loop);
542  return TRUE;
543 }
544 
545 bool_t mpris_tracklist_random (MprisTrackList * obj, bool_t random,
546  GError * * error)
547 {
548  set_bool (NULL, "shuffle", random);
549  return TRUE;
550 }
551 
552 // Audacious General Information
554 {
555  *version = g_strdup(VERSION);
556  return TRUE;
557 }
558 
560 {
561  event_queue("quit", NULL);
562  return TRUE;
563 }
564 
566 {
568  return TRUE;
569 }
570 
572  bool_t * visible, GError ** error)
573 {
574  * visible = interface_is_shown ();
575  return TRUE;
576 }
577 
579  GError * * error)
580 {
581  interface_show (show);
582  return TRUE;
583 }
584 
585 bool_t audacious_rc_get_tuple_fields(RemoteObject * obj, char *** fields, GError ** error)
586 {
587  * fields = g_new (char *, TUPLE_FIELDS);
588 
589  for (int i = 0; i < TUPLE_FIELDS; i ++)
590  (* fields)[i] = g_strdup (tuple_field_get_name (i));
591 
592  (* fields)[TUPLE_FIELDS] = NULL;
593  return TRUE;
594 }
595 
596 
597 // Playback Information/Manipulation
598 
600 {
601  drct_play ();
602  return TRUE;
603 }
604 
606 {
607  drct_pause ();
608  return TRUE;
609 }
610 
612 {
613  drct_stop ();
614  return TRUE;
615 }
616 
617 bool_t audacious_rc_playing (RemoteObject * obj, bool_t * is_playing, GError * * error)
618 {
619  * is_playing = drct_get_playing ();
620  return TRUE;
621 }
622 
623 bool_t audacious_rc_paused (RemoteObject * obj, bool_t * is_paused, GError * * error)
624 {
625  * is_paused = drct_get_paused ();
626  return TRUE;
627 }
628 
629 bool_t audacious_rc_stopped (RemoteObject * obj, bool_t * is_stopped, GError * * error)
630 {
631  * is_stopped = ! drct_get_playing ();
632  return TRUE;
633 }
634 
635 bool_t audacious_rc_status (RemoteObject * obj, char * * status, GError * * error)
636 {
637  if (drct_get_playing ())
638  * status = strdup (drct_get_paused () ? "paused" : "playing");
639  else
640  * status = strdup ("stopped");
641 
642  return TRUE;
643 }
644 
645 bool_t audacious_rc_info (RemoteObject * obj, int * rate, int * freq, int * nch,
646  GError * * error)
647 {
648  drct_get_info (rate, freq, nch);
649  return TRUE;
650 }
651 
652 bool_t audacious_rc_time (RemoteObject * obj, int * time, GError * * error)
653 {
654  * time = drct_get_time ();
655  return TRUE;
656 }
657 
658 bool_t audacious_rc_seek (RemoteObject * obj, unsigned int pos, GError * * error)
659 {
660  drct_seek (pos);
661  return TRUE;
662 }
663 
664 bool_t audacious_rc_volume(RemoteObject * obj, int * vl, int * vr, GError ** error)
665 {
666  drct_get_volume (vl, vr);
667  return TRUE;
668 }
669 
670 bool_t audacious_rc_set_volume(RemoteObject * obj, int vl, int vr, GError ** error)
671 {
672  drct_set_volume (vl, vr);
673  return TRUE;
674 }
675 
676 bool_t audacious_rc_balance(RemoteObject * obj, int * balance, GError ** error)
677 {
678  drct_get_volume_balance (balance);
679  return TRUE;
680 }
681 
682 // Playlist Information/Manipulation
683 
684 bool_t audacious_rc_position (RemoteObject * obj, int * pos, GError * * error)
685 {
687  return TRUE;
688 }
689 
691 {
692  drct_pl_next ();
693  return TRUE;
694 }
695 
697 {
698  drct_pl_prev ();
699  return TRUE;
700 }
701 
702 bool_t audacious_rc_length (RemoteObject * obj, int * length, GError * * error)
703 {
705  return TRUE;
706 }
707 
708 bool_t audacious_rc_song_title (RemoteObject * obj, unsigned int pos, char * *
709  title, GError * * error)
710 {
711  char * title2 = playlist_entry_get_title (playlist_get_active (), pos, FALSE);
712  * title = strdup (title2);
713  str_unref (title2);
714  return TRUE;
715 }
716 
718  char * * filename, GError * * error)
719 {
720  char * filename2 = playlist_entry_get_filename (playlist_get_active (), pos);
721  * filename = strdup (filename2);
722  str_unref (filename2);
723  return TRUE;
724 }
725 
726 bool_t audacious_rc_song_length(RemoteObject * obj, unsigned int pos, int * length, GError * *error)
727 {
728  audacious_rc_song_frames(obj, pos, length, error);
729  *length /= 1000;
730  return TRUE;
731 }
732 
733 bool_t audacious_rc_song_frames (RemoteObject * obj, unsigned int pos, int *
734  length, GError * * error)
735 {
737  return TRUE;
738 }
739 
740 bool_t audacious_rc_song_tuple (RemoteObject * obj, unsigned int pos, char *
741  field, GValue * value, GError * * error)
742 {
743  GValue * value2 = get_field (playlist_get_active (), pos, field);
744  if (! value2)
745  return FALSE;
746 
747  memset (value, 0, sizeof (GValue));
748  g_value_init (value, G_VALUE_TYPE (value2));
749  g_value_copy (value2, value);
750  g_value_unset (value2);
751  g_free (value2);
752  return TRUE;
753 }
754 
755 bool_t audacious_rc_jump (RemoteObject * obj, unsigned int pos, GError * * error)
756 {
758  return TRUE;
759 }
760 
761 bool_t audacious_rc_add(RemoteObject * obj, char * file, GError * *error)
762 {
763  return audacious_rc_playlist_ins_url_string(obj, file, -1, error);
764 }
765 
766 bool_t audacious_rc_add_url(RemoteObject * obj, char * file, GError * *error)
767 {
768  return audacious_rc_playlist_ins_url_string(obj, file, -1, error);
769 }
770 
771 static Index * strings_to_index (char * * strings)
772 {
773  Index * index = index_new ();
774 
775  while (* strings)
776  index_append (index, str_get (* strings ++));
777 
778  return index;
779 }
780 
782  GError * * error)
783 {
784  drct_pl_add_list (strings_to_index (filenames), -1);
785  return TRUE;
786 }
787 
789  GError * * error)
790 {
791  drct_pl_open_list (strings_to_index (filenames));
792  return TRUE;
793 }
794 
796  filenames, GError * * error)
797 {
799  return TRUE;
800 }
801 
802 bool_t audacious_rc_delete (RemoteObject * obj, unsigned int pos, GError * * error)
803 {
805  return TRUE;
806 }
807 
809 {
810  int playlist = playlist_get_active ();
811  playlist_entry_delete (playlist, 0, playlist_entry_count (playlist));
812  return TRUE;
813 }
814 
816 {
817  * is_advance = ! get_bool (NULL, "no_playlist_advance");
818  return TRUE;
819 }
820 
822 {
823  set_bool (NULL, "no_playlist_advance", ! get_bool (NULL, "no_playlist_advance"));
824  return TRUE;
825 }
826 
827 bool_t audacious_rc_repeat(RemoteObject * obj, bool_t * is_repeating, GError ** error)
828 {
829  *is_repeating = get_bool (NULL, "repeat");
830  return TRUE;
831 }
832 
834 {
835  set_bool (NULL, "repeat", ! get_bool (NULL, "repeat"));
836  return TRUE;
837 }
838 
839 bool_t audacious_rc_shuffle(RemoteObject * obj, bool_t * is_shuffling, GError ** error)
840 {
841  *is_shuffling = get_bool (NULL, "shuffle");
842  return TRUE;
843 }
844 
846 {
847  set_bool (NULL, "shuffle", ! get_bool (NULL, "shuffle"));
848  return TRUE;
849 }
850 
851 bool_t audacious_rc_stop_after (RemoteObject * obj, bool_t * is_stopping, GError * * error)
852 {
853  * is_stopping = get_bool (NULL, "stop_after_current_song");
854  return TRUE;
855 }
856 
858 {
859  set_bool (NULL, "stop_after_current_song", ! get_bool (NULL, "stop_after_current_song"));
860  return TRUE;
861 }
862 
863 /* New on Oct 5 */
865 {
866  event_queue("prefswin show", GINT_TO_POINTER(show));
867  return TRUE;
868 }
869 
871 {
872  event_queue("aboutwin show", GINT_TO_POINTER(show));
873  return TRUE;
874 }
875 
877 {
878  if (show)
880 
881  return TRUE;
882 }
883 
885 {
886  if (show)
888 
889  return TRUE;
890 }
891 
893 {
894  if (drct_get_playing ())
895  drct_pause ();
896  else
897  drct_play ();
898 
899  return TRUE;
900 }
901 
902 bool_t audacious_rc_get_info (RemoteObject * obj, int * rate, int * freq,
903  int * nch, GError * * error)
904 {
905  drct_get_info (rate, freq, nch);
906  return TRUE;
907 }
908 
910 {
911  hook_call("mainwin set always on top", &ontop);
912  return TRUE;
913 }
914 
916 {
918  return TRUE;
919 }
920 
922 {
923  int playlist = playlist_get_active ();
924  int at = playlist_queue_find_entry (playlist, pos);
925 
926  if (at >= 0)
927  playlist_queue_delete (playlist, at, 1);
928 
929  return TRUE;
930 }
931 
933 {
934  int playlist = playlist_get_active ();
935  playlist_queue_delete (playlist, 0, playlist_queue_count (playlist));
936  return TRUE;
937 }
938 
940  GError * * error)
941 {
943  return TRUE;
944 }
945 
947  GError * * error)
948 {
950  return TRUE;
951 }
952 
954  qpos, GError * * error)
955 {
957  return TRUE;
958 }
959 
961  is_queued, GError * * error)
962 {
963  * is_queued = (playlist_queue_find_entry (playlist_get_active (), pos) >= 0);
964  return TRUE;
965 }
966 
968  pos, GError * * error)
969 {
971  return TRUE;
972 }
973 
974 bool_t audacious_rc_playlist_add(RemoteObject * obj, void *list, GError * *error)
975 {
976  return audacious_rc_playlist_ins_url_string(obj, list, -1, error);
977 }
978 
980  GError * * error)
981 {
982  drct_pl_open_temp (url);
983  return TRUE;
984 }
985 
986 /* New on Nov 7: Equalizer */
987 bool_t audacious_rc_get_eq(RemoteObject * obj, double * preamp, GArray ** bands, GError ** error)
988 {
989  * preamp = get_double (NULL, "equalizer_preamp");
990  * bands = g_array_new (FALSE, FALSE, sizeof (double));
991  g_array_set_size (* bands, AUD_EQUALIZER_NBANDS);
992  eq_get_bands ((double *) (* bands)->data);
993 
994  return TRUE;
995 }
996 
997 bool_t audacious_rc_get_eq_preamp(RemoteObject * obj, double * preamp, GError ** error)
998 {
999  * preamp = get_double (NULL, "equalizer_preamp");
1000  return TRUE;
1001 }
1002 
1003 bool_t audacious_rc_get_eq_band(RemoteObject * obj, int band, double * value, GError ** error)
1004 {
1005  * value = eq_get_band (band);
1006  return TRUE;
1007 }
1008 
1009 bool_t audacious_rc_set_eq(RemoteObject * obj, double preamp, GArray * bands, GError ** error)
1010 {
1011  set_double (NULL, "equalizer_preamp", preamp);
1012  eq_set_bands ((double *) bands->data);
1013  return TRUE;
1014 }
1015 
1016 bool_t audacious_rc_set_eq_preamp(RemoteObject * obj, double preamp, GError ** error)
1017 {
1018  set_double (NULL, "equalizer_preamp", preamp);
1019  return TRUE;
1020 }
1021 
1022 bool_t audacious_rc_set_eq_band(RemoteObject * obj, int band, double value, GError ** error)
1023 {
1024  eq_set_band (band, value);
1025  return TRUE;
1026 }
1027 
1029 {
1030  set_bool (NULL, "equalizer_active", active);
1031  return TRUE;
1032 }
1033 
1035  title, GError * * error)
1036 {
1037  char * title2 = playlist_get_title (playlist_get_active ());
1038  * title = strdup (title2);
1039  str_unref (title2);
1040  return TRUE;
1041 }
1042 
1043 DBusGProxy *audacious_get_dbus_proxy(void)
1044 {
1045  DBusGConnection *connection = NULL;
1046  GError *error = NULL;
1047  connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
1048  g_clear_error(&error);
1049  return dbus_g_proxy_new_for_name(connection, AUDACIOUS_DBUS_SERVICE, AUDACIOUS_DBUS_PATH, AUDACIOUS_DBUS_INTERFACE);
1050 }