Line 0
Link Here
|
|
|
1 |
/* logjam - a GTK client for LiveJournal. |
2 |
* Copyright (C) 2009 Andy Shevchenko <andy@smile.org.ua> |
3 |
* |
4 |
* vim: tabstop=4 shiftwidth=4 noexpandtab : |
5 |
* |
6 |
* See http://wiki.xmms2.xmms.se/wiki/MPRIS for MRPIS specification |
7 |
*/ |
8 |
|
9 |
#include <string.h> /* memset */ |
10 |
|
11 |
#include "lj_dbus.h" |
12 |
|
13 |
#define MPRIS_IF "org.freedesktop.MediaPlayer" |
14 |
|
15 |
/* Internal prototypes */ |
16 |
static gboolean lj_dbus_open(JamDBus *jd); |
17 |
static gboolean lj_dbus_append_player(JamDBus *jd, gchar *dest); |
18 |
static void lj_dbus_players_clear(JamDBus *jd); |
19 |
static gboolean lj_dbus_players_find(JamDBus *jd, GError **error); |
20 |
|
21 |
/* Implementation */ |
22 |
static gboolean |
23 |
lj_dbus_open(JamDBus *jd) { |
24 |
GError *error = NULL; |
25 |
|
26 |
jd->bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error); |
27 |
if (jd->bus == NULL) { |
28 |
g_printerr("Failed to open connection to bus: %s\n", error->message); |
29 |
g_error_free(error); |
30 |
return FALSE; |
31 |
} |
32 |
return TRUE; |
33 |
} |
34 |
|
35 |
void lj_dbus_close(JamDBus *jd) { |
36 |
if (jd == NULL) |
37 |
return; |
38 |
lj_dbus_players_clear(jd); |
39 |
dbus_g_connection_unref(jd->bus); |
40 |
} |
41 |
|
42 |
JamDBus * |
43 |
lj_dbus_new(void) { |
44 |
JamDBus *jd = (JamDBus *) g_malloc0(sizeof(JamDBus)); |
45 |
|
46 |
if (lj_dbus_open(jd) == FALSE) { |
47 |
g_free(jd); |
48 |
return NULL; |
49 |
} |
50 |
return jd; |
51 |
} |
52 |
|
53 |
static gboolean |
54 |
lj_dbus_append_player(JamDBus *jd, gchar *dest) { |
55 |
MediaPlayer *player; |
56 |
DBusGProxy *proxy; |
57 |
GError *error = NULL; |
58 |
gchar *name; |
59 |
|
60 |
proxy = dbus_g_proxy_new_for_name(jd->bus, dest, "/", MPRIS_IF); |
61 |
|
62 |
if (!dbus_g_proxy_call(proxy, "Identity", &error, G_TYPE_INVALID, |
63 |
G_TYPE_STRING, &name, G_TYPE_INVALID)) { |
64 |
g_printerr("Error: %s\n", error->message); |
65 |
g_error_free(error); |
66 |
return FALSE; |
67 |
} |
68 |
|
69 |
player = (MediaPlayer *) g_malloc0(sizeof(MediaPlayer)); |
70 |
player->dest = g_strdup(dest); |
71 |
player->name = g_strdup(name); |
72 |
player->proxy = dbus_g_proxy_new_for_name(jd->bus, dest, "/Player", MPRIS_IF); |
73 |
|
74 |
if (g_str_has_suffix(dest, "audacious")) |
75 |
player->hint |= MPRIS_HINT_BAD_STATUS; |
76 |
|
77 |
jd->player = g_list_append(jd->player, (gpointer) player); |
78 |
|
79 |
g_free(name); |
80 |
g_object_unref(proxy); |
81 |
|
82 |
return TRUE; |
83 |
} |
84 |
|
85 |
static void |
86 |
lj_dbus_players_clear(JamDBus *jd) { |
87 |
GList *list; |
88 |
|
89 |
if (jd->player == NULL) |
90 |
return; |
91 |
|
92 |
for (list = g_list_first(jd->player); list; list = g_list_next(list)) { |
93 |
MediaPlayer *player = (MediaPlayer *) list->data; |
94 |
g_object_unref(player->proxy); |
95 |
if (player->name) |
96 |
g_free(player->name); |
97 |
if (player->dest) |
98 |
g_free(player->dest); |
99 |
} |
100 |
g_list_free(jd->player); |
101 |
jd->player = NULL; |
102 |
} |
103 |
|
104 |
static gboolean |
105 |
lj_dbus_players_find(JamDBus *jd, GError **error) { |
106 |
DBusGProxy *proxy; |
107 |
gchar **names, **p; |
108 |
|
109 |
proxy = dbus_g_proxy_new_for_name(jd->bus, |
110 |
DBUS_SERVICE_DBUS, |
111 |
DBUS_PATH_DBUS, |
112 |
DBUS_INTERFACE_DBUS); |
113 |
|
114 |
if (!dbus_g_proxy_call(proxy, "ListNames", error, G_TYPE_INVALID, |
115 |
G_TYPE_STRV, &names, G_TYPE_INVALID)) { |
116 |
return FALSE; |
117 |
} |
118 |
|
119 |
for (p = names; *p; p++) { |
120 |
if (g_str_has_prefix(*p, "org.mpris.")) { |
121 |
lj_dbus_append_player(jd, *p); |
122 |
} |
123 |
} |
124 |
|
125 |
g_strfreev(names); |
126 |
g_object_unref(proxy); |
127 |
|
128 |
return TRUE; |
129 |
} |
130 |
|
131 |
gboolean |
132 |
lj_dbus_mpris_update_list(JamDBus *jd, GError **error) { |
133 |
if (jd == NULL) |
134 |
return FALSE; |
135 |
lj_dbus_players_clear(jd); |
136 |
return lj_dbus_players_find(jd, error); |
137 |
} |
138 |
|
139 |
#define DBUS_TYPE_MPRIS_STATUS \ |
140 |
(dbus_g_type_get_struct("GValueArray", G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INVALID)) |
141 |
#define DBUS_TYPE_G_STRING_VALUE_HASHTABLE \ |
142 |
(dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE)) |
143 |
|
144 |
/* TODO: Connect to status change signal */ |
145 |
|
146 |
gboolean |
147 |
lj_dbus_mpris_update_info(JamDBus *jd, GList *list, GError **error) { |
148 |
GValueArray *array = NULL; |
149 |
GHashTable *info = NULL; |
150 |
GValue *value; |
151 |
MediaPlayer *player; |
152 |
|
153 |
if (jd == NULL) |
154 |
return FALSE; |
155 |
|
156 |
if (list == NULL) |
157 |
return FALSE; |
158 |
|
159 |
if ((player = (MediaPlayer *) list->data) == NULL) |
160 |
return FALSE; |
161 |
|
162 |
memset((void *) &player->info, 0, sizeof(MetaInfo)); |
163 |
|
164 |
if (player->hint & MPRIS_HINT_BAD_STATUS) { |
165 |
if (!dbus_g_proxy_call(player->proxy, "GetStatus", error, G_TYPE_INVALID, |
166 |
G_TYPE_INT, &player->info.status, G_TYPE_INVALID)) { |
167 |
return FALSE; |
168 |
} |
169 |
} else { |
170 |
if (!dbus_g_proxy_call(player->proxy, "GetStatus", error, G_TYPE_INVALID, |
171 |
DBUS_TYPE_MPRIS_STATUS, &array, G_TYPE_INVALID)) { |
172 |
return FALSE; |
173 |
} |
174 |
|
175 |
value = g_value_array_get_nth(array, 0); |
176 |
player->info.status = g_value_get_int(value); |
177 |
g_value_array_free(array); |
178 |
} |
179 |
|
180 |
if (player->info.status == MPRIS_STATUS_PLAYING) { |
181 |
if (!dbus_g_proxy_call(player->proxy, "GetMetadata", error, G_TYPE_INVALID, |
182 |
DBUS_TYPE_G_STRING_VALUE_HASHTABLE, &info, G_TYPE_INVALID)) { |
183 |
return FALSE; |
184 |
} |
185 |
value = (GValue *) g_hash_table_lookup(info, "artist"); |
186 |
if (value != NULL && G_VALUE_HOLDS_STRING(value)) { |
187 |
g_strlcpy(player->info.artist, g_value_get_string(value), MPRIS_INFO_LEN); |
188 |
} |
189 |
|
190 |
value = (GValue *) g_hash_table_lookup(info, "album"); |
191 |
if (value != NULL && G_VALUE_HOLDS_STRING(value)) { |
192 |
g_strlcpy(player->info.album, g_value_get_string(value), MPRIS_INFO_LEN); |
193 |
} |
194 |
|
195 |
value = (GValue *) g_hash_table_lookup(info, "title"); |
196 |
if (value != NULL && G_VALUE_HOLDS_STRING(value)) { |
197 |
g_strlcpy(player->info.title, g_value_get_string(value), MPRIS_INFO_LEN); |
198 |
} |
199 |
} |
200 |
|
201 |
return TRUE; |
202 |
} |
203 |
|
204 |
GQuark |
205 |
lj_dbus_error_quark(void) { |
206 |
static GQuark quark = 0; |
207 |
if (quark == 0) |
208 |
quark = g_quark_from_static_string("dbus-error-quark"); |
209 |
return quark; |
210 |
} |
211 |
|
212 |
/* TODO: User defined format */ |
213 |
|
214 |
gchar * |
215 |
lj_dbus_mpris_current_music(JamDBus *jd, GError **error) { |
216 |
gchar *music; |
217 |
GList *list; |
218 |
|
219 |
if (!lj_dbus_mpris_update_list(jd, error)) |
220 |
return NULL; |
221 |
|
222 |
list = jd ? jd->player : NULL; |
223 |
|
224 |
if (lj_dbus_mpris_update_info(jd, list, error)) { |
225 |
MediaPlayer *player = (MediaPlayer *) list->data; |
226 |
if (player->info.status == MPRIS_STATUS_PLAYING) { |
227 |
music = g_strdup_printf("%s - %s - %s", |
228 |
player->info.artist[0] ? player->info.artist : _("Unknown Artist"), |
229 |
player->info.album[0] ? player->info.album: _("Unknown Album"), |
230 |
player->info.title[0] ? player->info.title: _("Unknown Track")); |
231 |
return music; |
232 |
} else { |
233 |
g_set_error(error, lj_dbus_error_quark(), MPRIS_ERROR_NOT_PLAYING, |
234 |
_("Player is stopped.")); |
235 |
} |
236 |
} else if (error == NULL || *error == NULL) { |
237 |
g_set_error(error, lj_dbus_error_quark(), MPRIS_ERROR_NO_PLAYER, |
238 |
_("No players found.")); |
239 |
} |
240 |
return NULL; |
241 |
} |
242 |
|
243 |
/* lj_dbus.c */ |
244 |
|