Audacious $Id:Doxyfile42802007-03-2104:39:00Znenolod$
dbus.c
Go to the documentation of this file.
00001 /*
00002  * Audacious: A cross-platform multimedia player
00003  * Copyright (c) 2007 Ben Tucker
00004  * Copyright 2009-2010 Audacious development team
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; under version 3 of the License.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses>.
00017  *
00018  * The Audacious team does not consider modular code linking to
00019  * Audacious or using our public API to be a derived work.
00020  */
00021 
00022 #include "config.h"
00023 
00024 #include <glib.h>
00025 #include <dbus/dbus.h>
00026 #include <dbus/dbus-glib.h>
00027 #include <dbus/dbus-glib-bindings.h>
00028 #include <dbus/dbus-glib-lowlevel.h>
00029 #include "dbus.h"
00030 #include "dbus-service.h"
00031 #include "dbus-server-bindings.h"
00032 
00033 #include <math.h>
00034 #include <libaudcore/eventqueue.h>
00035 
00036 #include "audconfig.h"
00037 #include "debug.h"
00038 #include "drct.h"
00039 #include "equalizer.h"
00040 #include "playback.h"
00041 #include "playlist.h"
00042 #include "interface.h"
00043 
00044 struct StatusRequest
00045 {
00046     gboolean playing, paused;
00047     gint time, length;
00048     gint bitrate, samplerate, channels;
00049 };
00050 
00051 struct PositionRequest
00052 {
00053     gint playlist;              /* -1 = active, -2 = playing */
00054     gint entry;                 /* -1 = current */
00055     gint entry_count, queue_count;
00056 };
00057 
00058 struct InfoRequest
00059 {
00060     gint playlist;              /* -1 = active, -2 = playing */
00061     gint entry;                 /* -1 = current */
00062     gchar *filename, *title, *pltitle;
00063     gint length;
00064 };
00065 
00066 struct FieldRequest
00067 {
00068     gint playlist;              /* -1 = active, -2 = playing */
00069     gint entry;                 /* -1 = current */
00070     const gchar *field;
00071     GValue *value;
00072 };
00073 
00074 struct AddRequest
00075 {
00076     gint position;              /* -1 = at end */
00077     gchar *filename;
00078     gboolean play;
00079 };
00080 
00081 struct MprisMetadataRequest
00082 {
00083     gint playlist;              /* -1 = active, -2 = playing */
00084     gint entry;                 /* -1 = current */
00085     GHashTable *metadata;
00086 };
00087 
00088 static DBusGConnection *dbus_conn = NULL;
00089 static guint signals[LAST_SIG] = { 0 };
00090 static guint tracklist_signals[LAST_TRACKLIST_SIG] = { 0 };
00091 
00092 MprisPlayer * mpris = NULL;
00093 
00094 static GThread *main_thread;
00095 static GMutex *info_mutex;
00096 static GCond *info_cond;
00097 
00098 G_DEFINE_TYPE (RemoteObject, audacious_rc, G_TYPE_OBJECT)
00099 G_DEFINE_TYPE (MprisRoot, mpris_root, G_TYPE_OBJECT)
00100 G_DEFINE_TYPE (MprisPlayer, mpris_player, G_TYPE_OBJECT)
00101 G_DEFINE_TYPE (MprisTrackList, mpris_tracklist, G_TYPE_OBJECT)
00102 
00103 #define DBUS_TYPE_G_STRING_VALUE_HASHTABLE (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE))
00104 
00105 static void mpris_playlist_update_hook(gpointer unused, MprisTrackList *obj);
00106 
00107 void audacious_rc_class_init(RemoteObjectClass * klass)
00108 {
00109 }
00110 
00111 void mpris_root_class_init(MprisRootClass * klass)
00112 {
00113 }
00114 
00115 void mpris_player_class_init(MprisPlayerClass * klass)
00116 {
00117     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);
00118     signals[TRACK_CHANGE_SIG] =
00119         g_signal_new("track_change",
00120                      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);
00121     signals[STATUS_CHANGE_SIG] =
00122         g_signal_new("status_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_VALUE_ARRAY);
00123 }
00124 
00125 void mpris_tracklist_class_init(MprisTrackListClass * klass)
00126 {
00127     tracklist_signals[TRACKLIST_CHANGE_SIG] = g_signal_new("track_list_change", G_OBJECT_CLASS_TYPE(klass),
00128         G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
00129 }
00130 
00131 void audacious_rc_init(RemoteObject * object)
00132 {
00133     GError *error = NULL;
00134     DBusGProxy *driver_proxy;
00135     guint request_ret;
00136 
00137     AUDDBG ("Registering remote D-Bus interfaces.\n");
00138 
00139     dbus_g_object_type_install_info(audacious_rc_get_type(), &dbus_glib_audacious_rc_object_info);
00140 
00141     // Register DBUS path
00142     dbus_g_connection_register_g_object(dbus_conn, AUDACIOUS_DBUS_PATH, G_OBJECT(object));
00143 
00144     // Register the service name, the constants here are defined in
00145     // dbus-glib-bindings.h
00146     driver_proxy = dbus_g_proxy_new_for_name(dbus_conn, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
00147 
00148     if (!org_freedesktop_DBus_request_name(driver_proxy, AUDACIOUS_DBUS_SERVICE, 0, &request_ret, &error))
00149     {
00150         g_warning("Unable to register service: %s", error->message);
00151         g_error_free(error);
00152     }
00153 
00154     if (!org_freedesktop_DBus_request_name(driver_proxy, AUDACIOUS_DBUS_SERVICE_MPRIS, 0, &request_ret, &error))
00155     {
00156         g_warning("Unable to register service: %s", error->message);
00157         g_error_free(error);
00158     }
00159 
00160     g_object_unref(driver_proxy);
00161 }
00162 
00163 void mpris_root_init(MprisRoot * object)
00164 {
00165     dbus_g_object_type_install_info(mpris_root_get_type(), &dbus_glib_mpris_root_object_info);
00166 
00167     // Register DBUS path
00168     dbus_g_connection_register_g_object(dbus_conn, AUDACIOUS_DBUS_PATH_MPRIS_ROOT, G_OBJECT(object));
00169 }
00170 
00171 void mpris_player_init(MprisPlayer * object)
00172 {
00173     dbus_g_object_type_install_info(mpris_player_get_type(), &dbus_glib_mpris_player_object_info);
00174 
00175     // Register DBUS path
00176     dbus_g_connection_register_g_object(dbus_conn, AUDACIOUS_DBUS_PATH_MPRIS_PLAYER, G_OBJECT(object));
00177 
00178     // Add signals
00179     DBusGProxy *proxy = object->proxy;
00180     if (proxy != NULL)
00181     {
00182         dbus_g_proxy_add_signal (proxy, "StatusChange", dbus_g_type_get_struct
00183          ("GValueArray", G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT,
00184          G_TYPE_INVALID), G_TYPE_INVALID);
00185         dbus_g_proxy_add_signal (proxy, "CapsChange", G_TYPE_INT, G_TYPE_INVALID);
00186         dbus_g_proxy_add_signal(proxy, "TrackChange", DBUS_TYPE_G_STRING_VALUE_HASHTABLE, G_TYPE_INVALID);
00187     }
00188     else
00189     {
00190         /* XXX / FIXME: Why does this happen? -- ccr */
00191         AUDDBG ("object->proxy == NULL; not adding some signals.\n");
00192     }
00193 }
00194 
00195 void mpris_tracklist_init(MprisTrackList * object)
00196 {
00197     dbus_g_object_type_install_info(mpris_tracklist_get_type(), &dbus_glib_mpris_tracklist_object_info);
00198 
00199     // Register DBUS path
00200     dbus_g_connection_register_g_object(dbus_conn, AUDACIOUS_DBUS_PATH_MPRIS_TRACKLIST, G_OBJECT(object));
00201 
00202     // Add signals
00203     DBusGProxy *proxy = object->proxy;
00204     if (proxy != NULL)
00205     {
00206         dbus_g_proxy_add_signal(proxy, "TrackListChange", G_TYPE_INT, G_TYPE_INVALID);
00207     }
00208     else
00209     {
00210         /* XXX / FIXME: Why does this happen? -- ccr */
00211         AUDDBG ("object->proxy == NULL, not adding some signals.\n");
00212     }
00213 
00214     hook_associate("playlist update", (HookFunction) mpris_playlist_update_hook, object);
00215 }
00216 
00217 void init_dbus()
00218 {
00219     GError *error = NULL;
00220     DBusConnection *local_conn;
00221 
00222     main_thread = g_thread_self();
00223     info_mutex = g_mutex_new();
00224     info_cond = g_cond_new();
00225 
00226     AUDDBG ("Trying to initialize D-Bus.\n");
00227     dbus_conn = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
00228     if (dbus_conn == NULL)
00229     {
00230         g_warning("Unable to connect to dbus: %s", error->message);
00231         g_error_free(error);
00232         return;
00233     }
00234 
00235     g_type_init();
00236     g_object_new(audacious_rc_get_type(), NULL);
00237     g_object_new(mpris_root_get_type(), NULL);
00238     mpris = g_object_new(mpris_player_get_type(), NULL);
00239     g_object_new(mpris_tracklist_get_type(), NULL);
00240 
00241     local_conn = dbus_g_connection_get_connection(dbus_conn);
00242     dbus_connection_set_exit_on_disconnect(local_conn, FALSE);
00243 }
00244 
00245 static GValue *tuple_value_to_gvalue(const Tuple * tuple, const gchar * key)
00246 {
00247     GValue *val;
00248     TupleValueType type = tuple_get_value_type((Tuple *) tuple, -1, key);
00249 
00250     if (type == TUPLE_STRING)
00251     {
00252         val = g_new0(GValue, 1);
00253         g_value_init(val, G_TYPE_STRING);
00254         g_value_take_string(val, g_strdup(tuple_get_string((Tuple *) tuple, -1, key)));
00255         return val;
00256     }
00257     else if (type == TUPLE_INT)
00258     {
00259         val = g_new0(GValue, 1);
00260         g_value_init(val, G_TYPE_INT);
00261         g_value_set_int(val, tuple_get_int((Tuple *) tuple, -1, key));
00262         return val;
00263     }
00264     return NULL;
00265 }
00266 
00275 static void tuple_insert_to_hash_full(GHashTable * md, const Tuple * tuple,
00276                                       const gchar * tuple_key, const gchar *key)
00277 {
00278     GValue *value = tuple_value_to_gvalue(tuple, tuple_key);
00279     if (value != NULL)
00280         g_hash_table_insert (md, (void *) key, value);
00281 }
00282 
00283 static void tuple_insert_to_hash(GHashTable * md, const Tuple * tuple,
00284                                  const gchar *key)
00285 {
00286     tuple_insert_to_hash_full(md, tuple, key, key);
00287 }
00288 
00289 static void remove_metadata_value(gpointer value)
00290 {
00291     g_value_unset((GValue *) value);
00292     g_free((GValue *) value);
00293 }
00294 
00295 static GHashTable *make_mpris_metadata(const gchar * filename, const Tuple * tuple)
00296 {
00297     GHashTable *md = NULL;
00298     gpointer value;
00299 
00300     md = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, remove_metadata_value);
00301 
00302     value = g_malloc(sizeof(GValue));
00303     memset(value, 0, sizeof(GValue));
00304     g_value_init(value, G_TYPE_STRING);
00305     g_value_take_string(value, g_strdup(filename));
00306     g_hash_table_insert(md, "location", value);
00307 
00308     if (tuple != NULL)
00309     {
00310         tuple_insert_to_hash_full(md, tuple, "length", "mtime");
00311         tuple_insert_to_hash(md, tuple, "title");
00312         tuple_insert_to_hash(md, tuple, "artist");
00313         tuple_insert_to_hash(md, tuple, "album");
00314         tuple_insert_to_hash(md, tuple, "comment");
00315         tuple_insert_to_hash(md, tuple, "genre");
00316         tuple_insert_to_hash(md, tuple, "year");
00317         tuple_insert_to_hash(md, tuple, "codec");
00318         tuple_insert_to_hash(md, tuple, "quality");
00319         tuple_insert_to_hash_full(md, tuple, "track-number", "tracknumber");
00320         tuple_insert_to_hash_full(md, tuple, "bitrate", "audio-bitrate");
00321     }
00322 
00323     return md;
00324 }
00325 
00326 static void real_position(gint * playlist, gint * entry)
00327 {
00328     if (*playlist == -2)
00329         *playlist = playlist_get_playing();
00330     if (*playlist == -1)
00331         *playlist = playlist_get_active();
00332     if (*entry == -1)
00333         *entry = playlist_get_position(*playlist);
00334 }
00335 
00336 static gboolean get_status_cb(void *data)
00337 {
00338     struct StatusRequest *request = data;
00339 
00340     g_mutex_lock(info_mutex);
00341 
00342     memset (request, 0, sizeof (* request));
00343     request->playing = playback_get_playing();
00344 
00345     if (request->playing)
00346     {
00347         request->paused = playback_get_paused ();
00348         request->time = playback_get_time ();
00349         request->length = playback_get_length ();
00350         playback_get_info (& request->bitrate, & request->samplerate,
00351          & request->channels);
00352     }
00353 
00354     g_cond_signal(info_cond);
00355     g_mutex_unlock(info_mutex);
00356     return FALSE;
00357 }
00358 
00359 static void get_status(struct StatusRequest *request)
00360 {
00361     if (g_thread_self() == main_thread)
00362         get_status_cb(request);
00363     else
00364     {
00365         g_mutex_lock(info_mutex);
00366         g_timeout_add(0, get_status_cb, request);
00367         g_cond_wait(info_cond, info_mutex);
00368         g_mutex_unlock(info_mutex);
00369     }
00370 }
00371 
00372 static gboolean get_position_cb(void *data)
00373 {
00374     struct PositionRequest *request = data;
00375 
00376     g_mutex_lock(info_mutex);
00377 
00378     real_position(&request->playlist, &request->entry);
00379     request->entry_count = playlist_entry_count(request->playlist);
00380     request->queue_count = playlist_queue_count(request->playlist);
00381 
00382     g_cond_signal(info_cond);
00383     g_mutex_unlock(info_mutex);
00384     return FALSE;
00385 }
00386 
00387 static void get_position(struct PositionRequest *request)
00388 {
00389     if (g_thread_self() == main_thread)
00390         get_position_cb(request);
00391     else
00392     {
00393         g_mutex_lock(info_mutex);
00394         g_timeout_add(0, get_position_cb, request);
00395         g_cond_wait(info_cond, info_mutex);
00396         g_mutex_unlock(info_mutex);
00397     }
00398 }
00399 
00400 static gboolean get_info_cb(void *data)
00401 {
00402     struct InfoRequest *request = data;
00403 
00404     g_mutex_lock(info_mutex);
00405 
00406     real_position(&request->playlist, &request->entry);
00407     request->filename = playlist_entry_get_filename (request->playlist,
00408      request->entry);
00409     request->title = playlist_entry_get_title (request->playlist,
00410      request->entry, FALSE);
00411     request->length = playlist_entry_get_length (request->playlist,
00412      request->entry, FALSE);
00413     request->pltitle = playlist_get_title (request->playlist);
00414 
00415     g_cond_signal(info_cond);
00416     g_mutex_unlock(info_mutex);
00417     return FALSE;
00418 }
00419 
00420 static void get_info(struct InfoRequest *request)
00421 {
00422     if (g_thread_self() == main_thread)
00423         get_info_cb(request);
00424     else
00425     {
00426         g_mutex_lock(info_mutex);
00427         g_timeout_add(0, get_info_cb, request);
00428         g_cond_wait(info_cond, info_mutex);
00429         g_mutex_unlock(info_mutex);
00430     }
00431 }
00432 
00433 static gboolean get_field_cb(void *data)
00434 {
00435     struct FieldRequest *request = data;
00436 
00437     g_mutex_lock(info_mutex);
00438 
00439     real_position(&request->playlist, &request->entry);
00440     Tuple * tuple = playlist_entry_get_tuple (request->playlist, request->entry, FALSE);
00441     request->value = (tuple == NULL) ? NULL : tuple_value_to_gvalue(tuple, request->field);
00442     if (tuple)
00443         tuple_free (tuple)
00444 
00445     g_cond_signal(info_cond);
00446     g_mutex_unlock(info_mutex);
00447     return FALSE;
00448 }
00449 
00450 static void get_field(struct FieldRequest *request)
00451 {
00452     if (g_thread_self() == main_thread)
00453         get_field_cb(request);
00454     else
00455     {
00456         g_mutex_lock(info_mutex);
00457         g_timeout_add(0, get_field_cb, request);
00458         g_cond_wait(info_cond, info_mutex);
00459         g_mutex_unlock(info_mutex);
00460     }
00461 }
00462 
00463 static gboolean play_cb(void *unused)
00464 {
00465     /* Only the active playlist is visible through DBUS interface, so make sure
00466      * to play from it, not another playlist. --jlindgren */
00467     if (playlist_get_playing () != playlist_get_active ())
00468         playlist_set_playing (playlist_get_active ());
00469 
00470     drct_play();
00471     return FALSE;
00472 }
00473 
00474 static gboolean pause_cb(void *unused)
00475 {
00476     playback_pause();
00477     return FALSE;
00478 }
00479 
00480 static gboolean play_pause_cb(void *unused)
00481 {
00482     if (playback_get_playing())
00483         playback_pause();
00484     else
00485         playback_play (0, FALSE);
00486 
00487     return FALSE;
00488 }
00489 
00490 static gboolean seek_cb(void *data)
00491 {
00492     playback_seek (GPOINTER_TO_INT (data));
00493     return FALSE;
00494 }
00495 
00496 static gboolean stop_cb(void *unused)
00497 {
00498     playback_stop();
00499     return FALSE;
00500 }
00501 
00502 static gboolean prev_cb(void *unused)
00503 {
00504     drct_pl_prev();
00505     return FALSE;
00506 }
00507 
00508 static gboolean next_cb(void *unused)
00509 {
00510     drct_pl_next();
00511     return FALSE;
00512 }
00513 
00514 static gboolean jump_cb(void *data)
00515 {
00516     drct_pl_set_pos(GPOINTER_TO_INT(data));
00517     return FALSE;
00518 }
00519 
00520 static gboolean add_cb(void *data)
00521 {
00522     struct AddRequest *request = data;
00523     gint playlist = playlist_get_active();
00524 
00525     if (request->position < 0)
00526         request->position = playlist_entry_count (playlist);
00527 
00528     drct_pl_add (request->filename, request->position);
00529 
00530     if (request->play)
00531     {
00532         playlist_set_playing(playlist);
00533         playlist_set_position(playlist, request->position);
00534         playback_play (0, FALSE);
00535     }
00536 
00537     g_free(request);
00538     return FALSE;
00539 }
00540 
00541 static gboolean delete_cb(void *data)
00542 {
00543     drct_pl_delete(GPOINTER_TO_INT(data));
00544     return FALSE;
00545 }
00546 
00547 static gboolean clear_cb(void *unused)
00548 {
00549     drct_pl_clear();
00550     return FALSE;
00551 }
00552 
00553 static gboolean add_to_queue_cb(void *data)
00554 {
00555     drct_pq_add(GPOINTER_TO_INT(data));
00556     return FALSE;
00557 }
00558 
00559 static gboolean remove_from_queue_cb(void *data)
00560 {
00561     drct_pq_remove(GPOINTER_TO_INT(data));
00562     return FALSE;
00563 }
00564 
00565 static gboolean clear_queue_cb(void *unused)
00566 {
00567     drct_pq_clear();
00568     return FALSE;
00569 }
00570 
00571 static gboolean queue_get_entry_cb(void *data)
00572 {
00573     g_mutex_lock(info_mutex);
00574 
00575     * (gint *) data = drct_pq_get_entry (* (gint *) data);
00576 
00577     g_cond_signal(info_cond);
00578     g_mutex_unlock(info_mutex);
00579     return FALSE;
00580 }
00581 
00582 static gint queue_get_entry(gint position)
00583 {
00584     if (g_thread_self() == main_thread)
00585         queue_get_entry_cb(&position);
00586     else
00587     {
00588         g_mutex_lock(info_mutex);
00589         g_timeout_add(0, queue_get_entry_cb, &position);
00590         g_cond_wait(info_cond, info_mutex);
00591         g_mutex_unlock(info_mutex);
00592     }
00593 
00594     return position;
00595 }
00596 
00597 static gboolean queue_find_entry_cb(void *data)
00598 {
00599     g_mutex_lock(info_mutex);
00600 
00601     *(gint *) data = drct_pq_get_queue_position(*(gint *) data);
00602 
00603     g_cond_signal(info_cond);
00604     g_mutex_unlock(info_mutex);
00605     return FALSE;
00606 }
00607 
00608 static gint queue_find_entry(gint position)
00609 {
00610     if (g_thread_self() == main_thread)
00611         queue_find_entry_cb(&position);
00612     else
00613     {
00614         g_mutex_lock(info_mutex);
00615         g_timeout_add(0, queue_find_entry_cb, &position);
00616         g_cond_wait(info_cond, info_mutex);
00617         g_mutex_unlock(info_mutex);
00618     }
00619 
00620     return position;
00621 }
00622 
00623 gboolean add_to_new_playlist_cb(void *data)
00624 {
00625     drct_pl_open_temp (data);
00626     g_free(data);
00627     return FALSE;
00628 }
00629 
00630 static gboolean get_mpris_metadata_cb(void *data)
00631 {
00632     struct MprisMetadataRequest *request = data;
00633 
00634     g_mutex_lock(info_mutex);
00635 
00636     real_position(&request->playlist, &request->entry);
00637     gchar * filename = playlist_entry_get_filename (request->playlist,
00638      request->entry);
00639     Tuple * tuple = playlist_entry_get_tuple (request->playlist, request->entry,
00640      FALSE);
00641 
00642     if (filename && tuple)
00643         request->metadata = make_mpris_metadata (filename, tuple);
00644     else
00645         request->metadata = NULL;
00646 
00647     g_free (filename);
00648     if (tuple)
00649         tuple_free (tuple);
00650 
00651     g_cond_signal(info_cond);
00652     g_mutex_unlock(info_mutex);
00653     return FALSE;
00654 }
00655 
00656 static void get_mpris_metadata(struct MprisMetadataRequest *request)
00657 {
00658     if (g_thread_self() == main_thread)
00659         get_mpris_metadata_cb(request);
00660     else
00661     {
00662         g_mutex_lock(info_mutex);
00663         g_timeout_add(0, get_mpris_metadata_cb, request);
00664         g_cond_wait(info_cond, info_mutex);
00665         g_mutex_unlock(info_mutex);
00666     }
00667 }
00668 
00669 static gboolean set_no_playlist_advance_cb (void * no_advance)
00670 {
00671     cfg.no_playlist_advance = GPOINTER_TO_INT (no_advance);
00672     event_queue ("toggle no playlist advance", NULL);
00673     return FALSE;
00674 }
00675 
00676 static gboolean set_shuffle_cb (void * shuffle)
00677 {
00678     cfg.shuffle = GPOINTER_TO_INT (shuffle);
00679     event_queue ("toggle shuffle", NULL);
00680     return FALSE;
00681 }
00682 
00683 static gboolean set_repeat_cb (void * repeat)
00684 {
00685     cfg.repeat = GPOINTER_TO_INT (repeat);
00686     event_queue ("toggle repeat", NULL);
00687     return FALSE;
00688 }
00689 
00690 /* MPRIS API */
00691 // MPRIS /
00692 gboolean mpris_root_identity(MprisRoot * obj, gchar ** identity, GError ** error)
00693 {
00694     *identity = g_strdup_printf("Audacious %s", VERSION);
00695     return TRUE;
00696 }
00697 
00698 gboolean mpris_root_quit(MprisPlayer * obj, GError ** error)
00699 {
00700     event_queue("quit", NULL);
00701     return TRUE;
00702 }
00703 
00704 // MPRIS /Player
00705 
00706 gboolean mpris_player_next(MprisPlayer * obj, GError * *error)
00707 {
00708     g_timeout_add(0, next_cb, NULL);
00709     return TRUE;
00710 }
00711 
00712 gboolean mpris_player_prev(MprisPlayer * obj, GError * *error)
00713 {
00714     g_timeout_add(0, prev_cb, NULL);
00715     return TRUE;
00716 }
00717 
00718 gboolean mpris_player_pause(MprisPlayer * obj, GError * *error)
00719 {
00720     g_timeout_add(0, pause_cb, NULL);
00721     return TRUE;
00722 }
00723 
00724 gboolean mpris_player_stop(MprisPlayer * obj, GError * *error)
00725 {
00726     g_timeout_add(0, stop_cb, NULL);
00727     return TRUE;
00728 }
00729 
00730 gboolean mpris_player_play(MprisPlayer * obj, GError * *error)
00731 {
00732     g_timeout_add(0, play_cb, NULL);
00733     return TRUE;
00734 }
00735 
00736 gboolean mpris_player_repeat(MprisPlayer * obj, gboolean rpt, GError ** error)
00737 {
00738     fprintf (stderr, "implement me\n");
00739     return TRUE;
00740 }
00741 
00742 static void append_int_value(GValueArray * ar, gint tmp)
00743 {
00744     GValue value;
00745     memset(&value, 0, sizeof(value));
00746     g_value_init(&value, G_TYPE_INT);
00747     g_value_set_int(&value, tmp);
00748     g_value_array_append(ar, &value);
00749 }
00750 
00751 static gint get_playback_status(void)
00752 {
00753     struct StatusRequest request;
00754     get_status(&request);
00755 
00756     return (!request.playing ? MPRIS_STATUS_STOP : request.paused ? MPRIS_STATUS_PAUSE : MPRIS_STATUS_PLAY);
00757 }
00758 
00759 gboolean mpris_player_get_status(MprisPlayer * obj, GValueArray * *status, GError * *error)
00760 {
00761     *status = g_value_array_new(4);
00762 
00763     append_int_value(*status, (gint) get_playback_status());
00764     append_int_value(*status, (gint) cfg.shuffle);
00765     append_int_value(*status, (gint) cfg.no_playlist_advance);
00766     append_int_value(*status, (gint) cfg.repeat);
00767     return TRUE;
00768 }
00769 
00770 gboolean mpris_player_get_metadata(MprisPlayer * obj, GHashTable * *metadata, GError * *error)
00771 {
00772     struct MprisMetadataRequest request = {.playlist = -1,.entry = -1 };
00773 
00774     get_mpris_metadata(&request);
00775     *metadata = request.metadata;
00776     return TRUE;
00777 }
00778 
00779 gboolean mpris_player_get_caps(MprisPlayer * obj, gint * capabilities, GError ** error)
00780 {
00781     *capabilities = MPRIS_CAPS_CAN_GO_NEXT | MPRIS_CAPS_CAN_GO_PREV | MPRIS_CAPS_CAN_PAUSE | MPRIS_CAPS_CAN_PLAY | MPRIS_CAPS_CAN_SEEK | MPRIS_CAPS_CAN_PROVIDE_METADATA | MPRIS_CAPS_PROVIDES_TIMING;
00782     return TRUE;
00783 }
00784 
00785 gboolean mpris_player_volume_set(MprisPlayer * obj, gint vol, GError ** error)
00786 {
00787     drct_set_volume_main (vol);
00788     return TRUE;
00789 }
00790 
00791 gboolean mpris_player_volume_get(MprisPlayer * obj, gint * vol, GError ** error)
00792 {
00793     drct_get_volume_main (vol);
00794     return TRUE;
00795 }
00796 
00797 gboolean mpris_player_position_set(MprisPlayer * obj, gint pos, GError * *error)
00798 {
00799     g_timeout_add(0, seek_cb, GINT_TO_POINTER(pos));
00800     return TRUE;
00801 }
00802 
00803 gboolean mpris_player_position_get(MprisPlayer * obj, gint * pos, GError * *error)
00804 {
00805     struct StatusRequest request;
00806 
00807     get_status(&request);
00808     *pos = request.time;
00809     return TRUE;
00810 }
00811 
00812 // MPRIS /Player signals
00813 gboolean mpris_emit_caps_change(MprisPlayer * obj)
00814 {
00815     g_signal_emit(obj, signals[CAPS_CHANGE_SIG], 0, 0);
00816     return TRUE;
00817 }
00818 
00819 gboolean mpris_emit_track_change(MprisPlayer * obj)
00820 {
00821     gint playlist, entry;
00822     GHashTable *metadata;
00823 
00824     playlist = playlist_get_playing();
00825     entry = playlist_get_position(playlist);
00826     gchar * filename = playlist_entry_get_filename (playlist, entry);
00827     Tuple * tuple = playlist_entry_get_tuple (playlist, entry, FALSE);
00828 
00829     if (filename && tuple)
00830     {
00831         metadata = make_mpris_metadata (filename, tuple);
00832         g_signal_emit (obj, signals[TRACK_CHANGE_SIG], 0, metadata);
00833         g_hash_table_destroy (metadata);
00834     }
00835 
00836     g_free (filename);
00837     if (tuple)
00838         tuple_free (tuple);
00839 
00840     return (filename && tuple);
00841 }
00842 
00843 gboolean mpris_emit_status_change(MprisPlayer * obj, PlaybackStatus status)
00844 {
00845     GValueArray *ar = g_value_array_new(4);
00846 
00847     if (status == MPRIS_STATUS_INVALID)
00848         status = get_playback_status ();
00849 
00850     append_int_value(ar, (gint) status);
00851     append_int_value(ar, (gint) cfg.shuffle);
00852     append_int_value(ar, (gint) cfg.no_playlist_advance);
00853     append_int_value(ar, (gint) cfg.repeat);
00854 
00855     g_signal_emit(obj, signals[STATUS_CHANGE_SIG], 0, ar);
00856     g_value_array_free(ar);
00857     return TRUE;
00858 }
00859 
00860 // MPRIS /TrackList
00861 gboolean mpris_emit_tracklist_change(MprisTrackList * obj, gint playlist)
00862 {
00863     g_signal_emit(obj, tracklist_signals[TRACKLIST_CHANGE_SIG], 0, playlist_entry_count(playlist));
00864     return TRUE;
00865 }
00866 
00867 static void mpris_playlist_update_hook(gpointer unused, MprisTrackList * obj)
00868 {
00869     gint playlist = playlist_get_active();
00870 
00871     mpris_emit_tracklist_change(obj, playlist);
00872 }
00873 
00874 gboolean mpris_tracklist_get_metadata(MprisTrackList * obj, gint pos, GHashTable * *metadata, GError * *error)
00875 {
00876     struct MprisMetadataRequest request = {.playlist = -1,.entry = pos };
00877 
00878     get_mpris_metadata(&request);
00879     *metadata = request.metadata;
00880     return TRUE;
00881 }
00882 
00883 gboolean mpris_tracklist_get_current_track(MprisTrackList * obj, gint * pos, GError * *error)
00884 {
00885     struct PositionRequest request = {.playlist = -1,.entry = -1 };
00886 
00887     get_position(&request);
00888     *pos = request.entry;
00889     return TRUE;
00890 }
00891 
00892 gboolean mpris_tracklist_get_length(MprisTrackList * obj, gint * length, GError * *error)
00893 {
00894     struct PositionRequest request = {.playlist = -1,.entry = -1 };
00895 
00896     get_position(&request);
00897     *length = request.entry_count;
00898     return TRUE;
00899 }
00900 
00901 gboolean mpris_tracklist_add_track(MprisTrackList * obj, gchar * uri, gboolean play, GError * *error)
00902 {
00903     struct AddRequest *request = g_malloc(sizeof(struct AddRequest));
00904 
00905     request->position = -1;
00906     request->filename = g_strdup(uri);
00907     request->play = play;
00908 
00909     g_timeout_add(0, add_cb, request);
00910     return TRUE;
00911 }
00912 
00913 gboolean mpris_tracklist_del_track(MprisTrackList * obj, gint pos, GError * *error)
00914 {
00915     g_timeout_add(0, delete_cb, GINT_TO_POINTER(pos));
00916     return TRUE;
00917 }
00918 
00919 gboolean mpris_tracklist_loop (MprisTrackList * obj, gboolean loop, GError * *
00920  error)
00921 {
00922     g_timeout_add (0, set_repeat_cb, GINT_TO_POINTER (loop));
00923     return TRUE;
00924 }
00925 
00926 gboolean mpris_tracklist_random (MprisTrackList * obj, gboolean random,
00927  GError * * error)
00928 {
00929     g_timeout_add (0, set_shuffle_cb, GINT_TO_POINTER (random));
00930     return TRUE;
00931 }
00932 
00933 // Audacious General Information
00934 gboolean audacious_rc_version(RemoteObject * obj, gchar ** version, GError ** error)
00935 {
00936     *version = g_strdup(VERSION);
00937     return TRUE;
00938 }
00939 
00940 gboolean audacious_rc_quit(RemoteObject * obj, GError * *error)
00941 {
00942     event_queue("quit", NULL);
00943     return TRUE;
00944 }
00945 
00946 gboolean audacious_rc_eject(RemoteObject * obj, GError ** error)
00947 {
00948     interface_show_filebrowser (TRUE);
00949     return TRUE;
00950 }
00951 
00952 gboolean audacious_rc_main_win_visible (RemoteObject * obj,
00953  gboolean * visible, GError ** error)
00954 {
00955     * visible = interface_is_shown ();
00956     return TRUE;
00957 }
00958 
00959 gboolean audacious_rc_show_main_win (RemoteObject * obj, gboolean show,
00960  GError * * error)
00961 {
00962     interface_show (show);
00963     return TRUE;
00964 }
00965 
00966 gboolean audacious_rc_get_tuple_fields(RemoteObject * obj, gchar *** fields, GError ** error)
00967 {
00968     gchar **res = g_new0(gchar *, FIELD_LAST + 1);
00969     gint i;
00970     for (i = 0; i < FIELD_LAST; i++)
00971     {
00972         res[i] = g_strdup(tuple_fields[i].name);
00973     }
00974     *fields = res;
00975 
00976     return TRUE;
00977 }
00978 
00979 
00980 // Playback Information/Manipulation
00981 
00982 gboolean audacious_rc_play(RemoteObject * obj, GError * *error)
00983 {
00984     g_timeout_add(0, play_cb, NULL);
00985     return TRUE;
00986 }
00987 
00988 gboolean audacious_rc_pause(RemoteObject * obj, GError * *error)
00989 {
00990     g_timeout_add(0, pause_cb, NULL);
00991     return TRUE;
00992 }
00993 
00994 gboolean audacious_rc_stop(RemoteObject * obj, GError * *error)
00995 {
00996     g_timeout_add(0, stop_cb, NULL);
00997     return TRUE;
00998 }
00999 
01000 gboolean audacious_rc_playing(RemoteObject * obj, gboolean * is_playing, GError * *error)
01001 {
01002     struct StatusRequest request;
01003 
01004     get_status(&request);
01005     *is_playing = request.playing;
01006     return TRUE;
01007 }
01008 
01009 gboolean audacious_rc_paused(RemoteObject * obj, gboolean * is_paused, GError * *error)
01010 {
01011     struct StatusRequest request;
01012 
01013     get_status(&request);
01014     *is_paused = request.paused;
01015     return TRUE;
01016 }
01017 
01018 gboolean audacious_rc_stopped(RemoteObject * obj, gboolean * is_stopped, GError * *error)
01019 {
01020     struct StatusRequest request;
01021 
01022     get_status(&request);
01023     *is_stopped = !request.playing;
01024     return TRUE;
01025 }
01026 
01027 gboolean audacious_rc_status(RemoteObject * obj, gchar * *status, GError * *error)
01028 {
01029     struct StatusRequest request;
01030 
01031     get_status(&request);
01032     *status = g_strdup(!request.playing ? "stopped" : request.paused ? "paused" : "playing");
01033     return TRUE;
01034 }
01035 
01036 gboolean audacious_rc_info(RemoteObject * obj, gint * rate, gint * freq, gint * nch, GError * *error)
01037 {
01038     struct StatusRequest request;
01039 
01040     get_status(&request);
01041     *rate = request.bitrate;
01042     *freq = request.samplerate;
01043     *nch = request.channels;
01044     return TRUE;
01045 }
01046 
01047 gboolean audacious_rc_time(RemoteObject * obj, gint * time, GError * *error)
01048 {
01049     struct StatusRequest request;
01050 
01051     get_status(&request);
01052     *time = request.time;
01053     return TRUE;
01054 }
01055 
01056 gboolean audacious_rc_seek(RemoteObject * obj, guint pos, GError * *error)
01057 {
01058     g_timeout_add(0, seek_cb, GINT_TO_POINTER(pos));
01059     return TRUE;
01060 }
01061 
01062 gboolean audacious_rc_volume(RemoteObject * obj, gint * vl, gint * vr, GError ** error)
01063 {
01064     drct_get_volume (vl, vr);
01065     return TRUE;
01066 }
01067 
01068 gboolean audacious_rc_set_volume(RemoteObject * obj, gint vl, gint vr, GError ** error)
01069 {
01070     drct_set_volume (vl, vr);
01071     return TRUE;
01072 }
01073 
01074 gboolean audacious_rc_balance(RemoteObject * obj, gint * balance, GError ** error)
01075 {
01076     drct_get_volume_balance (balance);
01077     return TRUE;
01078 }
01079 
01080 // Playlist Information/Manipulation
01081 
01082 gboolean audacious_rc_position(RemoteObject * obj, gint * pos, GError * *error)
01083 {
01084     struct PositionRequest request = {.playlist = -1,.entry = -1 };
01085 
01086     get_position(&request);
01087     *pos = request.entry;
01088     return TRUE;
01089 }
01090 
01091 gboolean audacious_rc_advance(RemoteObject * obj, GError * *error)
01092 {
01093     g_timeout_add(0, next_cb, NULL);
01094     return TRUE;
01095 }
01096 
01097 gboolean audacious_rc_reverse(RemoteObject * obj, GError * *error)
01098 {
01099     g_timeout_add(0, prev_cb, NULL);
01100     return TRUE;
01101 }
01102 
01103 gboolean audacious_rc_length(RemoteObject * obj, gint * length, GError * *error)
01104 {
01105     struct PositionRequest request = {.playlist = -1,.entry = -1 };
01106 
01107     get_position(&request);
01108     *length = request.entry_count;
01109     return TRUE;
01110 }
01111 
01112 gboolean audacious_rc_song_title(RemoteObject * obj, guint pos, gchar * *title, GError * *error)
01113 {
01114     struct InfoRequest request = {.playlist = -1,.entry = pos };
01115 
01116     get_info(&request);
01117     g_free(request.filename);
01118     g_free(request.pltitle);
01119     *title = request.title;
01120     return TRUE;
01121 }
01122 
01123 gboolean audacious_rc_song_filename(RemoteObject * obj, guint pos, gchar * *filename, GError * *error)
01124 {
01125     struct InfoRequest request = {.playlist = -1,.entry = pos };
01126 
01127     get_info(&request);
01128     *filename = request.filename;
01129     g_free(request.title);
01130     g_free(request.pltitle);
01131     return TRUE;
01132 }
01133 
01134 gboolean audacious_rc_song_length(RemoteObject * obj, guint pos, gint * length, GError * *error)
01135 {
01136     audacious_rc_song_frames(obj, pos, length, error);
01137     *length /= 1000;
01138     return TRUE;
01139 }
01140 
01141 gboolean audacious_rc_song_frames(RemoteObject * obj, guint pos, gint * length, GError * *error)
01142 {
01143     struct InfoRequest request = {.playlist = -1,.entry = pos };
01144 
01145     get_info(&request);
01146     g_free(request.filename);
01147     g_free(request.title);
01148     g_free(request.pltitle);
01149     *length = request.length;
01150     return TRUE;
01151 }
01152 
01153 gboolean audacious_rc_song_tuple(RemoteObject * obj, guint pos, gchar * field, GValue * value, GError * *error)
01154 {
01155     struct FieldRequest request = {.playlist = -1,.entry = pos,.field = field };
01156 
01157     get_field(&request);
01158 
01159     if (request.value == NULL)
01160         return FALSE;
01161 
01162     memset(value, 0, sizeof(GValue));
01163     g_value_init(value, G_VALUE_TYPE(request.value));
01164     g_value_copy(request.value, value);
01165     g_value_unset(request.value);
01166     g_free(request.value);
01167     return TRUE;
01168 }
01169 
01170 gboolean audacious_rc_jump(RemoteObject * obj, guint pos, GError * *error)
01171 {
01172     g_timeout_add(0, jump_cb, GINT_TO_POINTER(pos));
01173     return TRUE;
01174 }
01175 
01176 gboolean audacious_rc_add(RemoteObject * obj, gchar * file, GError * *error)
01177 {
01178     return audacious_rc_playlist_ins_url_string(obj, file, -1, error);
01179 }
01180 
01181 gboolean audacious_rc_add_url(RemoteObject * obj, gchar * file, GError * *error)
01182 {
01183     return audacious_rc_playlist_ins_url_string(obj, file, -1, error);
01184 }
01185 
01186 static GList * string_array_to_list (gchar * * strings)
01187 {
01188     GList * list = NULL;
01189 
01190     while (* strings != NULL)
01191         list = g_list_prepend (list, * strings ++);
01192 
01193     return g_list_reverse (list);
01194 }
01195 
01196 gboolean audacious_rc_add_list (RemoteObject * obj, gchar * * filenames,
01197  GError * * error)
01198 {
01199     GList * list = string_array_to_list (filenames);
01200 
01201     drct_pl_add_list (list, -1);
01202     g_list_free (list);
01203     return TRUE;
01204 }
01205 
01206 gboolean audacious_rc_open_list (RemoteObject * obj, gchar * * filenames,
01207  GError * * error)
01208 {
01209     GList * list = string_array_to_list (filenames);
01210 
01211     drct_pl_open_list (list);
01212     g_list_free (list);
01213     return TRUE;
01214 }
01215 
01216 gboolean audacious_rc_open_list_to_temp (RemoteObject * obj, gchar * *
01217  filenames, GError * * error)
01218 {
01219     GList * list = string_array_to_list (filenames);
01220 
01221     drct_pl_open_temp_list (list);
01222     g_list_free (list);
01223     return TRUE;
01224 }
01225 
01226 gboolean audacious_rc_delete(RemoteObject * obj, guint pos, GError * *error)
01227 {
01228     g_timeout_add(0, delete_cb, GINT_TO_POINTER(pos));
01229     return TRUE;
01230 }
01231 
01232 gboolean audacious_rc_clear(RemoteObject * obj, GError * *error)
01233 {
01234     g_timeout_add(0, clear_cb, NULL);
01235     return TRUE;
01236 }
01237 
01238 gboolean audacious_rc_auto_advance(RemoteObject * obj, gboolean * is_advance, GError ** error)
01239 {
01240     *is_advance = !cfg.no_playlist_advance;
01241     return TRUE;
01242 }
01243 
01244 gboolean audacious_rc_toggle_auto_advance(RemoteObject * obj, GError ** error)
01245 {
01246     g_timeout_add (0, set_no_playlist_advance_cb,
01247             GINT_TO_POINTER (! cfg.no_playlist_advance));
01248     return TRUE;
01249 }
01250 
01251 gboolean audacious_rc_repeat(RemoteObject * obj, gboolean * is_repeating, GError ** error)
01252 {
01253     *is_repeating = cfg.repeat;
01254     return TRUE;
01255 }
01256 
01257 gboolean audacious_rc_toggle_repeat (RemoteObject * obj, GError * * error)
01258 {
01259     g_timeout_add (0, set_repeat_cb, GINT_TO_POINTER (! cfg.repeat));
01260     return TRUE;
01261 }
01262 
01263 gboolean audacious_rc_shuffle(RemoteObject * obj, gboolean * is_shuffling, GError ** error)
01264 {
01265     *is_shuffling = cfg.shuffle;
01266     return TRUE;
01267 }
01268 
01269 gboolean audacious_rc_toggle_shuffle (RemoteObject * obj, GError * * error)
01270 {
01271     g_timeout_add (0, set_shuffle_cb, GINT_TO_POINTER (! cfg.shuffle));
01272     return TRUE;
01273 }
01274 
01275 /* New on Oct 5 */
01276 gboolean audacious_rc_show_prefs_box(RemoteObject * obj, gboolean show, GError ** error)
01277 {
01278     event_queue("prefswin show", GINT_TO_POINTER(show));
01279     return TRUE;
01280 }
01281 
01282 gboolean audacious_rc_show_about_box(RemoteObject * obj, gboolean show, GError ** error)
01283 {
01284     event_queue("aboutwin show", GINT_TO_POINTER(show));
01285     return TRUE;
01286 }
01287 
01288 gboolean audacious_rc_show_jtf_box(RemoteObject * obj, gboolean show, GError ** error)
01289 {
01290     if (show)
01291         event_queue("interface show jump to track", NULL);
01292     else
01293         event_queue("interface hide jump to track", NULL);
01294     return TRUE;
01295 }
01296 
01297 gboolean audacious_rc_show_filebrowser(RemoteObject * obj, gboolean show, GError ** error)
01298 {
01299     if (show)
01300         event_queue("filebrowser show", GINT_TO_POINTER(FALSE));
01301     else
01302         event_queue("filebrowser hide", NULL);
01303     return TRUE;
01304 }
01305 
01306 gboolean audacious_rc_play_pause(RemoteObject * obj, GError * *error)
01307 {
01308     g_timeout_add(0, play_pause_cb, NULL);
01309     return TRUE;
01310 }
01311 
01312 gboolean audacious_rc_get_info(RemoteObject * obj, gint * rate, gint * freq, gint * nch, GError * *error)
01313 {
01314     struct StatusRequest request;
01315 
01316     get_status(&request);
01317     *rate = request.bitrate;
01318     *freq = request.samplerate;
01319     *nch = request.channels;
01320     return TRUE;
01321 }
01322 
01323 gboolean audacious_rc_toggle_aot(RemoteObject * obj, gboolean ontop, GError ** error)
01324 {
01325     hook_call("mainwin set always on top", &ontop);
01326     return TRUE;
01327 }
01328 
01329 gboolean audacious_rc_playqueue_add(RemoteObject * obj, gint pos, GError * *error)
01330 {
01331     g_timeout_add(0, add_to_queue_cb, GINT_TO_POINTER(pos));
01332     return TRUE;
01333 }
01334 
01335 gboolean audacious_rc_playqueue_remove(RemoteObject * obj, gint pos, GError * *error)
01336 {
01337     g_timeout_add(0, remove_from_queue_cb, GINT_TO_POINTER(pos));
01338     return TRUE;
01339 }
01340 
01341 gboolean audacious_rc_playqueue_clear(RemoteObject * obj, GError * *error)
01342 {
01343     g_timeout_add(0, clear_queue_cb, NULL);
01344     return TRUE;
01345 }
01346 
01347 gboolean audacious_rc_get_playqueue_length(RemoteObject * obj, gint * length, GError * *error)
01348 {
01349     struct PositionRequest request = {.playlist = -1,.entry = -1 };
01350 
01351     get_position(&request);
01352     *length = request.queue_count;
01353     return TRUE;
01354 }
01355 
01356 gboolean audacious_rc_queue_get_list_pos(RemoteObject * obj, gint qpos, gint * pos, GError * *error)
01357 {
01358     *pos = queue_get_entry(qpos);
01359     return TRUE;
01360 }
01361 
01362 gboolean audacious_rc_queue_get_queue_pos(RemoteObject * obj, gint pos, gint * qpos, GError * *error)
01363 {
01364     *qpos = queue_find_entry(pos);
01365     return TRUE;
01366 }
01367 
01368 gboolean audacious_rc_playqueue_is_queued(RemoteObject * obj, gint pos, gboolean * is_queued, GError * *error)
01369 {
01370     *is_queued = (queue_find_entry(pos) != -1);
01371     return TRUE;
01372 }
01373 
01374 gboolean audacious_rc_playlist_ins_url_string(RemoteObject * obj, gchar * url, gint pos, GError * *error)
01375 {
01376     struct AddRequest *request = g_malloc(sizeof(struct AddRequest));
01377 
01378     request->position = pos;
01379     request->filename = g_strdup(url);
01380     request->play = FALSE;
01381 
01382     g_timeout_add(0, add_cb, request);
01383     return TRUE;
01384 }
01385 
01386 gboolean audacious_rc_playlist_add(RemoteObject * obj, void *list, GError * *error)
01387 {
01388     return audacious_rc_playlist_ins_url_string(obj, list, -1, error);
01389 }
01390 
01391 gboolean audacious_rc_playlist_enqueue_to_temp(RemoteObject * obj, gchar * url, GError * *error)
01392 {
01393     g_timeout_add(0, add_to_new_playlist_cb, g_strdup(url));
01394     return TRUE;
01395 }
01396 
01397 /* New on Nov 7: Equalizer */
01398 gboolean audacious_rc_get_eq(RemoteObject * obj, gdouble * preamp, GArray ** bands, GError ** error)
01399 {
01400     int i;
01401 
01402     * preamp = cfg.equalizer_preamp;
01403     *bands = g_array_sized_new(FALSE, FALSE, sizeof(gdouble), AUD_EQUALIZER_NBANDS);
01404 
01405     for (i = 0; i < AUD_EQUALIZER_NBANDS; i++)
01406         g_array_append_val (* bands, cfg.equalizer_bands[i]);
01407 
01408     return TRUE;
01409 }
01410 
01411 gboolean audacious_rc_get_eq_preamp(RemoteObject * obj, gdouble * preamp, GError ** error)
01412 {
01413     * preamp = cfg.equalizer_preamp;
01414     return TRUE;
01415 }
01416 
01417 gboolean audacious_rc_get_eq_band(RemoteObject * obj, gint band, gdouble * value, GError ** error)
01418 {
01419     * value = cfg.equalizer_bands[band];
01420     return TRUE;
01421 }
01422 
01423 gboolean audacious_rc_set_eq(RemoteObject * obj, gdouble preamp, GArray * bands, GError ** error)
01424 {
01425     int i;
01426 
01427     cfg.equalizer_preamp = preamp;
01428 
01429     for (i = 0; i < AUD_EQUALIZER_NBANDS; i++)
01430         cfg.equalizer_bands[i] = g_array_index (bands, gdouble, i);
01431 
01432     hook_call ("equalizer changed", NULL);
01433     return TRUE;
01434 }
01435 
01436 gboolean audacious_rc_set_eq_preamp(RemoteObject * obj, gdouble preamp, GError ** error)
01437 {
01438     cfg.equalizer_preamp = preamp;
01439     hook_call ("equalizer changed", NULL);
01440     return TRUE;
01441 }
01442 
01443 gboolean audacious_rc_set_eq_band(RemoteObject * obj, gint band, gdouble value, GError ** error)
01444 {
01445     cfg.equalizer_bands[band] = value;
01446     hook_call ("equalizer changed", NULL);
01447     return TRUE;
01448 }
01449 
01450 gboolean audacious_rc_equalizer_activate(RemoteObject * obj, gboolean active, GError ** error)
01451 {
01452     cfg.equalizer_active = active;
01453     hook_call ("equalizer changed", NULL);
01454     return TRUE;
01455 }
01456 
01457 gboolean audacious_rc_get_active_playlist_name(RemoteObject * obj, gchar * *title, GError * *error)
01458 {
01459     struct InfoRequest request = {.playlist = -2 };
01460 
01461     get_info(&request);
01462     g_free(request.title);
01463     g_free(request.filename);
01464     *title = request.pltitle;
01465     return TRUE;
01466 }
01467 
01468 DBusGProxy *audacious_get_dbus_proxy(void)
01469 {
01470     DBusGConnection *connection = NULL;
01471     GError *error = NULL;
01472     connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
01473     g_clear_error(&error);
01474     return dbus_g_proxy_new_for_name(connection, AUDACIOUS_DBUS_SERVICE, AUDACIOUS_DBUS_PATH, AUDACIOUS_DBUS_INTERFACE);
01475 }