1 /*
2  *  Copyright (C) 2005 Marc Pavot <marc.pavot@gmail.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2, or (at your option)
7  *  any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  */
19 
20 #include "servers/ario-server-interface.h"
21 #include <gtk/gtk.h>
22 
23 #include "ario-debug.h"
24 #include "ario-util.h"
25 
26 static void ario_server_interface_finalize (GObject *object);
27 static void ario_server_interface_set_property (GObject *object,
28                                                 guint prop_id,
29                                                 const GValue *value,
30                                                 GParamSpec *pspec);
31 static void ario_server_interface_get_property (GObject *object,
32                                                 guint prop_id,
33                                                 GValue *value,
34                                                 GParamSpec *pspec);
35 
36 /* Object properties */
37 enum
38 {
39         PROP_0,
40         PROP_SONGID,
41         PROP_STATE,
42         PROP_VOLUME,
43         PROP_ELAPSED,
44         PROP_PLAYLISTID,
45         PROP_CONSUME,
46         PROP_RANDOM,
47         PROP_UPDATINGDB,
48         PROP_REPEAT
49 };
50 
G_DEFINE_TYPE(ArioServerInterface,ario_server_interface,G_TYPE_OBJECT)51 G_DEFINE_TYPE (ArioServerInterface, ario_server_interface, G_TYPE_OBJECT)
52 
53         /* Dummy methods for default behavior */
54 static void
55 dummy_void_void (void)
56 {
57 }
58 
59 static void
dummy_void_int(const int a)60 dummy_void_int (const int a)
61 {
62 }
63 
64 static void
dummy_void_int_int(const int a,const int b)65 dummy_void_int_int (const int a,
66                     const int b)
67 {
68 }
69 
70 static void
dummy_void_pointer(const gpointer * a)71 dummy_void_pointer (const gpointer *a)
72 {
73 }
74 
75 static void
dummy_void_pointer_int(const gpointer * a,const int b)76 dummy_void_pointer_int (const gpointer *a,
77                         const int b)
78 {
79 }
80 
81 static int
dummy_int_void(void)82 dummy_int_void (void)
83 {
84         return 0;
85 }
86 
87 static int
dummy_int_pointer(const gpointer * a)88 dummy_int_pointer (const gpointer *a)
89 {
90         return 0;
91 }
92 
93 static unsigned long
dummy_ulong_void(void)94 dummy_ulong_void (void)
95 {
96         return 0;
97 }
98 
99 static gpointer
dummy_pointer_void(void)100 dummy_pointer_void (void)
101 {
102         return NULL;
103 }
104 
105 static gpointer
dummy_pointer_pointer(const gpointer * a)106 dummy_pointer_pointer (const gpointer *a)
107 {
108         return NULL;
109 }
110 
111 static gpointer
dummy_pointer_pointer_int(const gpointer * a,const int b)112 dummy_pointer_pointer_int (const gpointer *a,
113                            const int b)
114 {
115         return NULL;
116 }
117 
118 static gpointer
dummy_pointer_tag_pointer(const ArioServerTag a,const gpointer * b)119 dummy_pointer_tag_pointer (const ArioServerTag a,
120                            const gpointer *b)
121 {
122         return NULL;
123 }
124 
125 static gpointer
dummy_pointer_int(gint64 playlist_id)126 dummy_pointer_int (gint64 playlist_id)
127 {
128         return NULL;
129 }
130 
131 static void
ario_server_interface_class_init(ArioServerInterfaceClass * klass)132 ario_server_interface_class_init (ArioServerInterfaceClass *klass)
133 {
134         ARIO_LOG_FUNCTION_START;
135         GObjectClass *object_class = G_OBJECT_CLASS (klass);
136 
137         /* GObject virtual methods */
138         object_class->finalize = ario_server_interface_finalize;
139         object_class->set_property = ario_server_interface_set_property;
140         object_class->get_property = ario_server_interface_get_property;
141 
142         /* Default virtual methods for ArioServerInterface */
143         klass->connect = dummy_void_void;
144         klass->disconnect = dummy_void_void;
145         klass->is_connected = dummy_int_void;
146         klass->update_status = dummy_int_void;
147         klass->update_db = (void (*) (const char *)) dummy_void_pointer;
148         klass->list_tags = (GSList* (*) (const ArioServerTag, const ArioServerCriteria *)) dummy_pointer_tag_pointer;
149         klass->get_albums = (GSList* (*) (const ArioServerCriteria *)) dummy_pointer_pointer;
150         klass->get_songs = (GSList* (*) (const ArioServerCriteria *, const gboolean)) dummy_pointer_pointer_int;
151         klass->get_songs_from_playlist = (GSList* (*) (char *)) dummy_pointer_pointer;
152         klass->get_playlists = (GSList* (*) (void)) dummy_pointer_void;
153         klass->get_playlist_changes = (GSList* (*) (gint64))dummy_pointer_int;
154         klass->get_current_song_on_server = (ArioServerSong* (*) (void)) dummy_pointer_void;
155         klass->get_current_playlist_total_time = dummy_int_void;
156         klass->get_last_update = dummy_ulong_void;
157         klass->do_next = dummy_void_void;
158         klass->do_prev = dummy_void_void;
159         klass->do_play = dummy_void_void;
160         klass->do_play_pos = dummy_void_int;
161         klass->do_pause = dummy_void_void;
162         klass->do_stop = dummy_void_void;
163         klass->set_current_elapsed = dummy_void_int;
164         klass->set_current_volume = dummy_void_int;
165         klass->set_current_consume = dummy_void_int;
166         klass->set_current_random = dummy_void_int;
167         klass->set_current_repeat = dummy_void_int;
168         klass->set_crossfadetime = dummy_void_int;
169         klass->clear = dummy_void_void;
170         klass->shuffle = dummy_void_void;
171         klass->queue_commit = dummy_void_void;
172         klass->insert_at = (void (*) (const GSList *, const gint)) dummy_void_pointer_int;
173         klass->save_playlist = (int (*) (const char *)) dummy_int_pointer;
174         klass->delete_playlist = (void (*) (const char *)) dummy_void_pointer;
175         klass->get_outputs = (GSList* (*) (void)) dummy_pointer_void;
176         klass->enable_output = dummy_void_int_int;
177         klass->get_stats = (ArioServerStats* (*) (void)) dummy_pointer_void;
178         klass->get_songs_info = (GList* (*) (GSList *)) dummy_pointer_pointer;
179         klass->list_files = (ArioServerFileList* (*) (const char *, const int)) dummy_pointer_pointer_int;
180 
181         /* Object properties */
182         g_object_class_install_property (object_class,
183                                          PROP_SONGID,
184                                          g_param_spec_int ("song_id",
185                                                            "song_id",
186                                                            "song_id",
187                                                            -1, INT_MAX, 0,
188                                                            G_PARAM_READWRITE));
189 
190         g_object_class_install_property (object_class,
191                                          PROP_STATE,
192                                          g_param_spec_uint ("state",
193                                                             "state",
194                                                             "state",
195                                                             0, 3, 0,
196                                                             G_PARAM_READWRITE));
197 
198         g_object_class_install_property (object_class,
199                                          PROP_VOLUME,
200                                          g_param_spec_int ("volume",
201                                                            "volume",
202                                                            "volume",
203                                                            -1, 100, 0,
204                                                            G_PARAM_READWRITE));
205 
206         g_object_class_install_property (object_class,
207                                          PROP_ELAPSED,
208                                          g_param_spec_uint ("elapsed",
209                                                             "elapsed",
210                                                             "elapsed",
211                                                             0, INT_MAX, 0,
212                                                             G_PARAM_READWRITE));
213 
214         g_object_class_install_property (object_class,
215                                          PROP_PLAYLISTID,
216                                          g_param_spec_int64 ("playlist_id",
217                                                              "playlist_id",
218                                                              "playlist_id",
219                                                              -1, G_MAXINT64, 0,
220                                                              G_PARAM_READWRITE));
221 
222         g_object_class_install_property (object_class,
223                                          PROP_RANDOM,
224                                          g_param_spec_boolean ("random",
225                                                                "random",
226                                                                "random",
227                                                                FALSE,
228                                                                G_PARAM_READWRITE));
229 
230         g_object_class_install_property (object_class,
231                                          PROP_CONSUME,
232                                          g_param_spec_boolean ("consume",
233                                                                "consume",
234                                                                "consume",
235                                                                FALSE,
236                                                                G_PARAM_READWRITE));
237 
238         g_object_class_install_property (object_class,
239                                          PROP_REPEAT,
240                                          g_param_spec_boolean ("repeat",
241                                                                "repeat",
242                                                                "repeat",
243                                                                FALSE,
244                                                                G_PARAM_READWRITE));
245 
246         g_object_class_install_property (object_class,
247                                          PROP_UPDATINGDB,
248                                          g_param_spec_uint ("updatingdb",
249                                                             "updatingdb",
250                                                             "updatingdb",
251                                                             0, INT_MAX, 0,
252                                                             G_PARAM_READWRITE));
253 }
254 
255 static void
ario_server_interface_init(ArioServerInterface * server_interface)256 ario_server_interface_init (ArioServerInterface *server_interface)
257 {
258         ARIO_LOG_FUNCTION_START;
259         /* Initialization of attributes */
260         server_interface->song_id = -1;
261         server_interface->playlist_id = -1;
262         server_interface->volume = -1;
263 }
264 
265 static void
ario_server_interface_finalize(GObject * object)266 ario_server_interface_finalize (GObject *object)
267 {
268         ARIO_LOG_FUNCTION_START;
269         ArioServerInterface *server_interface;
270 
271         g_return_if_fail (object != NULL);
272         g_return_if_fail (IS_ARIO_SERVER_INTERFACE (object));
273 
274         server_interface = ARIO_SERVER_INTERFACE (object);
275 
276         /* Free current song */
277         if (server_interface->server_song)
278                 ario_server_free_song (server_interface->server_song);
279 
280         G_OBJECT_CLASS (ario_server_interface_parent_class)->finalize (object);
281 }
282 
283 static void
ario_server_interface_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)284 ario_server_interface_set_property (GObject *object,
285                                     guint prop_id,
286                                     const GValue *value,
287                                     GParamSpec *pspec)
288 {
289         ARIO_LOG_FUNCTION_START;
290         ArioServerInterface *server_interface = ARIO_SERVER_INTERFACE (object);
291         int song_id;
292         gboolean song_changed = FALSE;
293 
294         switch (prop_id) {
295         case PROP_SONGID:
296                 song_id = g_value_get_int (value);
297                 /* Detect if song has changed */
298                 if (server_interface->song_id != song_id) {
299                         server_interface->signals_to_emit |= SERVER_SONG_CHANGED_FLAG;
300                         server_interface->song_id = song_id;
301                         song_changed = TRUE;
302                 }
303 
304                 /* Check if there is a connection */
305                 if (ario_server_is_connected ()) {
306                         ArioServerSong *new_song;
307                         ArioServerSong *old_song = server_interface->server_song;
308                         gboolean state_changed;
309                         gboolean artist_changed = FALSE;
310                         gboolean album_changed = FALSE;
311 
312                         /* Get new song on server */
313                         new_song = ario_server_get_current_song_on_server ();
314 
315                         /* Detect is state has changed */
316                         state_changed = (!old_song || !new_song);
317                         if (!state_changed) {
318                                 /* Detect if artist has changed */
319                                 artist_changed = ario_util_strcmp (old_song->artist, new_song->artist) != 0;
320                                 if (!artist_changed)
321                                         album_changed = ario_util_strcmp (old_song->album, new_song->album) != 0;
322                                 /* Detect if song has changed */
323                                 if (!song_changed)
324                                         song_changed = ario_util_strcmp (old_song->name, new_song->name) != 0
325                                                 || ario_util_strcmp (old_song->title, new_song->title) != 0;
326                         }
327 
328                         /* Remember to emit album-changed signal */
329                         if (state_changed || artist_changed || album_changed)
330                                 server_interface->signals_to_emit |= SERVER_ALBUM_CHANGED_FLAG;
331 
332                         /* Remember to emit song-changed signal */
333                         if (song_changed)
334                                 server_interface->signals_to_emit |= SERVER_SONG_CHANGED_FLAG;
335 
336                         /* Change current song */
337                         if (server_interface->server_song)
338                                 ario_server_free_song (server_interface->server_song);
339                         server_interface->server_song = new_song;
340                 } else {
341                         /* Not connected: free song */
342                         if (server_interface->server_song) {
343                                 ario_server_free_song (server_interface->server_song);
344                                 server_interface->server_song = NULL;
345                         }
346                 }
347                 break;
348         case PROP_STATE:
349                 /* Change value and flag signal to emit */
350                 server_interface->state = g_value_get_uint (value);
351                 server_interface->signals_to_emit |= SERVER_STATE_CHANGED_FLAG;
352                 break;
353         case PROP_VOLUME:
354                 /* Change value and flag signal to emit */
355                 server_interface->volume = g_value_get_int (value);
356                 server_interface->signals_to_emit |= SERVER_VOLUME_CHANGED_FLAG;
357                 break;
358         case PROP_ELAPSED:
359                 /* Change value and flag signal to emit */
360                 server_interface->elapsed = g_value_get_uint (value);
361                 server_interface->signals_to_emit |= SERVER_ELAPSED_CHANGED_FLAG;
362                 break;
363         case PROP_PLAYLISTID:
364                 /* Change value and flag signal to emit */
365                 server_interface->playlist_id = g_value_get_int64 (value);
366                 if (!ario_server_is_connected ())
367                         server_interface->playlist_length = 0;
368                 server_interface->signals_to_emit |= SERVER_PLAYLIST_CHANGED_FLAG;
369                 break;
370         case PROP_CONSUME:
371                 /* Change value and flag signal to emit */
372                 server_interface->consume = g_value_get_boolean (value);
373                 server_interface->signals_to_emit |= SERVER_CONSUME_CHANGED_FLAG;
374                 break;
375         case PROP_RANDOM:
376                 /* Change value and flag signal to emit */
377                 server_interface->random = g_value_get_boolean (value);
378                 server_interface->signals_to_emit |= SERVER_RANDOM_CHANGED_FLAG;
379                 break;
380         case PROP_REPEAT:
381                 /* Change value and flag signal to emit */
382                 server_interface->repeat = g_value_get_boolean (value);
383                 server_interface->signals_to_emit |= SERVER_REPEAT_CHANGED_FLAG;
384                 break;
385         case PROP_UPDATINGDB:
386                 /* Change value and flag signal to emit */
387                 server_interface->updatingdb = g_value_get_uint (value);
388                 server_interface->signals_to_emit |= SERVER_UPDATINGDB_CHANGED_FLAG;
389                 break;
390         default:
391                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
392                 break;
393         }
394 }
395 
396 static void
ario_server_interface_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)397 ario_server_interface_get_property (GObject *object,
398                                     guint prop_id,
399                                     GValue *value,
400                                     GParamSpec *pspec)
401 {
402         ARIO_LOG_FUNCTION_START;
403         ArioServerInterface *server_interface = ARIO_SERVER_INTERFACE (object);
404 
405         switch (prop_id) {
406         case PROP_SONGID:
407                 g_value_set_int (value, server_interface->song_id);
408                 break;
409         case PROP_STATE:
410                 g_value_set_int (value, server_interface->state);
411                 break;
412         case PROP_VOLUME:
413                 g_value_set_int (value, server_interface->volume);
414                 break;
415         case PROP_ELAPSED:
416                 g_value_set_int (value, server_interface->elapsed);
417                 break;
418         case PROP_PLAYLISTID:
419                 g_value_set_int64 (value, server_interface->playlist_id);
420                 break;
421         case PROP_CONSUME:
422                 g_value_set_boolean (value, server_interface->consume);
423                 break;
424         case PROP_RANDOM:
425                 g_value_set_boolean (value, server_interface->random);
426                 break;
427         case PROP_REPEAT:
428                 g_value_set_boolean (value, server_interface->repeat);
429                 break;
430         case PROP_UPDATINGDB:
431                 g_value_set_int (value, server_interface->updatingdb);
432                 break;
433         default:
434                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
435                 break;
436         }
437 }
438 
439 void
ario_server_interface_set_default(ArioServerInterface * server_interface)440 ario_server_interface_set_default (ArioServerInterface *server_interface)
441 {
442         ARIO_LOG_FUNCTION_START;
443         /* Set default song ID */
444         if (server_interface->song_id != 0)
445                 g_object_set (G_OBJECT (server_interface), "song_id", 0, NULL);
446 
447         /* Set default state */
448         if (server_interface->state != ARIO_STATE_UNKNOWN)
449                 g_object_set (G_OBJECT (server_interface), "state", ARIO_STATE_UNKNOWN, NULL);
450 
451         /* Set default volume */
452         if (server_interface->volume != -1)
453                 g_object_set (G_OBJECT (server_interface), "volume", -1, NULL);
454 
455         /* Set default elapsed time */
456         if (server_interface->elapsed != 0)
457                 g_object_set (G_OBJECT (server_interface), "elapsed", 0, NULL);
458 
459         /* Set default playlist ID */
460         g_object_set (G_OBJECT (server_interface), "playlist_id", (gint64) -1, NULL);
461 
462         /* Set default consume value */
463         if (server_interface->consume != FALSE)
464                 g_object_set (G_OBJECT (server_interface), "consume", FALSE, NULL);
465 
466         /* Set default random value */
467         if (server_interface->random != FALSE)
468                 g_object_set (G_OBJECT (server_interface), "random", FALSE, NULL);
469 
470         /* Set default repeat value */
471         if (server_interface->repeat != FALSE)
472                 g_object_set (G_OBJECT (server_interface), "repeat", FALSE, NULL);
473 
474         /* Set default updatingdb value */
475         if (server_interface->updatingdb != 0)
476                 g_object_set (G_OBJECT (server_interface), "updatingdb", 0, NULL);
477 }
478 
479 void
ario_server_interface_emit(ArioServerInterface * server_interface,ArioServer * server)480 ario_server_interface_emit (ArioServerInterface *server_interface,
481                             ArioServer *server)
482 {
483         ARIO_LOG_FUNCTION_START;
484         /* Emit signals depending of flags set in signals_to_emit */
485         if (server_interface->signals_to_emit & SERVER_SONG_CHANGED_FLAG)
486                 g_signal_emit_by_name (G_OBJECT (server), "song_changed");
487         if (server_interface->signals_to_emit & SERVER_ALBUM_CHANGED_FLAG)
488                 g_signal_emit_by_name (G_OBJECT (server), "album_changed");
489         if (server_interface->signals_to_emit & SERVER_STATE_CHANGED_FLAG)
490                 g_signal_emit_by_name (G_OBJECT (server), "state_changed");
491         if (server_interface->signals_to_emit & SERVER_VOLUME_CHANGED_FLAG)
492                 g_signal_emit_by_name (G_OBJECT (server), "volume_changed", server_interface->volume);
493         if (server_interface->signals_to_emit & SERVER_ELAPSED_CHANGED_FLAG)
494                 g_signal_emit_by_name (G_OBJECT (server), "elapsed_changed", server_interface->elapsed);
495         if (server_interface->signals_to_emit & SERVER_PLAYLIST_CHANGED_FLAG)
496                 g_signal_emit_by_name (G_OBJECT (server), "playlist_changed");
497         if (server_interface->signals_to_emit & SERVER_CONSUME_CHANGED_FLAG)
498                 g_signal_emit_by_name (G_OBJECT (server), "consume_changed");
499         if (server_interface->signals_to_emit & SERVER_RANDOM_CHANGED_FLAG)
500                 g_signal_emit_by_name (G_OBJECT (server), "random_changed");
501         if (server_interface->signals_to_emit & SERVER_REPEAT_CHANGED_FLAG)
502                 g_signal_emit_by_name (G_OBJECT (server), "repeat_changed");
503         if (server_interface->signals_to_emit & SERVER_UPDATINGDB_CHANGED_FLAG)
504                 g_signal_emit_by_name (G_OBJECT (server), "updatingdb_changed");
505         server_interface->signals_to_emit = 0;
506 }
507