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 "main.h"
00041 #include "playback.h"
00042 #include "playlist.h"
00043 #include "interface.h"
00044 
00045 struct StatusRequest
00046 {
00047     gboolean playing, paused;
00048     gint time, length;
00049     gint bitrate, samplerate, channels;
00050 };
00051 
00052 struct PositionRequest
00053 {
00054     gint playlist;              /* -1 = active, -2 = playing */
00055     gint entry;                 /* -1 = current */
00056     gint entry_count, queue_count;
00057 };
00058 
00059 struct InfoRequest
00060 {
00061     gint playlist;              /* -1 = active, -2 = playing */
00062     gint entry;                 /* -1 = current */
00063     gchar *filename, *title, *pltitle;
00064     gint length;
00065 };
00066 
00067 struct FieldRequest
00068 {
00069     gint playlist;              /* -1 = active, -2 = playing */
00070     gint entry;                 /* -1 = current */
00071     const gchar *field;
00072     GValue *value;
00073 };
00074 
00075 struct AddRequest
00076 {
00077     gint position;              /* -1 = at end */
00078     gchar *filename;
00079     gboolean play;
00080 };
00081 
00082 struct MprisMetadataRequest
00083 {
00084     gint playlist;              /* -1 = active, -2 = playing */
00085     gint entry;                 /* -1 = current */
00086     GHashTable *metadata;
00087 };
00088 
00089 static DBusGConnection *dbus_conn = NULL;
00090 static guint signals[LAST_SIG] = { 0 };
00091 static guint tracklist_signals[LAST_TRACKLIST_SIG] = { 0 };
00092 
00093 static GThread *main_thread;
00094 static GMutex *info_mutex;
00095 static GCond *info_cond;
00096 
00097 G_DEFINE_TYPE (RemoteObject, audacious_rc, G_TYPE_OBJECT)
00098 G_DEFINE_TYPE (MprisRoot, mpris_root, G_TYPE_OBJECT)
00099 G_DEFINE_TYPE (MprisPlayer, mpris_player, G_TYPE_OBJECT)
00100 G_DEFINE_TYPE (MprisTrackList, mpris_tracklist, G_TYPE_OBJECT)
00101 
00102 #define DBUS_TYPE_G_STRING_VALUE_HASHTABLE (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE))
00103 
00104 static void mpris_playlist_update_hook(gpointer unused, MprisTrackList *obj);
00105 
00106 void audacious_rc_class_init(RemoteObjectClass * klass)
00107 {
00108 }
00109 
00110 void mpris_root_class_init(MprisRootClass * klass)
00111 {
00112 }
00113 
00114 void mpris_player_class_init(MprisPlayerClass * klass)
00115 {
00116     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);
00117     signals[TRACK_CHANGE_SIG] =
00118         g_signal_new("track_change",
00119                      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);
00120     signals[STATUS_CHANGE_SIG] =
00121         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);
00122 }
00123 
00124 void mpris_tracklist_class_init(MprisTrackListClass * klass)
00125 {
00126     tracklist_signals[TRACKLIST_CHANGE_SIG] = g_signal_new("track_list_change", G_OBJECT_CLASS_TYPE(klass),
00127         G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
00128 }
00129 
00130 void audacious_rc_init(RemoteObject * object)
00131 {
00132     GError *error = NULL;
00133     DBusGProxy *driver_proxy;
00134     guint request_ret;
00135 
00136     AUDDBG ("Registering remote D-Bus interfaces.\n");
00137 
00138     dbus_g_object_type_install_info(audacious_rc_get_type(), &dbus_glib_audacious_rc_object_info);
00139 
00140     // Register DBUS path
00141     dbus_g_connection_register_g_object(dbus_conn, AUDACIOUS_DBUS_PATH, G_OBJECT(object));
00142 
00143     // Register the service name, the constants here are defined in
00144     // dbus-glib-bindings.h
00145     driver_proxy = dbus_g_proxy_new_for_name(dbus_conn, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
00146 
00147     if (!org_freedesktop_DBus_request_name(driver_proxy, AUDACIOUS_DBUS_SERVICE, 0, &request_ret, &error))
00148     {
00149         g_warning("Unable to register service: %s", error->message);
00150         g_error_free(error);
00151     }
00152 
00153     if (!org_freedesktop_DBus_request_name(driver_proxy, AUDACIOUS_DBUS_SERVICE_MPRIS, 0, &request_ret, &error))
00154     {
00155         g_warning("Unable to register service: %s", error->message);
00156         g_error_free(error);
00157     }
00158 
00159     g_object_unref(driver_proxy);
00160 }
00161 
00162 void mpris_root_init(MprisRoot * object)
00163 {
00164     dbus_g_object_type_install_info(mpris_root_get_type(), &dbus_glib_mpris_root_object_info);
00165 
00166     // Register DBUS path
00167     dbus_g_connection_register_g_object(dbus_conn, AUDACIOUS_DBUS_PATH_MPRIS_ROOT, G_OBJECT(object));
00168 }
00169 
00170 void mpris_player_init(MprisPlayer * object)
00171 {
00172     dbus_g_object_type_install_info(mpris_player_get_type(), &dbus_glib_mpris_player_object_info);
00173 
00174     // Register DBUS path
00175     dbus_g_connection_register_g_object(dbus_conn, AUDACIOUS_DBUS_PATH_MPRIS_PLAYER, G_OBJECT(object));
00176 
00177     // Add signals
00178     DBusGProxy *proxy = object->proxy;
00179     if (proxy != NULL)
00180     {
00181         dbus_g_proxy_add_signal (proxy, "StatusChange", dbus_g_type_get_struct
00182          ("GValueArray", G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT,
00183          G_TYPE_INVALID), G_TYPE_INVALID);
00184         dbus_g_proxy_add_signal (proxy, "CapsChange", G_TYPE_INT, G_TYPE_INVALID);
00185         dbus_g_proxy_add_signal(proxy, "TrackChange", DBUS_TYPE_G_STRING_VALUE_HASHTABLE, G_TYPE_INVALID);
00186     }
00187     else
00188     {
00189         /* XXX / FIXME: Why does this happen? -- ccr */
00190         AUDDBG ("object->proxy == NULL; not adding some signals.\n");
00191     }
00192 }
00193 
00194 void mpris_tracklist_init(MprisTrackList * object)
00195 {
00196     dbus_g_object_type_install_info(mpris_tracklist_get_type(), &dbus_glib_mpris_tracklist_object_info);
00197 
00198     // Register DBUS path
00199     dbus_g_connection_register_g_object(dbus_conn, AUDACIOUS_DBUS_PATH_MPRIS_TRACKLIST, G_OBJECT(object));
00200 
00201     // Add signals
00202     DBusGProxy *proxy = object->proxy;
00203     if (proxy != NULL)
00204     {
00205         dbus_g_proxy_add_signal(proxy, "TrackListChange", G_TYPE_INT, G_TYPE_INVALID);
00206     }
00207     else
00208     {
00209         /* XXX / FIXME: Why does this happen? -- ccr */
00210         AUDDBG ("object->proxy == NULL, not adding some signals.\n");
00211     }
00212 
00213     hook_associate("playlist update", (HookFunction) mpris_playlist_update_hook, object);
00214 }
00215 
00216 void init_dbus()
00217 {
00218     GError *error = NULL;
00219     DBusConnection *local_conn;
00220 
00221     main_thread = g_thread_self();
00222     info_mutex = g_mutex_new();
00223     info_cond = g_cond_new();
00224 
00225     AUDDBG ("Trying to initialize D-Bus.\n");
00226     dbus_conn = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
00227     if (dbus_conn == NULL)
00228     {
00229         g_warning("Unable to connect to dbus: %s", error->message);
00230         g_error_free(error);
00231         return;
00232     }
00233 
00234     g_type_init();
00235     g_object_new(audacious_rc_get_type(), NULL);
00236     g_object_new(mpris_root_get_type(), NULL);
00237     mpris = g_object_new(mpris_player_get_type(), NULL);
00238     g_object_new(mpris_tracklist_get_type(), NULL);
00239 
00240     local_conn = dbus_g_connection_get_connection(dbus_conn);
00241     dbus_connection_set_exit_on_disconnect(local_conn, FALSE);
00242 }
00243 
00244 static GValue *tuple_value_to_gvalue(const Tuple * tuple, const gchar * key)
00245 {
00246     GValue *val;
00247     TupleValueType type = tuple_get_value_type((Tuple *) tuple, -1, key);
00248 
00249     if (type == TUPLE_STRING)
00250     {
00251         val = g_new0(GValue, 1);
00252         g_value_init(val, G_TYPE_STRING);
00253         g_value_take_string(val, g_strdup(tuple_get_string((Tuple *) tuple, -1, key)));
00254         return val;
00255     }
00256     else if (type == TUPLE_INT)
00257     {
00258         val = g_new0(GValue, 1);
00259         g_value_init(val, G_TYPE_INT);
00260         g_value_set_int(val, tuple_get_int((Tuple *) tuple, -1, key));
00261         return val;
00262     }
00263     return NULL;
00264 }
00265 
00274 static void tuple_insert_to_hash_full(GHashTable * md, const Tuple * tuple,
00275                                       const gchar * tuple_key, const gchar *key)
00276 {
00277     GValue *value = tuple_value_to_gvalue(tuple, tuple_key);
00278     if (value != NULL)
00279         g_hash_table_insert (md, (void *) key, value);
00280 }
00281 
00282 static void tuple_insert_to_hash(GHashTable * md, const Tuple * tuple,
00283                                  const gchar *key)
00284 {
00285     tuple_insert_to_hash_full(md, tuple, key, key);
00286 }
00287 
00288 static void remove_metadata_value(gpointer value)
00289 {
00290     g_value_unset((GValue *) value);
00291     g_free((GValue *) value);
00292 }
00293 
00294 static GHashTable *make_mpris_metadata(const gchar * filename, const Tuple * tuple)
00295 {
00296     GHashTable *md = NULL;
00297     gpointer value;
00298 
00299     md = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, remove_metadata_value);
00300 
00301     value = g_malloc(sizeof(GValue));
00302     memset(value, 0, sizeof(GValue));
00303     g_value_init(value, G_TYPE_STRING);
00304     g_value_take_string(value, g_strdup(filename));
00305     g_hash_table_insert(md, "location", value);
00306 
00307     if (tuple != NULL)
00308     {
00309         tuple_insert_to_hash_full(md, tuple, "length", "mtime");
00310         tuple_insert_to_hash(md, tuple, "title");
00311         tuple_insert_to_hash(md, tuple, "artist");
00312         tuple_insert_to_hash(md, tuple, "album");
00313         tuple_insert_to_hash(md, tuple, "comment");
00314         tuple_insert_to_hash(md, tuple, "genre");
00315         tuple_insert_to_hash(md, tuple, "year");
00316         tuple_insert_to_hash(md, tuple, "codec");
00317         tuple_insert_to_hash(md, tuple, "quality");
00318         tuple_insert_to_hash_full(md, tuple, "track-number", "tracknumber");
00319         tuple_insert_to_hash_full(md, tuple, "bitrate", "audio-bitrate");
00320     }
00321 
00322     return md;
00323 }
00324 
00325 static void real_position(gint * playlist, gint * entry)
00326 {
00327     if (*playlist == -2)
00328         *playlist = playlist_get_playing();
00329     if (*playlist == -1)
00330         *playlist = playlist_get_active();
00331     if (*entry == -1)
00332         *entry = playlist_get_position(*playlist);
00333 }
00334 
00335 static gboolean get_status_cb(void *data)
00336 {
00337     struct StatusRequest *request = data;
00338 
00339     g_mutex_lock(info_mutex);
00340 
00341     memset (request, 0, sizeof (* request));
00342     request->playing = playback_get_playing();
00343 
00344     if (request->playing)
00345     {
00346         request->paused = playback_get_paused ();
00347         request->time = playback_get_time ();
00348         request->length = playback_get_length ();
00349         playback_get_info (& request->bitrate, & request->samplerate,
00350          & request->channels);
00351     }
00352 
00353     g_cond_signal(info_cond);
00354     g_mutex_unlock(info_mutex);
00355     return FALSE;
00356 }
00357 
00358 static void get_status(struct StatusRequest *request)
00359 {
00360     if (g_thread_self() == main_thread)
00361         get_status_cb(request);
00362     else
00363     {
00364         g_mutex_lock(info_mutex);
00365         g_timeout_add(0, get_status_cb, request);
00366         g_cond_wait(info_cond, info_mutex);
00367         g_mutex_unlock(info_mutex);
00368     }
00369 }
00370 
00371 static gboolean get_position_cb(void *data)
00372 {
00373     struct PositionRequest *request = data;
00374 
00375     g_mutex_lock(info_mutex);
00376 
00377     real_position(&request->playlist, &request->entry);
00378     request->entry_count = playlist_entry_count(request->playlist);
00379     request->queue_count = playlist_queue_count(request->playlist);
00380 
00381     g_cond_signal(info_cond);
00382     g_mutex_unlock(info_mutex);
00383     return FALSE;
00384 }
00385 
00386 static void get_position(struct PositionRequest *request)
00387 {
00388     if (g_thread_self() == main_thread)
00389         get_position_cb(request);
00390     else
00391     {
00392         g_mutex_lock(info_mutex);
00393         g_timeout_add(0, get_position_cb, request);
00394         g_cond_wait(info_cond, info_mutex);
00395         g_mutex_unlock(info_mutex);
00396     }
00397 }
00398 
00399 static gboolean get_info_cb(void *data)
00400 {
00401     struct InfoRequest *request = data;
00402     const gchar *filename, *title, *pltitle;
00403 
00404     g_mutex_lock(info_mutex);
00405 
00406     real_position(&request->playlist, &request->entry);
00407     filename = playlist_entry_get_filename(request->playlist, request->entry);
00408     request->filename = (filename == NULL) ? NULL : g_strdup(filename);
00409     title = playlist_entry_get_title (request->playlist, request->entry, FALSE);
00410     request->title = (title == NULL) ? NULL : g_strdup(title);
00411     request->length = playlist_entry_get_length (request->playlist,
00412      request->entry, FALSE);
00413     pltitle = playlist_get_title(request->playlist);
00414     request->pltitle = (pltitle == NULL) ? NULL : g_strdup(pltitle);
00415 
00416     g_cond_signal(info_cond);
00417     g_mutex_unlock(info_mutex);
00418     return FALSE;
00419 }
00420 
00421 static void get_info(struct InfoRequest *request)
00422 {
00423     if (g_thread_self() == main_thread)
00424         get_info_cb(request);
00425     else
00426     {
00427         g_mutex_lock(info_mutex);
00428         g_timeout_add(0, get_info_cb, request);
00429         g_cond_wait(info_cond, info_mutex);
00430         g_mutex_unlock(info_mutex);
00431     }
00432 }
00433 
00434 static gboolean get_field_cb(void *data)
00435 {
00436     struct FieldRequest *request = data;
00437     const Tuple *tuple;
00438 
00439     g_mutex_lock(info_mutex);
00440 
00441     real_position(&request->playlist, &request->entry);
00442     tuple = playlist_entry_get_tuple (request->playlist, request->entry, FALSE);
00443     request->value = (tuple == NULL) ? NULL : tuple_value_to_gvalue(tuple, request->field);
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     const gchar *filename;
00634 
00635     g_mutex_lock(info_mutex);
00636 
00637     real_position(&request->playlist, &request->entry);
00638     filename = playlist_entry_get_filename(request->playlist, request->entry);
00639 
00640     if (filename == NULL)
00641         request->metadata = NULL;
00642     else
00643         request->metadata = make_mpris_metadata (filename,
00644          playlist_entry_get_tuple (request->playlist, request->entry, FALSE));
00645 
00646     g_cond_signal(info_cond);
00647     g_mutex_unlock(info_mutex);
00648     return FALSE;
00649 }
00650 
00651 static void get_mpris_metadata(struct MprisMetadataRequest *request)
00652 {
00653     if (g_thread_self() == main_thread)
00654         get_mpris_metadata_cb(request);
00655     else
00656     {
00657         g_mutex_lock(info_mutex);
00658         g_timeout_add(0, get_mpris_metadata_cb, request);
00659         g_cond_wait(info_cond, info_mutex);
00660         g_mutex_unlock(info_mutex);
00661     }
00662 }
00663 
00664 static gboolean set_shuffle_cb (void * shuffle)
00665 {
00666     cfg.shuffle = GPOINTER_TO_INT (shuffle);
00667     event_queue ("toggle shuffle", NULL);
00668     return FALSE;
00669 }
00670 
00671 static gboolean set_repeat_cb (void * repeat)
00672 {
00673     cfg.repeat = GPOINTER_TO_INT (repeat);
00674     event_queue ("toggle repeat", NULL);
00675     return FALSE;
00676 }
00677 
00678 /* MPRIS API */
00679 // MPRIS /
00680 gboolean mpris_root_identity(MprisRoot * obj, gchar ** identity, GError ** error)
00681 {
00682     *identity = g_strdup_printf("Audacious %s", VERSION);
00683     return TRUE;
00684 }
00685 
00686 gboolean mpris_root_quit(MprisPlayer * obj, GError ** error)
00687 {
00688     event_queue("quit", NULL);
00689     return TRUE;
00690 }
00691 
00692 // MPRIS /Player
00693 
00694 gboolean mpris_player_next(MprisPlayer * obj, GError * *error)
00695 {
00696     g_timeout_add(0, next_cb, NULL);
00697     return TRUE;
00698 }
00699 
00700 gboolean mpris_player_prev(MprisPlayer * obj, GError * *error)
00701 {
00702     g_timeout_add(0, prev_cb, NULL);
00703     return TRUE;
00704 }
00705 
00706 gboolean mpris_player_pause(MprisPlayer * obj, GError * *error)
00707 {
00708     g_timeout_add(0, pause_cb, NULL);
00709     return TRUE;
00710 }
00711 
00712 gboolean mpris_player_stop(MprisPlayer * obj, GError * *error)
00713 {
00714     g_timeout_add(0, stop_cb, NULL);
00715     return TRUE;
00716 }
00717 
00718 gboolean mpris_player_play(MprisPlayer * obj, GError * *error)
00719 {
00720     g_timeout_add(0, play_cb, NULL);
00721     return TRUE;
00722 }
00723 
00724 gboolean mpris_player_repeat(MprisPlayer * obj, gboolean rpt, GError ** error)
00725 {
00726     fprintf (stderr, "implement me\n");
00727     return TRUE;
00728 }
00729 
00730 static void append_int_value(GValueArray * ar, gint tmp)
00731 {
00732     GValue value;
00733     memset(&value, 0, sizeof(value));
00734     g_value_init(&value, G_TYPE_INT);
00735     g_value_set_int(&value, tmp);
00736     g_value_array_append(ar, &value);
00737 }
00738 
00739 static gint get_playback_status(void)
00740 {
00741     struct StatusRequest request;
00742     get_status(&request);
00743 
00744     return (!request.playing ? MPRIS_STATUS_STOP : request.paused ? MPRIS_STATUS_PAUSE : MPRIS_STATUS_PLAY);
00745 }
00746 
00747 gboolean mpris_player_get_status(MprisPlayer * obj, GValueArray * *status, GError * *error)
00748 {
00749     *status = g_value_array_new(4);
00750 
00751     append_int_value(*status, (gint) get_playback_status());
00752     append_int_value(*status, (gint) cfg.shuffle);
00753     append_int_value(*status, (gint) cfg.no_playlist_advance);
00754     append_int_value(*status, (gint) cfg.repeat);
00755     return TRUE;
00756 }
00757 
00758 gboolean mpris_player_get_metadata(MprisPlayer * obj, GHashTable * *metadata, GError * *error)
00759 {
00760     struct MprisMetadataRequest request = {.playlist = -1,.entry = -1 };
00761 
00762     get_mpris_metadata(&request);
00763     *metadata = request.metadata;
00764     return TRUE;
00765 }
00766 
00767 gboolean mpris_player_get_caps(MprisPlayer * obj, gint * capabilities, GError ** error)
00768 {
00769     *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;
00770     return TRUE;
00771 }
00772 
00773 gboolean mpris_player_volume_set(MprisPlayer * obj, gint vol, GError ** error)
00774 {
00775     gint vl, vr, v;
00776 
00777     // get the current volume so we can maintain the balance
00778     input_get_volume(&vl, &vr);
00779 
00780     // sanity check
00781     vl = CLAMP(vl, 0, 100);
00782     vr = CLAMP(vr, 0, 100);
00783     v = CLAMP(vol, 0, 100);
00784 
00785     if (vl > vr)
00786     {
00787         input_set_volume(v, (gint) rint(((gdouble) vr / vl) * v));
00788     }
00789     else if (vl < vr)
00790     {
00791         input_set_volume((gint) rint(((gdouble) vl / vr) * v), v);
00792     }
00793     else
00794     {
00795         input_set_volume(v, v);
00796     }
00797     return TRUE;
00798 }
00799 
00800 gboolean mpris_player_volume_get(MprisPlayer * obj, gint * vol, GError ** error)
00801 {
00802     gint vl, vr;
00803     input_get_volume(&vl, &vr);
00804     // vl and vr may be different depending on the balance; the true volume is
00805     // the maximum of vl or vr.
00806     *vol = MAX(vl, vr);
00807     return TRUE;
00808 }
00809 
00810 gboolean mpris_player_position_set(MprisPlayer * obj, gint pos, GError * *error)
00811 {
00812     g_timeout_add(0, seek_cb, GINT_TO_POINTER(pos));
00813     return TRUE;
00814 }
00815 
00816 gboolean mpris_player_position_get(MprisPlayer * obj, gint * pos, GError * *error)
00817 {
00818     struct StatusRequest request;
00819 
00820     get_status(&request);
00821     *pos = request.time;
00822     return TRUE;
00823 }
00824 
00825 // MPRIS /Player signals
00826 gboolean mpris_emit_caps_change(MprisPlayer * obj)
00827 {
00828     g_signal_emit(obj, signals[CAPS_CHANGE_SIG], 0, 0);
00829     return TRUE;
00830 }
00831 
00832 gboolean mpris_emit_track_change(MprisPlayer * obj)
00833 {
00834     gint playlist, entry;
00835     const gchar *filename;
00836     GHashTable *metadata;
00837 
00838     playlist = playlist_get_playing();
00839     entry = playlist_get_position(playlist);
00840     filename = playlist_entry_get_filename(playlist, entry);
00841 
00842     if (filename == NULL)
00843         return FALSE;
00844 
00845     metadata = make_mpris_metadata (filename, playlist_entry_get_tuple
00846      (playlist, entry, FALSE));
00847 
00848     g_signal_emit(obj, signals[TRACK_CHANGE_SIG], 0, metadata);
00849     g_hash_table_destroy(metadata);
00850     return TRUE;
00851 }
00852 
00853 gboolean mpris_emit_status_change(MprisPlayer * obj, PlaybackStatus status)
00854 {
00855     GValueArray *ar = g_value_array_new(4);
00856 
00857     if (status < 0) status = get_playback_status();
00858     append_int_value(ar, (gint) status);
00859     append_int_value(ar, (gint) cfg.shuffle);
00860     append_int_value(ar, (gint) cfg.no_playlist_advance);
00861     append_int_value(ar, (gint) cfg.repeat);
00862 
00863     g_signal_emit(obj, signals[STATUS_CHANGE_SIG], 0, ar);
00864     g_value_array_free(ar);
00865     return TRUE;
00866 }
00867 
00868 // MPRIS /TrackList
00869 gboolean mpris_emit_tracklist_change(MprisTrackList * obj, gint playlist)
00870 {
00871     g_signal_emit(obj, tracklist_signals[TRACKLIST_CHANGE_SIG], 0, playlist_entry_count(playlist));
00872     return TRUE;
00873 }
00874 
00875 static void mpris_playlist_update_hook(gpointer unused, MprisTrackList * obj)
00876 {
00877     gint playlist = playlist_get_active();
00878 
00879     mpris_emit_tracklist_change(obj, playlist);
00880 }
00881 
00882 gboolean mpris_tracklist_get_metadata(MprisTrackList * obj, gint pos, GHashTable * *metadata, GError * *error)
00883 {
00884     struct MprisMetadataRequest request = {.playlist = -1,.entry = pos };
00885 
00886     get_mpris_metadata(&request);
00887     *metadata = request.metadata;
00888     return TRUE;
00889 }
00890 
00891 gboolean mpris_tracklist_get_current_track(MprisTrackList * obj, gint * pos, GError * *error)
00892 {
00893     struct PositionRequest request = {.playlist = -1,.entry = -1 };
00894 
00895     get_position(&request);
00896     *pos = request.entry;
00897     return TRUE;
00898 }
00899 
00900 gboolean mpris_tracklist_get_length(MprisTrackList * obj, gint * length, GError * *error)
00901 {
00902     struct PositionRequest request = {.playlist = -1,.entry = -1 };
00903 
00904     get_position(&request);
00905     *length = request.entry_count;
00906     return TRUE;
00907 }
00908 
00909 gboolean mpris_tracklist_add_track(MprisTrackList * obj, gchar * uri, gboolean play, GError * *error)
00910 {
00911     struct AddRequest *request = g_malloc(sizeof(struct AddRequest));
00912 
00913     request->position = -1;
00914     request->filename = g_strdup(uri);
00915     request->play = play;
00916 
00917     g_timeout_add(0, add_cb, request);
00918     return TRUE;
00919 }
00920 
00921 gboolean mpris_tracklist_del_track(MprisTrackList * obj, gint pos, GError * *error)
00922 {
00923     g_timeout_add(0, delete_cb, GINT_TO_POINTER(pos));
00924     return TRUE;
00925 }
00926 
00927 gboolean mpris_tracklist_loop (MprisTrackList * obj, gboolean loop, GError * *
00928  error)
00929 {
00930     g_timeout_add (0, set_repeat_cb, GINT_TO_POINTER (loop));
00931     return TRUE;
00932 }
00933 
00934 gboolean mpris_tracklist_random (MprisTrackList * obj, gboolean random,
00935  GError * * error)
00936 {
00937     g_timeout_add (0, set_shuffle_cb, GINT_TO_POINTER (random));
00938     return TRUE;
00939 }
00940 
00941 // Audacious General Information
00942 gboolean audacious_rc_version(RemoteObject * obj, gchar ** version, GError ** error)
00943 {
00944     *version = g_strdup(VERSION);
00945     return TRUE;
00946 }
00947 
00948 gboolean audacious_rc_quit(RemoteObject * obj, GError * *error)
00949 {
00950     event_queue("quit", NULL);
00951     return TRUE;
00952 }
00953 
00954 gboolean audacious_rc_eject(RemoteObject * obj, GError ** error)
00955 {
00956     interface_run_filebrowser (TRUE);
00957     return TRUE;
00958 }
00959 
00960 gboolean audacious_rc_main_win_visible(RemoteObject * obj, gboolean * is_main_win, GError ** error)
00961 {
00962     *is_main_win = cfg.player_visible;
00963     return TRUE;
00964 }
00965 
00966 gboolean audacious_rc_show_main_win(RemoteObject * obj, gboolean show, GError ** error)
00967 {
00968     interface_toggle_visibility ();
00969     return TRUE;
00970 }
00971 
00972 gboolean audacious_rc_equalizer_visible(RemoteObject * obj, gboolean * is_eq_win, GError ** error)
00973 {
00974     *is_eq_win = cfg.equalizer_visible;
00975     return TRUE;
00976 }
00977 
00978 gboolean audacious_rc_show_equalizer(RemoteObject * obj, gboolean show, GError ** error)
00979 {
00980 #if 0
00981     drct_eq_win_toggle(show);
00982 #endif
00983     return TRUE;
00984 }
00985 
00986 gboolean audacious_rc_playlist_visible(RemoteObject * obj, gboolean * is_pl_win, GError ** error)
00987 {
00988     *is_pl_win = cfg.playlist_visible;
00989     return TRUE;
00990 }
00991 
00992 gboolean audacious_rc_show_playlist(RemoteObject * obj, gboolean show, GError ** error)
00993 {
00994 #if 0
00995     drct_pl_win_toggle(show);
00996 #endif
00997     return TRUE;
00998 }
00999 
01000 gboolean audacious_rc_get_tuple_fields(RemoteObject * obj, gchar *** fields, GError ** error)
01001 {
01002     gchar **res = g_new0(gchar *, FIELD_LAST + 1);
01003     gint i;
01004     for (i = 0; i < FIELD_LAST; i++)
01005     {
01006         res[i] = g_strdup(tuple_fields[i].name);
01007     }
01008     *fields = res;
01009 
01010     return TRUE;
01011 }
01012 
01013 
01014 // Playback Information/Manipulation
01015 
01016 gboolean audacious_rc_play(RemoteObject * obj, GError * *error)
01017 {
01018     g_timeout_add(0, play_cb, NULL);
01019     return TRUE;
01020 }
01021 
01022 gboolean audacious_rc_pause(RemoteObject * obj, GError * *error)
01023 {
01024     g_timeout_add(0, pause_cb, NULL);
01025     return TRUE;
01026 }
01027 
01028 gboolean audacious_rc_stop(RemoteObject * obj, GError * *error)
01029 {
01030     g_timeout_add(0, stop_cb, NULL);
01031     return TRUE;
01032 }
01033 
01034 gboolean audacious_rc_playing(RemoteObject * obj, gboolean * is_playing, GError * *error)
01035 {
01036     struct StatusRequest request;
01037 
01038     get_status(&request);
01039     *is_playing = request.playing;
01040     return TRUE;
01041 }
01042 
01043 gboolean audacious_rc_paused(RemoteObject * obj, gboolean * is_paused, GError * *error)
01044 {
01045     struct StatusRequest request;
01046 
01047     get_status(&request);
01048     *is_paused = request.paused;
01049     return TRUE;
01050 }
01051 
01052 gboolean audacious_rc_stopped(RemoteObject * obj, gboolean * is_stopped, GError * *error)
01053 {
01054     struct StatusRequest request;
01055 
01056     get_status(&request);
01057     *is_stopped = !request.playing;
01058     return TRUE;
01059 }
01060 
01061 gboolean audacious_rc_status(RemoteObject * obj, gchar * *status, GError * *error)
01062 {
01063     struct StatusRequest request;
01064 
01065     get_status(&request);
01066     *status = g_strdup(!request.playing ? "stopped" : request.paused ? "paused" : "playing");
01067     return TRUE;
01068 }
01069 
01070 gboolean audacious_rc_info(RemoteObject * obj, gint * rate, gint * freq, gint * nch, GError * *error)
01071 {
01072     struct StatusRequest request;
01073 
01074     get_status(&request);
01075     *rate = request.bitrate;
01076     *freq = request.samplerate;
01077     *nch = request.channels;
01078     return TRUE;
01079 }
01080 
01081 gboolean audacious_rc_time(RemoteObject * obj, gint * time, GError * *error)
01082 {
01083     struct StatusRequest request;
01084 
01085     get_status(&request);
01086     *time = request.time;
01087     return TRUE;
01088 }
01089 
01090 gboolean audacious_rc_seek(RemoteObject * obj, guint pos, GError * *error)
01091 {
01092     g_timeout_add(0, seek_cb, GINT_TO_POINTER(pos));
01093     return TRUE;
01094 }
01095 
01096 gboolean audacious_rc_volume(RemoteObject * obj, gint * vl, gint * vr, GError ** error)
01097 {
01098     input_get_volume(vl, vr);
01099     return TRUE;
01100 }
01101 
01102 gboolean audacious_rc_set_volume(RemoteObject * obj, gint vl, gint vr, GError ** error)
01103 {
01104     if (vl > 100)
01105         vl = 100;
01106     if (vr > 100)
01107         vr = 100;
01108     input_set_volume(vl, vr);
01109     return TRUE;
01110 }
01111 
01112 gboolean audacious_rc_balance(RemoteObject * obj, gint * balance, GError ** error)
01113 {
01114     gint vl, vr;
01115     input_get_volume(&vl, &vr);
01116     if (vl < 0 || vr < 0)
01117         *balance = 0;
01118     else if (vl > vr)
01119         *balance = -100 + ((vr * 100) / vl);
01120     else if (vr > vl)
01121         *balance = 100 - ((vl * 100) / vr);
01122     else
01123         *balance = 0;
01124     return TRUE;
01125 }
01126 
01127 // Playlist Information/Manipulation
01128 
01129 gboolean audacious_rc_position(RemoteObject * obj, gint * pos, GError * *error)
01130 {
01131     struct PositionRequest request = {.playlist = -1,.entry = -1 };
01132 
01133     get_position(&request);
01134     *pos = request.entry;
01135     return TRUE;
01136 }
01137 
01138 gboolean audacious_rc_advance(RemoteObject * obj, GError * *error)
01139 {
01140     g_timeout_add(0, next_cb, NULL);
01141     return TRUE;
01142 }
01143 
01144 gboolean audacious_rc_reverse(RemoteObject * obj, GError * *error)
01145 {
01146     g_timeout_add(0, prev_cb, NULL);
01147     return TRUE;
01148 }
01149 
01150 gboolean audacious_rc_length(RemoteObject * obj, gint * length, GError * *error)
01151 {
01152     struct PositionRequest request = {.playlist = -1,.entry = -1 };
01153 
01154     get_position(&request);
01155     *length = request.entry_count;
01156     return TRUE;
01157 }
01158 
01159 gboolean audacious_rc_song_title(RemoteObject * obj, guint pos, gchar * *title, GError * *error)
01160 {
01161     struct InfoRequest request = {.playlist = -1,.entry = pos };
01162 
01163     get_info(&request);
01164     g_free(request.filename);
01165     g_free(request.pltitle);
01166     *title = request.title;
01167     return TRUE;
01168 }
01169 
01170 gboolean audacious_rc_song_filename(RemoteObject * obj, guint pos, gchar * *filename, GError * *error)
01171 {
01172     struct InfoRequest request = {.playlist = -1,.entry = pos };
01173 
01174     get_info(&request);
01175     *filename = request.filename;
01176     g_free(request.title);
01177     g_free(request.pltitle);
01178     return TRUE;
01179 }
01180 
01181 gboolean audacious_rc_song_length(RemoteObject * obj, guint pos, gint * length, GError * *error)
01182 {
01183     audacious_rc_song_frames(obj, pos, length, error);
01184     *length /= 1000;
01185     return TRUE;
01186 }
01187 
01188 gboolean audacious_rc_song_frames(RemoteObject * obj, guint pos, gint * length, GError * *error)
01189 {
01190     struct InfoRequest request = {.playlist = -1,.entry = pos };
01191 
01192     get_info(&request);
01193     g_free(request.filename);
01194     g_free(request.title);
01195     g_free(request.pltitle);
01196     *length = request.length;
01197     return TRUE;
01198 }
01199 
01200 gboolean audacious_rc_song_tuple(RemoteObject * obj, guint pos, gchar * field, GValue * value, GError * *error)
01201 {
01202     struct FieldRequest request = {.playlist = -1,.entry = pos,.field = field };
01203 
01204     get_field(&request);
01205 
01206     if (request.value == NULL)
01207         return FALSE;
01208 
01209     memset(value, 0, sizeof(GValue));
01210     g_value_init(value, G_VALUE_TYPE(request.value));
01211     g_value_copy(request.value, value);
01212     g_value_unset(request.value);
01213     g_free(request.value);
01214     return TRUE;
01215 }
01216 
01217 gboolean audacious_rc_jump(RemoteObject * obj, guint pos, GError * *error)
01218 {
01219     g_timeout_add(0, jump_cb, GINT_TO_POINTER(pos));
01220     return TRUE;
01221 }
01222 
01223 gboolean audacious_rc_add(RemoteObject * obj, gchar * file, GError * *error)
01224 {
01225     return audacious_rc_playlist_ins_url_string(obj, file, -1, error);
01226 }
01227 
01228 gboolean audacious_rc_add_url(RemoteObject * obj, gchar * file, GError * *error)
01229 {
01230     return audacious_rc_playlist_ins_url_string(obj, file, -1, error);
01231 }
01232 
01233 static GList * string_array_to_list (gchar * * strings)
01234 {
01235     GList * list = NULL;
01236 
01237     while (* strings != NULL)
01238         list = g_list_prepend (list, * strings ++);
01239 
01240     return g_list_reverse (list);
01241 }
01242 
01243 gboolean audacious_rc_add_list (RemoteObject * obj, gchar * * filenames,
01244  GError * * error)
01245 {
01246     GList * list = string_array_to_list (filenames);
01247 
01248     drct_pl_add_list (list, -1);
01249     g_list_free (list);
01250     return TRUE;
01251 }
01252 
01253 gboolean audacious_rc_open_list (RemoteObject * obj, gchar * * filenames,
01254  GError * * error)
01255 {
01256     GList * list = string_array_to_list (filenames);
01257 
01258     drct_pl_open_list (list);
01259     g_list_free (list);
01260     return TRUE;
01261 }
01262 
01263 gboolean audacious_rc_open_list_to_temp (RemoteObject * obj, gchar * *
01264  filenames, GError * * error)
01265 {
01266     GList * list = string_array_to_list (filenames);
01267 
01268     drct_pl_open_temp_list (list);
01269     g_list_free (list);
01270     return TRUE;
01271 }
01272 
01273 gboolean audacious_rc_delete(RemoteObject * obj, guint pos, GError * *error)
01274 {
01275     g_timeout_add(0, delete_cb, GINT_TO_POINTER(pos));
01276     return TRUE;
01277 }
01278 
01279 gboolean audacious_rc_clear(RemoteObject * obj, GError * *error)
01280 {
01281     g_timeout_add(0, clear_cb, NULL);
01282     return TRUE;
01283 }
01284 
01285 gboolean audacious_rc_auto_advance(RemoteObject * obj, gboolean * is_advance, GError ** error)
01286 {
01287     *is_advance = !cfg.no_playlist_advance;
01288     return TRUE;
01289 }
01290 
01291 gboolean audacious_rc_toggle_auto_advance(RemoteObject * obj, GError ** error)
01292 {
01293     cfg.no_playlist_advance = !cfg.no_playlist_advance;
01294     return TRUE;
01295 }
01296 
01297 gboolean audacious_rc_repeat(RemoteObject * obj, gboolean * is_repeating, GError ** error)
01298 {
01299     *is_repeating = cfg.repeat;
01300     return TRUE;
01301 }
01302 
01303 gboolean audacious_rc_toggle_repeat (RemoteObject * obj, GError * * error)
01304 {
01305     g_timeout_add (0, set_repeat_cb, GINT_TO_POINTER (! cfg.repeat));
01306     return TRUE;
01307 }
01308 
01309 gboolean audacious_rc_shuffle(RemoteObject * obj, gboolean * is_shuffling, GError ** error)
01310 {
01311     *is_shuffling = cfg.shuffle;
01312     return TRUE;
01313 }
01314 
01315 gboolean audacious_rc_toggle_shuffle (RemoteObject * obj, GError * * error)
01316 {
01317     g_timeout_add (0, set_shuffle_cb, GINT_TO_POINTER (! cfg.shuffle));
01318     return TRUE;
01319 }
01320 
01321 /* New on Oct 5 */
01322 gboolean audacious_rc_show_prefs_box(RemoteObject * obj, gboolean show, GError ** error)
01323 {
01324     event_queue("prefswin show", GINT_TO_POINTER(show));
01325     return TRUE;
01326 }
01327 
01328 gboolean audacious_rc_show_about_box(RemoteObject * obj, gboolean show, GError ** error)
01329 {
01330     event_queue("aboutwin show", GINT_TO_POINTER(show));
01331     return TRUE;
01332 }
01333 
01334 gboolean audacious_rc_show_jtf_box(RemoteObject * obj, gboolean show, GError ** error)
01335 {
01336     if (show)
01337         event_queue("interface show jump to track", NULL);
01338     else
01339         event_queue("interface hide jump to track", NULL);
01340     return TRUE;
01341 }
01342 
01343 gboolean audacious_rc_show_filebrowser(RemoteObject * obj, gboolean show, GError ** error)
01344 {
01345     if (show)
01346         event_queue("filebrowser show", GINT_TO_POINTER(FALSE));
01347     else
01348         event_queue("filebrowser hide", NULL);
01349     return TRUE;
01350 }
01351 
01352 gboolean audacious_rc_play_pause(RemoteObject * obj, GError * *error)
01353 {
01354     g_timeout_add(0, play_pause_cb, NULL);
01355     return TRUE;
01356 }
01357 
01358 gboolean audacious_rc_activate(RemoteObject * obj, GError ** error)
01359 {
01360     fprintf (stderr, "implement me\n");
01361     return TRUE;
01362 }
01363 
01364 gboolean audacious_rc_get_info(RemoteObject * obj, gint * rate, gint * freq, gint * nch, GError * *error)
01365 {
01366     struct StatusRequest request;
01367 
01368     get_status(&request);
01369     *rate = request.bitrate;
01370     *freq = request.samplerate;
01371     *nch = request.channels;
01372     return TRUE;
01373 }
01374 
01375 gboolean audacious_rc_toggle_aot(RemoteObject * obj, gboolean ontop, GError ** error)
01376 {
01377     hook_call("mainwin set always on top", &ontop);
01378     return TRUE;
01379 }
01380 
01381 gboolean audacious_rc_playqueue_add(RemoteObject * obj, gint pos, GError * *error)
01382 {
01383     g_timeout_add(0, add_to_queue_cb, GINT_TO_POINTER(pos));
01384     return TRUE;
01385 }
01386 
01387 gboolean audacious_rc_playqueue_remove(RemoteObject * obj, gint pos, GError * *error)
01388 {
01389     g_timeout_add(0, remove_from_queue_cb, GINT_TO_POINTER(pos));
01390     return TRUE;
01391 }
01392 
01393 gboolean audacious_rc_playqueue_clear(RemoteObject * obj, GError * *error)
01394 {
01395     g_timeout_add(0, clear_queue_cb, NULL);
01396     return TRUE;
01397 }
01398 
01399 gboolean audacious_rc_get_playqueue_length(RemoteObject * obj, gint * length, GError * *error)
01400 {
01401     struct PositionRequest request = {.playlist = -1,.entry = -1 };
01402 
01403     get_position(&request);
01404     *length = request.queue_count;
01405     return TRUE;
01406 }
01407 
01408 gboolean audacious_rc_queue_get_list_pos(RemoteObject * obj, gint qpos, gint * pos, GError * *error)
01409 {
01410     *pos = queue_get_entry(qpos);
01411     return TRUE;
01412 }
01413 
01414 gboolean audacious_rc_queue_get_queue_pos(RemoteObject * obj, gint pos, gint * qpos, GError * *error)
01415 {
01416     *qpos = queue_find_entry(pos);
01417     return TRUE;
01418 }
01419 
01420 gboolean audacious_rc_playqueue_is_queued(RemoteObject * obj, gint pos, gboolean * is_queued, GError * *error)
01421 {
01422     *is_queued = (queue_find_entry(pos) != -1);
01423     return TRUE;
01424 }
01425 
01426 gboolean audacious_rc_playlist_ins_url_string(RemoteObject * obj, gchar * url, gint pos, GError * *error)
01427 {
01428     struct AddRequest *request = g_malloc(sizeof(struct AddRequest));
01429 
01430     request->position = pos;
01431     request->filename = g_strdup(url);
01432     request->play = FALSE;
01433 
01434     g_timeout_add(0, add_cb, request);
01435     return TRUE;
01436 }
01437 
01438 gboolean audacious_rc_playlist_add(RemoteObject * obj, void *list, GError * *error)
01439 {
01440     return audacious_rc_playlist_ins_url_string(obj, list, -1, error);
01441 }
01442 
01443 gboolean audacious_rc_playlist_enqueue_to_temp(RemoteObject * obj, gchar * url, GError * *error)
01444 {
01445     g_timeout_add(0, add_to_new_playlist_cb, g_strdup(url));
01446     return TRUE;
01447 }
01448 
01449 /* New on Nov 7: Equalizer */
01450 gboolean audacious_rc_get_eq(RemoteObject * obj, gdouble * preamp, GArray ** bands, GError ** error)
01451 {
01452     int i;
01453 
01454     * preamp = cfg.equalizer_preamp;
01455     *bands = g_array_sized_new(FALSE, FALSE, sizeof(gdouble), AUD_EQUALIZER_NBANDS);
01456 
01457     for (i = 0; i < AUD_EQUALIZER_NBANDS; i++)
01458         g_array_append_val (* bands, cfg.equalizer_bands[i]);
01459 
01460     return TRUE;
01461 }
01462 
01463 gboolean audacious_rc_get_eq_preamp(RemoteObject * obj, gdouble * preamp, GError ** error)
01464 {
01465     * preamp = cfg.equalizer_preamp;
01466     return TRUE;
01467 }
01468 
01469 gboolean audacious_rc_get_eq_band(RemoteObject * obj, gint band, gdouble * value, GError ** error)
01470 {
01471     * value = cfg.equalizer_bands[band];
01472     return TRUE;
01473 }
01474 
01475 gboolean audacious_rc_set_eq(RemoteObject * obj, gdouble preamp, GArray * bands, GError ** error)
01476 {
01477     int i;
01478 
01479     cfg.equalizer_preamp = preamp;
01480 
01481     for (i = 0; i < AUD_EQUALIZER_NBANDS; i++)
01482         cfg.equalizer_bands[i] = g_array_index (bands, gdouble, i);
01483 
01484     hook_call ("equalizer changed", NULL);
01485     return TRUE;
01486 }
01487 
01488 gboolean audacious_rc_set_eq_preamp(RemoteObject * obj, gdouble preamp, GError ** error)
01489 {
01490     cfg.equalizer_preamp = preamp;
01491     hook_call ("equalizer changed", NULL);
01492     return TRUE;
01493 }
01494 
01495 gboolean audacious_rc_set_eq_band(RemoteObject * obj, gint band, gdouble value, GError ** error)
01496 {
01497     cfg.equalizer_bands[band] = value;
01498     hook_call ("equalizer changed", NULL);
01499     return TRUE;
01500 }
01501 
01502 gboolean audacious_rc_equalizer_activate(RemoteObject * obj, gboolean active, GError ** error)
01503 {
01504     cfg.equalizer_active = active;
01505     hook_call ("equalizer changed", NULL);
01506     return TRUE;
01507 }
01508 
01509 gboolean audacious_rc_get_active_playlist_name(RemoteObject * obj, gchar * *title, GError * *error)
01510 {
01511     struct InfoRequest request = {.playlist = -2 };
01512 
01513     get_info(&request);
01514     g_free(request.title);
01515     g_free(request.filename);
01516     *title = request.pltitle;
01517     return TRUE;
01518 }
01519 
01520 DBusGProxy *audacious_get_dbus_proxy(void)
01521 {
01522     DBusGConnection *connection = NULL;
01523     GError *error = NULL;
01524     connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
01525     g_clear_error(&error);
01526     return dbus_g_proxy_new_for_name(connection, AUDACIOUS_DBUS_SERVICE, AUDACIOUS_DBUS_PATH, AUDACIOUS_DBUS_INTERFACE);
01527 }