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 "sources/ario-source-manager.h"
21 #include <gtk/gtk.h>
22 #include <string.h>
23 #include <config.h>
24 #include <glib/gi18n.h>
25
26 #include "ario-debug.h"
27 #include "lib/ario-conf.h"
28 #include "preferences/ario-preferences.h"
29 #include "sources/ario-browser.h"
30 #include "sources/ario-search.h"
31 #include "sources/ario-storedplaylists.h"
32 #include "widgets/ario-playlist.h"
33
34 static void ario_source_manager_sync (ArioSourceManager *sourcemanager);
35 static void ario_source_manager_showtabs_changed_cb (guint notification_id,
36 ArioSourceManager *sourcemanager);
37 static gboolean ario_source_manager_button_press_cb (GtkWidget *widget,
38 GdkEventButton *event,
39 ArioSourceManager *sourcemanager);
40 static gboolean ario_source_manager_switch_page_cb (GtkNotebook *notebook,
41 gpointer notebook_page,
42 guint page,
43 ArioSourceManager *sourcemanager);
44
45 struct ArioSourceManagerPrivate
46 {
47 GSList *sources;
48
49 ArioSource *source;
50 };
51
52 static ArioSourceManager *instance = NULL;
53
54 typedef struct ArioSourceData
55 {
56 ArioSource *source;
57 } ArioSourceData;
58
59 #define ARIO_SOURCE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ARIO_TYPE_SOURCE_MANAGER, ArioSourceManagerPrivate))
G_DEFINE_TYPE(ArioSourceManager,ario_source_manager,GTK_TYPE_NOTEBOOK)60 G_DEFINE_TYPE (ArioSourceManager, ario_source_manager, GTK_TYPE_NOTEBOOK)
61
62 static void
63 ario_source_manager_class_init (ArioSourceManagerClass *klass)
64 {
65 ARIO_LOG_FUNCTION_START;
66 /* Private attributes */
67 g_type_class_add_private (klass, sizeof (ArioSourceManagerPrivate));
68 }
69
70 static void
ario_source_manager_init(ArioSourceManager * sourcemanager)71 ario_source_manager_init (ArioSourceManager *sourcemanager)
72 {
73 ARIO_LOG_FUNCTION_START;
74 sourcemanager->priv = ARIO_SOURCE_MANAGER_GET_PRIVATE (sourcemanager);
75 }
76
77 GtkWidget *
ario_source_manager_get_instance(void)78 ario_source_manager_get_instance (void)
79 {
80 ARIO_LOG_FUNCTION_START;
81 GtkWidget *source;
82
83 /* Returns singleton if already instantiated */
84 if (instance)
85 return GTK_WIDGET (instance);
86
87 instance = g_object_new (ARIO_TYPE_SOURCE_MANAGER,
88 NULL);
89 g_return_val_if_fail (instance->priv != NULL, NULL);
90
91 /* Create browser */
92 source = ario_browser_new ();
93 ario_source_manager_append (ARIO_SOURCE (source));
94
95 #ifdef ENABLE_SEARCH
96 /* Create search */
97 source = ario_search_new ();
98 ario_source_manager_append (ARIO_SOURCE (source));
99 #endif /* ENABLE_SEARCH */
100 #ifdef ENABLE_STOREDPLAYLISTS
101 /* Create stored playlists source */
102 source = ario_storedplaylists_new ();
103 ario_source_manager_append (ARIO_SOURCE (source));
104 #endif /* ENABLE_STOREDPLAYLISTS */
105
106 /* Connect signlas for actions on notebook */
107 g_signal_connect (instance,
108 "button_press_event",
109 G_CALLBACK (ario_source_manager_button_press_cb),
110 instance);
111
112 g_signal_connect_after (instance,
113 "switch-page",
114 G_CALLBACK (ario_source_manager_switch_page_cb),
115 instance);
116
117 /* Reorder sources according to preferences */
118 ario_source_manager_reorder ();
119
120 /* Notification for preference changes */
121 ario_conf_notification_add (PREF_SHOW_TABS,
122 (ArioNotifyFunc) ario_source_manager_showtabs_changed_cb,
123 instance);
124
125 /* Set tabs visibility according to preferences */
126 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (instance),
127 ario_conf_get_boolean (PREF_SHOW_TABS, PREF_SHOW_TABS_DEFAULT));
128
129 return GTK_WIDGET (instance);
130 }
131
132 static void
ario_source_manager_shutdown_foreach(ArioSource * source,GSList ** ordered_sources)133 ario_source_manager_shutdown_foreach (ArioSource *source,
134 GSList **ordered_sources)
135 {
136 ARIO_LOG_FUNCTION_START;
137 /* Shutdown source */
138 ario_source_shutdown (source);
139
140 /* Add source to ordered list */
141 *ordered_sources = g_slist_append (*ordered_sources, ario_source_get_id (source));
142 }
143
144 void
ario_source_manager_shutdown(void)145 ario_source_manager_shutdown (void)
146 {
147 ARIO_LOG_FUNCTION_START;
148 GSList *ordered_sources = NULL;
149
150 /* Save current active page */
151 ario_conf_set_integer (PREF_SOURCE,
152 gtk_notebook_get_current_page (GTK_NOTEBOOK (instance)));
153
154 /* Shutdown each source and get an ordered list of sources */
155 gtk_container_foreach (GTK_CONTAINER (instance),
156 (GtkCallback) ario_source_manager_shutdown_foreach,
157 &ordered_sources);
158
159 /* Save ordered list of sources */
160 ario_conf_set_string_slist (PREF_SOURCE_LIST, ordered_sources);
161 g_slist_free (ordered_sources);
162 }
163
164 void
ario_source_manager_goto_playling_song(void)165 ario_source_manager_goto_playling_song (void)
166 {
167 ARIO_LOG_FUNCTION_START;
168 /* Go to playing song on active source */
169 if (instance->priv->source) {
170 ario_source_goto_playling_song (instance->priv->source);
171 }
172 }
173
174 void
ario_source_manager_reorder(void)175 ario_source_manager_reorder (void)
176 {
177 ARIO_LOG_FUNCTION_START;
178 int i = 0;
179 ArioSourceData *data;
180 GSList *ordered_tmp;
181 GSList *sources_tmp;
182 GSList *ordered_sources = ario_conf_get_string_slist (PREF_SOURCE_LIST, PREF_SOURCE_LIST_DEFAULT);
183
184 /* For each source in preferences */
185 for (ordered_tmp = ordered_sources; ordered_tmp; ordered_tmp = g_slist_next (ordered_tmp)) {
186 /* For each registered source */
187 for (sources_tmp = instance->priv->sources; sources_tmp; sources_tmp = g_slist_next (sources_tmp)) {
188 data = sources_tmp->data;
189 if (!strcmp (ario_source_get_id (data->source), ordered_tmp->data)) {
190 /* Move source tab according to preferences */
191 gtk_notebook_reorder_child (GTK_NOTEBOOK (instance),
192 GTK_WIDGET (data->source), i);
193 break;
194 }
195 }
196 ++i;
197 }
198
199 g_slist_foreach (ordered_sources, (GFunc) g_free, NULL);
200 g_slist_free (ordered_sources);
201
202 ario_source_manager_sync (instance);
203 }
204
205 static void
ario_source_manager_sync(ArioSourceManager * sourcemanager)206 ario_source_manager_sync (ArioSourceManager *sourcemanager)
207 {
208 ARIO_LOG_FUNCTION_START;
209 gint page;
210
211 /* Select active page according to preferences */
212 page = ario_conf_get_integer (PREF_SOURCE, PREF_SOURCE_DEFAULT);
213 gtk_notebook_set_current_page (GTK_NOTEBOOK (sourcemanager), page);
214 }
215
216 static void
ario_source_manager_showtabs_changed_cb(guint notification_id,ArioSourceManager * sourcemanager)217 ario_source_manager_showtabs_changed_cb (guint notification_id,
218 ArioSourceManager *sourcemanager)
219 {
220 ARIO_LOG_FUNCTION_START;
221 /* Set tabs visibility */
222 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (sourcemanager),
223 ario_conf_get_boolean (PREF_SHOW_TABS, PREF_SHOW_TABS_DEFAULT));
224 }
225
226 static void
ario_source_manager_set_source_active(ArioSource * source,gboolean active)227 ario_source_manager_set_source_active (ArioSource *source,
228 gboolean active)
229 {
230 ARIO_LOG_FUNCTION_START;
231 gchar *conf_name;
232
233 /* Set source activity in preferences */
234 conf_name = g_strconcat (ario_source_get_id (source), "-active", NULL);
235 ario_conf_set_boolean (conf_name, active);
236 g_free (conf_name);
237
238 if (active) {
239 /* Show source */
240 gtk_widget_set_no_show_all (GTK_WIDGET (source), FALSE);
241 gtk_widget_show_all (GTK_WIDGET (source));
242 gtk_widget_set_no_show_all (GTK_WIDGET (source), TRUE);
243 } else {
244 /* Hide source */
245 gtk_widget_hide (GTK_WIDGET (source));
246 }
247 }
248
249 static void
ario_source_manager_menu_cb(GtkCheckMenuItem * checkmenuitem,ArioSource * source)250 ario_source_manager_menu_cb (GtkCheckMenuItem *checkmenuitem,
251 ArioSource *source)
252 {
253 ARIO_LOG_FUNCTION_START;
254 /* Select source as in menu */
255 ario_source_manager_set_source_active (source, gtk_check_menu_item_get_active (checkmenuitem));
256 }
257
258 void
ario_source_manager_append(ArioSource * source)259 ario_source_manager_append (ArioSource *source)
260 {
261 ARIO_LOG_FUNCTION_START;
262 GtkWidget *hbox;
263 gchar *conf_name;
264 ArioSourceData *data;
265
266 /* Create hbox for tab header */
267 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
268
269 /* Add source icon to hbox */
270 gtk_box_pack_start (GTK_BOX (hbox),
271 gtk_image_new_from_icon_name (ario_source_get_icon (source), GTK_ICON_SIZE_MENU),
272 TRUE, TRUE, 0);
273
274 /* Add source name to hbox */
275 gtk_box_pack_start (GTK_BOX (hbox),
276 gtk_label_new (ario_source_get_name (source)),
277 TRUE, TRUE, 0);
278
279 /* Append source to source-manager */
280 gtk_widget_show_all (hbox);
281 gtk_notebook_append_page (GTK_NOTEBOOK (instance),
282 GTK_WIDGET (source),
283 hbox);
284
285 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (instance),
286 GTK_WIDGET (source),
287 TRUE);
288
289 /* Show/hide source depending on preferences */
290 conf_name = g_strconcat (ario_source_get_id (source), "-active", NULL);
291 if (ario_conf_get_boolean (conf_name, TRUE))
292 gtk_widget_show_all (GTK_WIDGET (source));
293 else
294 gtk_widget_hide (GTK_WIDGET (source));
295 gtk_widget_set_no_show_all (GTK_WIDGET (source), TRUE);
296 g_free (conf_name);
297
298 /* Add source data to list */
299 data = (ArioSourceData *) g_malloc (sizeof (ArioSourceData));
300 data->source = source;
301
302 instance->priv->sources = g_slist_append (instance->priv->sources, data);
303 }
304
305 void
ario_source_manager_remove(ArioSource * source)306 ario_source_manager_remove (ArioSource *source)
307 {
308 ARIO_LOG_FUNCTION_START;
309 GSList *tmp;
310 ArioSourceData *data;
311
312 /* Shutdown source */
313 ario_source_shutdown (source);
314
315 if (instance->priv->source == source)
316 instance->priv->source = NULL;
317
318 /* For each source */
319 for (tmp = instance->priv->sources; tmp; tmp = g_slist_next (tmp)) {
320 data = tmp->data;
321 /* Get source to remove */
322 if (data->source == source) {
323 /* Remove the source from the list */
324 instance->priv->sources = g_slist_remove (instance->priv->sources, data);
325 g_free (data);
326 break;
327 }
328 }
329 /* Remove source from notebook */
330 gtk_container_remove (GTK_CONTAINER (instance), GTK_WIDGET (source));
331 }
332
333 static gboolean
ario_source_manager_button_press_cb(GtkWidget * widget,GdkEventButton * event,ArioSourceManager * sourcemanager)334 ario_source_manager_button_press_cb (GtkWidget *widget,
335 GdkEventButton *event,
336 ArioSourceManager *sourcemanager)
337 {
338 ARIO_LOG_FUNCTION_START;
339 GtkWidget *menu;
340 GtkWidget *item;
341 GSList *tmp;
342 ArioSourceData *data;
343 gchar *conf_name;
344
345 if (event->button == 3) {
346 /* Third button: Show popup menu */
347 menu = gtk_menu_new ();
348
349 for (tmp = sourcemanager->priv->sources; tmp; tmp = g_slist_next (tmp)) {
350 /* Build menu with each source */
351 data = tmp->data;
352
353 item = gtk_check_menu_item_new_with_label (ario_source_get_name (data->source));
354 conf_name = g_strconcat (ario_source_get_id (data->source), "-active", NULL);
355 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
356 ario_conf_get_boolean (conf_name, TRUE));
357 g_free (conf_name);
358
359 /* Connect signal for activation/deactivation of sources in popup menu */
360 g_signal_connect (item, "toggled",
361 G_CALLBACK (ario_source_manager_menu_cb), data->source);
362 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
363 }
364
365 /* Show popup menu */
366 gtk_widget_show_all (menu);
367 gtk_menu_popup_at_pointer (GTK_MENU (menu), NULL);
368 }
369
370 return FALSE;
371 }
372
373 static gboolean
ario_source_manager_switch_page_cb(GtkNotebook * notebook,gpointer notebook_page,guint page,ArioSourceManager * sourcemanager)374 ario_source_manager_switch_page_cb (GtkNotebook *notebook,
375 gpointer notebook_page,
376 guint page,
377 ArioSourceManager *sourcemanager)
378 {
379 ARIO_LOG_FUNCTION_START;
380 ArioSource *new_source;
381
382 /* Call unselect on previous source */
383 if (sourcemanager->priv->source) {
384 ario_source_unselect (sourcemanager->priv->source);
385 }
386
387 /* Call select on new source */
388 new_source = ARIO_SOURCE (gtk_notebook_get_nth_page (notebook, page));
389 if (new_source)
390 ario_source_select (new_source);
391
392 sourcemanager->priv->source = new_source;
393
394 return FALSE;
395 }
396