Reformatted all code
[monky] / src / xmms2.c
1 /* Conky, a system monitor, based on torsmo
2  *
3  * Any original torsmo code is licensed under the BSD license
4  *
5  * All code written since the fork of torsmo is licensed under the GPL
6  *
7  * Please see COPYING for details
8  *
9  * Copyright (c) 2005-2007 Brenden Matthews, Philip Kovacs, et. al.
10  *      (see AUTHORS)
11  * All rights reserved.
12  *
13  * This program is free software: you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation, either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * You should have received a copy of the GNU General Public License
23  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24  *
25  * $Id$ */
26
27 #include "conky.h"
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <xmmsclient/xmmsclient.h>
32
33 #define CONN_INIT       0
34 #define CONN_OK         1
35 #define CONN_NO         2
36
37 /* callbacks */
38
39 static void xmms_alloc(struct information *ptr)
40 {
41         if (ptr->xmms2.status == NULL) {
42                 ptr->xmms2.status = malloc(TEXT_BUFFER_SIZE);
43                 ptr->xmms2.status[0] = '\0';
44         }
45
46         if (ptr->xmms2.artist == NULL) {
47                 ptr->xmms2.artist = malloc(TEXT_BUFFER_SIZE);
48                 ptr->xmms2.artist[0] = '\0';
49         }
50
51         if (ptr->xmms2.album == NULL) {
52                 ptr->xmms2.album = malloc(TEXT_BUFFER_SIZE);
53                 ptr->xmms2.album[0] = '\0';
54         }
55
56         if (ptr->xmms2.title == NULL) {
57                 ptr->xmms2.title = malloc(TEXT_BUFFER_SIZE);
58                 ptr->xmms2.title[0] = '\0';
59         }
60
61         if (ptr->xmms2.genre == NULL) {
62                 ptr->xmms2.genre = malloc(TEXT_BUFFER_SIZE);
63                 ptr->xmms2.genre[0] = '\0';
64         }
65
66         if (ptr->xmms2.comment == NULL) {
67                 ptr->xmms2.comment = malloc(TEXT_BUFFER_SIZE);
68                 ptr->xmms2.comment[0] = '\0';
69         }
70
71         if (ptr->xmms2.decoder == NULL) {
72                 ptr->xmms2.decoder = malloc(TEXT_BUFFER_SIZE);
73                 ptr->xmms2.decoder[0] = '\0';
74         }
75
76         if (ptr->xmms2.transport == NULL) {
77                 ptr->xmms2.transport = malloc(TEXT_BUFFER_SIZE);
78                 ptr->xmms2.transport[0] = '\0';
79         }
80
81         if (ptr->xmms2.url == NULL) {
82                 ptr->xmms2.url = malloc(TEXT_BUFFER_SIZE);
83                 ptr->xmms2.url[0] = '\0';
84         }
85
86         if (ptr->xmms2.date == NULL) {
87                 ptr->xmms2.date = malloc(TEXT_BUFFER_SIZE);
88                 ptr->xmms2.date[0] = '\0';
89         }
90 }
91
92 static void xmms_clear(struct information *ptr)
93 {
94         xmms_alloc(ptr);
95         ptr->xmms2.status[0] = '\0';
96         ptr->xmms2.artist[0] = '\0';
97         ptr->xmms2.album[0] = '\0';
98         ptr->xmms2.title[0] = '\0';
99         ptr->xmms2.genre[0] = '\0';
100         ptr->xmms2.comment[0] = '\0';
101         ptr->xmms2.decoder[0] = '\0';
102         ptr->xmms2.transport[0] = '\0';
103         ptr->xmms2.url[0] = '\0';
104         ptr->xmms2.date[0] = '\0';
105 }
106
107 void connection_lost(void *p)
108 {
109         struct information *ptr = p;
110
111         ptr->xmms2_conn_state = CONN_NO;
112
113         xmms_clear(ptr);
114         ptr->xmms2.tracknr = 0;
115         ptr->xmms2.id = 0;
116         ptr->xmms2.bitrate = 0;
117         ptr->xmms2.duration = 0;
118         ptr->xmms2.elapsed = 0;
119         ptr->xmms2.size = 0;
120         ptr->xmms2.progress = 0;
121 }
122
123 void handle_curent_id(xmmsc_result_t *res, void *p)
124 {
125         uint current_id;
126         struct information *ptr = p;
127
128         if (xmmsc_result_get_uint(res, &current_id)) {
129
130                 xmmsc_result_t *res2;
131
132                 res2 = xmmsc_medialib_get_info(ptr->xmms2_conn, current_id);
133                 xmmsc_result_wait(res2);
134
135                 xmms_clear(ptr);
136
137                 ptr->xmms2.id = current_id;
138
139                 char *temp;
140
141                 xmmsc_result_get_dict_entry_string(res2, "artist", &temp);
142                 if (temp != NULL) {
143                         strncpy(ptr->xmms2.artist, temp, TEXT_BUFFER_SIZE - 1);
144                 } else {
145                         strncpy(ptr->xmms2.artist, "[Unknown]", TEXT_BUFFER_SIZE - 1);
146                 }
147
148                 xmmsc_result_get_dict_entry_string(res2, "title", &temp);
149                 if (temp != NULL) {
150                         strncpy(ptr->xmms2.title, temp, TEXT_BUFFER_SIZE - 1);
151                 } else {
152                         strncpy(ptr->xmms2.title, "[Unknown]", TEXT_BUFFER_SIZE - 1);
153                 }
154
155                 xmmsc_result_get_dict_entry_string(res2, "album", &temp);
156                 if (temp != NULL) {
157                         strncpy(ptr->xmms2.album, temp, TEXT_BUFFER_SIZE - 1);
158                 } else {
159                         strncpy(ptr->xmms2.album, "[Unknown]", TEXT_BUFFER_SIZE - 1);
160                 }
161
162                 xmmsc_result_get_dict_entry_string(res2, "genre", &temp);
163                 if (temp != NULL) {
164
165                         strncpy(ptr->xmms2.genre, temp, TEXT_BUFFER_SIZE - 1);
166                 } else {
167                         strncpy(ptr->xmms2.genre, "[Unknown]", TEXT_BUFFER_SIZE - 1);
168                 }
169
170                 xmmsc_result_get_dict_entry_string(res2, "comment", &temp);
171                 if (temp != NULL) {
172                         strncpy(ptr->xmms2.comment, temp, TEXT_BUFFER_SIZE - 1);
173                 } else {
174                         strncpy(ptr->xmms2.comment, "", TEXT_BUFFER_SIZE - 1);
175                 }
176
177                 xmmsc_result_get_dict_entry_string(res2, "decoder", &temp);
178                 if (temp != NULL) {
179                         strncpy(ptr->xmms2.decoder, temp, TEXT_BUFFER_SIZE - 1);
180                 } else {
181                         strncpy(ptr->xmms2.decoder, "[Unknown]", TEXT_BUFFER_SIZE - 1);
182                 }
183
184                 xmmsc_result_get_dict_entry_string(res2, "transport", &temp);
185                 if (temp != NULL) {
186                         strncpy(ptr->xmms2.transport, temp, TEXT_BUFFER_SIZE - 1);
187                 } else {
188                         strncpy(ptr->xmms2.transport, "[Unknown]", TEXT_BUFFER_SIZE - 1);
189                 }
190
191                 xmmsc_result_get_dict_entry_string(res2, "url", &temp);
192                 if (temp != NULL) {
193                         strncpy(ptr->xmms2.url, temp, TEXT_BUFFER_SIZE - 1);
194                 } else {
195                         strncpy(ptr->xmms2.url, "[Unknown]", TEXT_BUFFER_SIZE - 1);
196                 }
197
198                 xmmsc_result_get_dict_entry_string(res2, "date", &temp);
199                 if (temp != NULL) {
200                         strncpy(ptr->xmms2.date, temp, TEXT_BUFFER_SIZE - 1);
201                 } else {
202                         strncpy(ptr->xmms2.date, "????", TEXT_BUFFER_SIZE - 1);
203                 }
204
205                 int itemp;
206
207                 xmmsc_result_get_dict_entry_int(res2, "tracknr", &itemp);
208                 ptr->xmms2.tracknr = itemp;
209
210                 xmmsc_result_get_dict_entry_int(res2, "duration", &itemp);
211                 ptr->xmms2.duration = itemp;
212
213                 xmmsc_result_get_dict_entry_int(res2, "bitrate", &itemp);
214                 ptr->xmms2.bitrate = itemp / 1000;
215
216                 xmmsc_result_get_dict_entry_int(res2, "size", &itemp);
217                 ptr->xmms2.size = (float) itemp / 1048576;
218
219                 xmmsc_result_unref(res2);
220         }
221 }
222
223 void handle_playtime(xmmsc_result_t *res, void *p)
224 {
225         struct information *ptr = p;
226         xmmsc_result_t *res2;
227         uint play_time;
228
229         if (xmmsc_result_iserror(res)) {
230                 return;
231         }
232
233         if (!xmmsc_result_get_uint(res, &play_time)) {
234                 return;
235         }
236
237         res2 = xmmsc_result_restart(res);
238         xmmsc_result_unref(res2);
239
240         ptr->xmms2.elapsed = play_time;
241         ptr->xmms2.progress = (float) play_time / ptr->xmms2.duration;
242 }
243
244 void handle_playback_state_change(xmmsc_result_t *res, void *p)
245 {
246         struct information *ptr = p;
247         uint pb_state = 0;
248
249         if (xmmsc_result_iserror(res)) {
250                 return;
251         }
252
253         if (!xmmsc_result_get_uint(res, &pb_state)) {
254                 return;
255         }
256
257         switch (pb_state) {
258                 case XMMS_PLAYBACK_STATUS_PLAY:
259                         strncpy(ptr->xmms2.status, "Playing", TEXT_BUFFER_SIZE - 1);
260                         break;
261                 case XMMS_PLAYBACK_STATUS_PAUSE:
262                         strncpy(ptr->xmms2.status, "Paused", TEXT_BUFFER_SIZE - 1);
263                         break;
264                 case XMMS_PLAYBACK_STATUS_STOP:
265                         strncpy(ptr->xmms2.status, "Stopped", TEXT_BUFFER_SIZE - 1);
266                         break;
267                 default:
268                         strncpy(ptr->xmms2.status, "Unknown", TEXT_BUFFER_SIZE - 1);
269         }
270 }
271
272 void update_xmms2()
273 {
274         struct information *current_info = &info;
275
276         /* initialize connection */
277         if (current_info->xmms2_conn_state == CONN_INIT) {
278
279                 if (current_info->xmms2_conn == NULL) {
280                         current_info->xmms2_conn = xmmsc_init("conky");
281                 }
282
283                 /* did init fail? */
284                 if (current_info->xmms2_conn == NULL) {
285                         fprintf(stderr, "Conky: xmms2 init failed. %s\n",
286                                 xmmsc_get_last_error(current_info->xmms2_conn));
287                         fflush(stderr);
288                         return;
289                 }
290
291                 /* init ok but not connected yet.. */
292                 current_info->xmms2_conn_state = CONN_NO;
293
294                 /* clear all values */
295                 xmms_clear(current_info);
296
297                 current_info->xmms2.tracknr = 0;
298                 current_info->xmms2.id = 0;
299                 current_info->xmms2.bitrate = 0;
300                 current_info->xmms2.duration = 0;
301                 current_info->xmms2.elapsed = 0;
302                 current_info->xmms2.size = 0;
303                 current_info->xmms2.progress = 0;
304
305                 /* fprintf(stderr, "Conky: xmms2 init ok.\n");
306                 fflush(stderr); */
307         }
308
309         /* connect */
310         if (current_info->xmms2_conn_state == CONN_NO) {
311
312                 char *path = getenv("XMMS_PATH");
313
314                 if (!xmmsc_connect(current_info->xmms2_conn, path)) {
315                         fprintf(stderr, "Conky: xmms2 connection failed. %s\n",
316                                 xmmsc_get_last_error(current_info->xmms2_conn));
317                         fflush(stderr);
318                         current_info->xmms2_conn_state = CONN_NO;
319                         return;
320                 }
321
322                 /* set callbacks */
323                 xmmsc_disconnect_callback_set(current_info->xmms2_conn, connection_lost,
324                         current_info);
325                 XMMS_CALLBACK_SET(current_info->xmms2_conn, xmmsc_playback_current_id,
326                         handle_curent_id, current_info);
327                 XMMS_CALLBACK_SET(current_info->xmms2_conn,
328                         xmmsc_broadcast_playback_current_id, handle_curent_id,
329                         current_info);
330                 XMMS_CALLBACK_SET(current_info->xmms2_conn,
331                         xmmsc_signal_playback_playtime, handle_playtime, current_info);
332                 XMMS_CALLBACK_SET(current_info->xmms2_conn,
333                         xmmsc_broadcast_playback_status, handle_playback_state_change,
334                         current_info);
335
336                 /* get playback status, it wont be broadcasted untill it chages */
337                 xmmsc_result_t *res = xmmsc_playback_status(current_info->xmms2_conn);
338
339                 xmmsc_result_wait(res);
340                 unsigned int pb_state;
341
342                 xmmsc_result_get_uint(res, &pb_state);
343                 switch (pb_state) {
344                         case XMMS_PLAYBACK_STATUS_PLAY:
345                                 strncpy(current_info->xmms2.status, "Playing",
346                                         TEXT_BUFFER_SIZE - 1);
347                                 break;
348                         case XMMS_PLAYBACK_STATUS_PAUSE:
349                                 strncpy(current_info->xmms2.status, "Paused",
350                                         TEXT_BUFFER_SIZE - 1);
351                                 break;
352                         case XMMS_PLAYBACK_STATUS_STOP:
353                                 strncpy(current_info->xmms2.status, "Stopped",
354                                         TEXT_BUFFER_SIZE - 1);
355                                 break;
356                         default:
357                                 strncpy(current_info->xmms2.status, "Unknown",
358                                         TEXT_BUFFER_SIZE - 1);
359                 }
360                 xmmsc_result_unref(res);
361
362                 /* everything seems to be ok */
363                 current_info->xmms2_conn_state = CONN_OK;
364
365                 /* fprintf(stderr, "Conky: xmms2 connected.\n");
366                 fflush(stderr); */
367         }
368
369         /* handle callbacks */
370         if (current_info->xmms2_conn_state == CONN_OK) {
371                 struct timeval tmout;
372
373                 tmout.tv_sec = 0;
374                 tmout.tv_usec = 100;
375
376                 select(current_info->xmms2_fd + 1, &current_info->xmms2_fdset, NULL,
377                         NULL, &tmout);
378
379                 xmmsc_io_in_handle(current_info->xmms2_conn);
380                 if (xmmsc_io_want_out(current_info->xmms2_conn)) {
381                         xmmsc_io_out_handle(current_info->xmms2_conn);
382                 }
383         }
384 }