1 /*
2  * Copyright (C) 2007 Felipe Weckx <felipe.weckx@gmail.com>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) 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 GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public
15  * License along with this program; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 
20 #include "gbemol-app.h"
21 #include "gbemol-utils.h"
22 #include "gbemol-preferences.h"
23 #include "bacon-volume.h"
24 
25 typedef struct _GbemolThreadData {
26 	GbemolApp* app;
27 	GbemolMpdSong* song;
28 } GbemolThreadData;
29 
30 struct _GbemolAppPrivate {
31 	GdkPixbuf* icon;
32 	GtkStatusIcon* status_icon;
33 
34 	GtkWidget *scl_song;
35 	gboolean update_scl_song;
36 
37 	GtkWidget *btn_previous;
38 	GtkWidget *btn_play;
39 	GtkWidget *btn_next;
40 	GtkWidget *btn_connect;
41 	GtkWidget *btn_volume;
42 
43 	GtkWidget *statusbar;
44 	GtkWidget *img_cover;
45 
46 	GtkWidget *btn_artist;
47 	GtkWidget *btn_album;
48 	GtkWidget *btn_title;
49 	GtkWidget *lbl_time;
50 	GtkWidget *lbl_dash;
51 	GtkWidget *lbl_from;
52 
53 	GtkWidget *mnu_status;
54 	GtkWidget *img_item_play;
55 
56 	GtkWidget *mnu_main;
57 
58 	GtkWidget *expander;
59 
60 	GtkWidget *win_main;
61 	GtkWidget *mnu_item_random;
62 	GtkWidget *mnu_item_repeat;
63 	GtkWidget *mnu_item_disconnect;
64 	GtkWidget *mnu_item_connect;
65 
66 	GtkTooltips *tips;
67 
68 	GThreadPool* pool;
69 	GbemolPreferences *pref;
70 };
71 
72 static GObjectClass *parent_class = NULL;
73 
74 static const gchar* authors[] = {"Felipe Weckx <felipe.weckx@gmail.com>",
75 				NULL};
76 
77 /* Class Functions */
78 static void gbemol_app_class_init (GbemolApp *g_class);
79 static void gbemol_app_init (GbemolApp *obj);
80 static void gbemol_app_finalize (GObject *object);
81 static void gbemol_app_dispose (GObject *object);
82 static void gbemol_app_build_menus (GbemolApp* app);
83 static void gbemol_app_build_gui (GbemolApp* app);
84 
85 static gboolean gbemol_app_win_main_resize_idled (GbemolApp* app);
86 
87 /* GTK+ Callbacks */
88 static gboolean on_win_main_delete_event (GtkWidget *w, GdkEventButton *event, GbemolApp* data);
89 static void on_btn_previous_clicked (GtkButton *button, GbemolApp* app);
90 static void on_btn_play_clicked (GtkButton *button, GbemolApp* app);
91 static void on_btn_next_clicked (GtkButton *button, GbemolApp* app);
92 static void on_btn_title_clicked (GtkButton *button, GbemolApp* app);
93 static void on_btn_album_clicked (GtkButton *button, GbemolApp* app);
94 static void on_btn_artist_clicked (GtkButton *button, GbemolApp* app);
95 static gboolean on_evt_button_press_event (GtkWidget *w, GdkEventButton *event, GbemolApp* data);
96 static void on_mnu_random_activate (GtkWidget* w, GbemolApp* data);
97 static void on_mnu_repeat_activate (GtkWidget* w, GbemolApp* data);
98 static void on_mnu_about_activate (GtkWidget* w, GbemolApp* data);
99 static void on_mnu_connect_activate (GtkWidget* b, GbemolApp* data);
100 static void on_expander_activate (GtkExpander* e, GbemolApp* data);
101 static void on_mnu_quit_activate (GtkWidget* e, GbemolApp* data);
102 static void on_mnu_preferences_activate (GtkWidget* e, GbemolApp* data);
103 static gboolean on_scl_song_change_value (GtkRange* range, GtkScrollType* scroll, gdouble value, GbemolApp* data);
104 static void on_status_icon_popup_menu (GtkStatusIcon* icon, guint button, guint activate_time, GbemolApp* app);
105 static void on_status_icon_activate (GtkStatusIcon *icon, GbemolApp* app);
106 static void on_btn_volume_value_changed (BaconVolumeButton *btn, GbemolApp* app);
107 static void on_notebook_page_switch (GtkNotebook* n, GtkNotebookPage* p, gint page_num, GbemolApp* app);
108 static gpointer gbemol_app_set_cover_image(GbemolThreadData* data);
109 
110 
111 GType
gbemol_app_get_type(void)112 gbemol_app_get_type (void)
113 {
114 	static GType type = 0;
115 	if (type == 0) {
116 		static const GTypeInfo info = {
117 			sizeof (GbemolAppClass),
118 			NULL,   /* base_init */
119 			NULL,   /* base_finalize */
120 			(GClassInitFunc) gbemol_app_class_init,   /* class_init */
121 			NULL,   /* class_finalize */
122 			NULL,   /* class_data */
123 			sizeof (GbemolApp),
124 			0,      /* n_preallocs */
125 			(GInstanceInitFunc) gbemol_app_init    /* instance_init */
126 		};
127 
128 		type = g_type_register_static (G_TYPE_OBJECT,
129 				"GbemolApp",
130 				&info, 0);
131 	}
132 	return type;
133 }
134 
135 static void
gbemol_app_build_menus(GbemolApp * app)136 gbemol_app_build_menus (GbemolApp* app)
137 {
138 	GtkWidget *item, *img;
139 
140 
141 	/*** MAIN MENU ***/
142 	app->priv->mnu_main = gtk_menu_new ();
143 
144 	/* About */
145 	item = gtk_image_menu_item_new_with_label (_("About"));
146 	img = gtk_image_new_from_stock (GTK_STOCK_ABOUT, GTK_ICON_SIZE_MENU);
147 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), img);
148 	gtk_menu_shell_append (GTK_MENU_SHELL (app->priv->mnu_main), item);
149 	g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (on_mnu_about_activate), app);
150 	gtk_widget_show (item);
151 
152 	item = gtk_separator_menu_item_new ();
153 	gtk_menu_shell_append (GTK_MENU_SHELL (app->priv->mnu_main), item);
154 	gtk_widget_show (item);
155 
156 	/* Random */
157 	item = gtk_check_menu_item_new_with_mnemonic (_("R_andom"));
158 	gtk_menu_shell_append (GTK_MENU_SHELL (app->priv->mnu_main), item);
159 	g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (on_mnu_random_activate), app);
160 	gtk_widget_show (item);
161 	app->priv->mnu_item_random = item;
162 
163 	/* Repeat */
164 	item = gtk_check_menu_item_new_with_mnemonic (_("_Repeat"));
165 	gtk_menu_shell_append (GTK_MENU_SHELL (app->priv->mnu_main), item);
166 	g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (on_mnu_repeat_activate), app);
167 	gtk_widget_show (item);
168 	app->priv->mnu_item_repeat = item;
169 
170 	item = gtk_separator_menu_item_new ();
171 	gtk_menu_shell_append (GTK_MENU_SHELL (app->priv->mnu_main), item);
172 	gtk_widget_show (item);
173 
174 	/* Preferences */
175 	item = gtk_image_menu_item_new_with_mnemonic (_("_Preferences"));
176 	img = gtk_image_new_from_stock (GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU);
177 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), img);
178 	gtk_menu_shell_append (GTK_MENU_SHELL (app->priv->mnu_main), item);
179 	g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (on_mnu_preferences_activate), app);
180 	gtk_widget_show (item);
181 
182 	item = gtk_separator_menu_item_new ();
183 	gtk_menu_shell_append (GTK_MENU_SHELL (app->priv->mnu_main), item);
184 	gtk_widget_show (item);
185 
186 	/* Connect/Disconnect */
187 	item = gtk_image_menu_item_new_with_mnemonic (_("_Connect"));
188 	img = gtk_image_new_from_stock (GTK_STOCK_CONNECT, GTK_ICON_SIZE_MENU);
189 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), img);
190 	gtk_menu_shell_append (GTK_MENU_SHELL (app->priv->mnu_main), item);
191 	g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (on_mnu_connect_activate), app);
192 	gtk_widget_show (item);
193 	app->priv->mnu_item_connect = item;
194 
195 	item = gtk_image_menu_item_new_with_mnemonic (_("_Disconnect"));
196 	img = gtk_image_new_from_stock (GTK_STOCK_DISCONNECT, GTK_ICON_SIZE_MENU);
197 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), img);
198 	gtk_menu_shell_append (GTK_MENU_SHELL (app->priv->mnu_main), item);
199 	g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (on_mnu_connect_activate), app);
200 	gtk_widget_show (item);
201 	app->priv->mnu_item_disconnect = item;
202 
203 	item = gtk_separator_menu_item_new ();
204 	gtk_menu_shell_append (GTK_MENU_SHELL (app->priv->mnu_main), item);
205 	gtk_widget_show (item);
206 
207 	/* Quit */
208 	item = gtk_image_menu_item_new_with_label (_("Quit"));
209 	img = gtk_image_new_from_stock (GTK_STOCK_QUIT, GTK_ICON_SIZE_MENU);
210 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), img);
211 	gtk_menu_shell_append (GTK_MENU_SHELL (app->priv->mnu_main), item);
212 	g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (on_mnu_quit_activate), app);
213 	gtk_widget_show (item);
214 
215 
216 	/*** STATUS ICON MENU ****/
217 	app->priv->mnu_status = gtk_menu_new ();
218 
219 	/* Next */
220 	item = gtk_image_menu_item_new_with_label (_("Next"));
221 	img = gtk_image_new_from_stock (GTK_STOCK_MEDIA_NEXT, GTK_ICON_SIZE_MENU);
222 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), img);
223 	gtk_menu_shell_append (GTK_MENU_SHELL (app->priv->mnu_status), item);
224 	g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (on_btn_next_clicked), app);
225 	gtk_widget_show (item);
226 
227 	/* Play/Pause */
228 	item = gtk_image_menu_item_new_with_label (_("Play/Pause"));
229 	img = gtk_image_new_from_stock (GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_MENU);
230 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), img);
231 	app->priv->img_item_play = img;
232 	gtk_menu_shell_append (GTK_MENU_SHELL (app->priv->mnu_status), item);
233 	g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (on_btn_play_clicked), app);
234 	gtk_widget_show (item);
235 
236 	/* Previous */
237 	item = gtk_image_menu_item_new_with_label (_("Previous"));
238 	img = gtk_image_new_from_stock (GTK_STOCK_MEDIA_PREVIOUS, GTK_ICON_SIZE_MENU);
239 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), img);
240 	gtk_menu_shell_append (GTK_MENU_SHELL (app->priv->mnu_status), item);
241 	g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (on_btn_previous_clicked), app);
242 	gtk_widget_show (item);
243 
244 	item = gtk_separator_menu_item_new ();
245 	gtk_menu_shell_append (GTK_MENU_SHELL (app->priv->mnu_status), item);
246 	gtk_widget_show (item);
247 
248 	/* Quit */
249 	item = gtk_image_menu_item_new_with_label (_("Quit"));
250 	img = gtk_image_new_from_stock (GTK_STOCK_QUIT, GTK_ICON_SIZE_MENU);
251 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), img);
252 	gtk_menu_shell_append (GTK_MENU_SHELL (app->priv->mnu_status), item);
253 	g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (on_mnu_quit_activate), app);
254 	gtk_widget_show (item);
255 }
256 
257 static void
gbemol_app_build_gui(GbemolApp * obj)258 gbemol_app_build_gui (GbemolApp *obj)
259 {
260 	GtkWidget *hbox1, *hbox2, *vbox1, *vbox2, *ebox, *btn, *lbl, *img;
261 
262 	obj->priv->tips = gtk_tooltips_new ();
263 
264 	obj->priv->icon = gdk_pixbuf_new_from_file (ICON_FILE, NULL);
265 
266 	gbemol_app_build_menus (obj);
267 
268 	/* Main window */
269 	obj->priv->win_main = gtk_window_new (GTK_WINDOW_TOPLEVEL);
270 	gtk_window_set_icon (GTK_WINDOW (obj->priv->win_main), obj->priv->icon);
271 	if (gbemol_cfg_get_bool("win_main", "stick"))
272 		gtk_window_stick (GTK_WINDOW (obj->priv->win_main));
273 	gtk_container_set_border_width (GTK_CONTAINER (obj->priv->win_main), 5);
274 	g_signal_connect (G_OBJECT (obj->priv->win_main), "delete-event", G_CALLBACK (on_win_main_delete_event), obj);
275 
276 	/* Status icon */
277 	if (gbemol_cfg_get_bool("app", "status-icon"))
278 		gbemol_app_create_status_icon (obj);
279 
280 	ebox = gtk_event_box_new ();
281 	g_signal_connect (G_OBJECT (ebox), "button-press-event", G_CALLBACK (on_evt_button_press_event), obj);
282 	gtk_container_add (GTK_CONTAINER (obj->priv->win_main), ebox);
283 
284 	/* The main vbox */
285 	vbox1 = gtk_vbox_new (FALSE, 2);
286 	gtk_container_add (GTK_CONTAINER (ebox), vbox1);
287 
288 	/* Top HBox */
289 	hbox1 = gtk_hbox_new (FALSE, 0);
290 	gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0);
291 
292 	/* Left-corner VBox */
293 	vbox2 = gtk_vbox_new (FALSE, 0);
294 	gtk_box_pack_start (GTK_BOX (hbox1), vbox2, FALSE, FALSE, 0);
295 
296 	hbox2 = gtk_hbox_new (FALSE, 0);
297 	gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 0);
298 
299 	/* Artist */
300 	btn = gtk_button_new_with_label ("Artist");
301 	obj->priv->btn_artist = btn;
302 	gtk_button_set_relief (GTK_BUTTON (btn), GTK_RELIEF_NONE);
303 	gtk_button_set_alignment (GTK_BUTTON (btn), 0.0, 0.5);
304 	gtk_tooltips_set_tip (obj->priv->tips, btn, _("More songs from this artist"), NULL);
305 	g_signal_connect (G_OBJECT (btn), "clicked", G_CALLBACK (on_btn_artist_clicked), obj);
306 	g_signal_connect (G_OBJECT (btn), "activate", G_CALLBACK (on_btn_artist_clicked), obj);
307 	gtk_box_pack_start (GTK_BOX (hbox2), btn, FALSE, FALSE, 0);
308 
309 	lbl = gtk_label_new ("");
310 	gtk_label_set_markup (GTK_LABEL (lbl), _("<span size=\"large\" weight=\"ultrabold\">-</span>"));
311 	gtk_box_pack_start (GTK_BOX (hbox2), lbl, FALSE, FALSE, 0);
312 	obj->priv->lbl_dash = lbl;
313 
314 	/* Song Title */
315 	btn = gtk_button_new_with_label ("Title");
316 	obj->priv->btn_title = btn;
317 	gtk_button_set_relief (GTK_BUTTON (btn), GTK_RELIEF_NONE);
318 	gtk_button_set_alignment (GTK_BUTTON (btn), 0.0, 0.5);
319 	gtk_tooltips_set_tip (obj->priv->tips, btn, _("Song Information"), NULL);
320 	g_signal_connect (G_OBJECT (btn), "clicked", G_CALLBACK (on_btn_title_clicked), obj);
321 	g_signal_connect (G_OBJECT (btn), "activate", G_CALLBACK (on_btn_title_clicked), obj);
322 	gtk_box_pack_start (GTK_BOX (hbox2), btn, FALSE, FALSE, 0);
323 
324 	hbox2 = gtk_hbox_new (FALSE, 0);
325 	gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 0);
326 
327 	lbl = gtk_label_new ("");
328 	gtk_label_set_markup (GTK_LABEL (lbl), _("<span size=\"small\">from</span>"));
329 	gtk_box_pack_start (GTK_BOX (hbox2), lbl, FALSE, FALSE, 0);
330 	obj->priv->lbl_from = lbl;
331 
332 	/* Album */
333 	btn = gtk_button_new_with_label ("Album");
334 	obj->priv->btn_album = btn;
335 	gtk_button_set_relief (GTK_BUTTON (btn), GTK_RELIEF_NONE);
336 	gtk_button_set_alignment (GTK_BUTTON (btn), 0.0, 0.5);
337 	gtk_tooltips_set_tip (obj->priv->tips, btn, _("More songs from this album"), NULL);
338 	g_signal_connect (G_OBJECT (btn), "clicked", G_CALLBACK (on_btn_album_clicked), obj);
339 	g_signal_connect (G_OBJECT (btn), "activate", G_CALLBACK (on_btn_album_clicked), obj);
340 	gtk_box_pack_start (GTK_BOX (hbox2), btn, FALSE, FALSE, 0);
341 
342 	/* Cover image */
343 	obj->priv->img_cover = gtk_image_new ();
344 	gtk_misc_set_alignment (GTK_MISC (obj->priv->img_cover), 1.0, 0.5);
345 	gtk_box_pack_start (GTK_BOX (hbox1), obj->priv->img_cover, TRUE, TRUE, 0);
346 
347 	/* Player hbox */
348 	hbox1 = gtk_hbox_new (FALSE, 3);
349 	gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, TRUE, 0);
350 
351 	/* Previous */
352 	btn = gtk_button_new ();
353 	gtk_button_set_relief (GTK_BUTTON (btn), GTK_RELIEF_NONE);
354 	img = gtk_image_new_from_stock (GTK_STOCK_MEDIA_PREVIOUS, GTK_ICON_SIZE_BUTTON);
355 	gtk_button_set_image (GTK_BUTTON (btn), img);
356 	gtk_tooltips_set_tip (obj->priv->tips, btn, _("Previous Song"), NULL);
357 	g_signal_connect (G_OBJECT (btn), "clicked", G_CALLBACK (on_btn_previous_clicked), obj);
358 	g_signal_connect (G_OBJECT (btn), "activate", G_CALLBACK (on_btn_previous_clicked), obj);
359 	gtk_box_pack_start (GTK_BOX (hbox1), btn, FALSE, FALSE, 0);
360 	obj->priv->btn_previous = btn;
361 
362 	/* Play/Pause */
363 	btn = gtk_button_new ();
364 	gtk_button_set_relief (GTK_BUTTON (btn), GTK_RELIEF_NONE);
365 	img = gtk_image_new_from_stock (GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_BUTTON);
366 	gtk_button_set_image (GTK_BUTTON (btn), img);
367 	gtk_tooltips_set_tip (obj->priv->tips, btn, _("Play"), NULL);
368 	g_signal_connect (G_OBJECT (btn), "clicked", G_CALLBACK (on_btn_play_clicked), obj);
369 	g_signal_connect (G_OBJECT (btn), "activate", G_CALLBACK (on_btn_play_clicked), obj);
370 	gtk_box_pack_start (GTK_BOX (hbox1), btn, FALSE, FALSE, 0);
371 	obj->priv->btn_play = btn;
372 
373 	/* Next */
374 	btn = gtk_button_new ();
375 	gtk_button_set_relief (GTK_BUTTON (btn), GTK_RELIEF_NONE);
376 	img = gtk_image_new_from_stock (GTK_STOCK_MEDIA_NEXT, GTK_ICON_SIZE_BUTTON);
377 	gtk_button_set_image (GTK_BUTTON (btn), img);
378 	gtk_tooltips_set_tip (obj->priv->tips, btn, _("Next Song"), NULL);
379 	g_signal_connect (G_OBJECT (btn), "clicked", G_CALLBACK (on_btn_next_clicked), obj);
380 	g_signal_connect (G_OBJECT (btn), "activate", G_CALLBACK (on_btn_next_clicked), obj);
381 	gtk_box_pack_start (GTK_BOX (hbox1), btn, FALSE, FALSE, 0);
382 	obj->priv->btn_next = btn;
383 
384 	/* Scrollbar */
385 	obj->priv->scl_song = gtk_hscale_new_with_range (0.0, 1.0, 0.01);
386 	gtk_scale_set_draw_value (GTK_SCALE (obj->priv->scl_song), FALSE);
387 	gtk_range_set_update_policy (GTK_RANGE (obj->priv->scl_song), GTK_UPDATE_DISCONTINUOUS);
388 	gtk_box_pack_start (GTK_BOX (hbox1), obj->priv->scl_song, TRUE, TRUE, 0);
389 	g_signal_connect (G_OBJECT (obj->priv->scl_song), "change-value", G_CALLBACK (on_scl_song_change_value), obj);
390 
391 	/* Time Label */
392 	obj->priv->lbl_time = gtk_label_new (NULL);
393 	gtk_box_pack_start (GTK_BOX (hbox1), obj->priv->lbl_time, FALSE, FALSE, 0);
394 
395 	/* Volume Button */
396 	obj->priv->btn_volume = bacon_volume_button_new (GTK_ICON_SIZE_BUTTON, 0.0, 100.0, 1.0);
397 	gtk_button_set_relief (GTK_BUTTON (obj->priv->btn_volume), GTK_RELIEF_NONE);
398 	gtk_box_pack_start (GTK_BOX (hbox1), obj->priv->btn_volume, FALSE, FALSE, 0);
399 	g_signal_connect (G_OBJECT (obj->priv->btn_volume), "value-changed",
400 			G_CALLBACK (on_btn_volume_value_changed), obj);
401 
402 	/* Expander */
403 	obj->priv->expander = gtk_expander_new (NULL);
404 	gtk_container_set_border_width (GTK_CONTAINER (obj->priv->expander), 3);
405 	gtk_box_pack_start (GTK_BOX (vbox1), obj->priv->expander, TRUE, TRUE, 0);
406 	g_signal_connect (G_OBJECT (obj->priv->expander), "activate", G_CALLBACK (on_expander_activate), obj);
407 
408 	vbox2 = gtk_vbox_new (FALSE, 0);
409 	gtk_container_add (GTK_CONTAINER (obj->priv->expander), vbox2);
410 
411 	/* Notebook */
412 	obj->notebook = gtk_notebook_new ();
413 	gtk_notebook_set_tab_pos (GTK_NOTEBOOK (obj->notebook), GTK_POS_LEFT);
414 	gtk_box_pack_start (GTK_BOX (vbox2), obj->notebook, TRUE, TRUE, 5);
415 
416 	hbox1 = gtk_hbox_new (FALSE, 5);
417 	gtk_box_pack_start (GTK_BOX (vbox2), hbox1, FALSE, FALSE, 0);
418 
419 	/* Status bar
420 	obj->priv->statusbar = gtk_statusbar_new ();
421 	gtk_box_pack_start (GTK_BOX (hbox1), obj->priv->statusbar, TRUE, TRUE, 0);
422 	*/
423 
424 	gtk_widget_show_all (ebox);
425 
426 	if (gbemol_cfg_get_int ("win_main", "expanded"))
427 		gtk_expander_set_expanded (GTK_EXPANDER (obj->priv->expander), TRUE);
428 
429 	g_idle_add ((GSourceFunc) gbemol_app_win_main_resize_idled, obj);
430 }
431 
432 static void
gbemol_app_init(GbemolApp * app)433 gbemol_app_init (GbemolApp* app)
434 {
435 	gchar *host, *pass, *str;
436 	gint i, defaults[] = {0, 1, 2, 10};
437 	GtkWidget* lbl;
438 	GtkNotebook* n;
439 
440 	app->priv = g_new0 (GbemolAppPrivate, 1);
441 	app->mpd = NULL;
442 	app->priv->status_icon = NULL;
443 	app->priv->update_scl_song = TRUE;
444 	app->pls = NULL;
445 	app->lib = NULL;
446 	app->info = NULL;
447 
448 	/* Build Interface */
449 	gbemol_app_build_gui (app);
450 
451 	/* Check if there is a config file */
452 	if (!(host = gbemol_cfg_get_string ("MPD", "host")))
453 	{
454 		app->mpd = gbemol_mpd_new_with_defaults ();
455 
456 		/* Save default columns in playlist and library, otherwise nothing is shown */
457 		for (i = 0; i < 4; i++)
458 		{
459 			if (i == 3)
460 				str = g_strdup_printf ("column%d", defaults[i] - 1);
461 			else
462 				str = g_strdup_printf ("column%d", defaults[i]);
463 			gbemol_cfg_set_int ("library", str, 1);
464 			g_free (str);
465 
466 			str = g_strdup_printf ("column%d", defaults[i] + 1);
467 			gbemol_cfg_set_int ("playlist", str, 1);
468 			g_free (str);
469 		}
470 	}
471 	else
472 	{
473 		/* We need a password? */
474 		if (gbemol_cfg_get_int ("MPD", "use_auth"))
475 			pass = gbemol_cfg_get_string ("MPD", "pass");
476 		else
477 			pass = NULL;
478 
479 		app->mpd = gbemol_mpd_new (host, pass, gbemol_cfg_get_int ("MPD", "port"),
480 				gbemol_cfg_get_double ("MPD", "timeout"));
481 		g_free (host);
482 		g_free (pass);
483 	}
484 
485 	n = GTK_NOTEBOOK (app->notebook);
486 	g_signal_connect (G_OBJECT (n), "switch-page", G_CALLBACK (on_notebook_page_switch), app);
487 
488 	/* Playlist Tab */
489 	app->pls = gbemol_playlist_new (app->mpd);
490 	lbl = gtk_label_new (_("Playlist"));
491 	gtk_label_set_angle (GTK_LABEL (lbl), 90.0);
492 	gtk_notebook_append_page (n, GTK_WIDGET (app->pls), lbl);
493 
494 	/* Library Tab */
495 	app->lib = gbemol_library_new (app->mpd);
496 	lbl = gtk_label_new (_("Library"));
497 	gtk_label_set_angle (GTK_LABEL (lbl), 90.0);
498 	gtk_notebook_append_page (n, GTK_WIDGET (app->lib), lbl);
499 
500 	/* Info Tab */
501 	app->info = gbemol_info_new (app->mpd);
502 	lbl = gtk_label_new (_("Info"));
503 	gtk_label_set_angle (GTK_LABEL (lbl), 90.0);
504 	gtk_notebook_append_page (n, GTK_WIDGET (app->info), lbl);
505 }
506 
507 static void
gbemol_app_class_init(GbemolApp * klass)508 gbemol_app_class_init (GbemolApp* klass)
509 {
510 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
511 
512 	gobject_class->dispose = gbemol_app_dispose;
513 	gobject_class->finalize = gbemol_app_finalize;
514 
515   	parent_class = g_type_class_peek_parent (klass);
516 }
517 
518 void
gbemol_app_finalize(GObject * obj)519 gbemol_app_finalize (GObject *obj)
520 {
521 
522 	gtk_widget_destroy (GBEMOL_APP (obj)->priv->win_main);
523 	g_object_unref (G_OBJECT (GBEMOL_APP (obj)->mpd));
524 	/*g_thread_pool_free(GBEMOL_APP(obj)->priv->pool, TRUE, TRUE);*/
525 	g_free (GBEMOL_APP (obj)->priv);
526 
527 	G_OBJECT_CLASS (parent_class)->finalize (obj);
528 }
529 
gbemol_app_new(void)530 GbemolApp* gbemol_app_new (void)
531 {
532 	GbemolApp* obj;
533 
534 	obj = GBEMOL_APP (g_object_new (GBEMOL_TYPE_APP, NULL));
535 
536 	return obj;
537 }
538 
gbemol_app_set_mpd(GbemolApp * obj,GbemolMpd * mpd)539 void gbemol_app_set_mpd (GbemolApp* obj, GbemolMpd* mpd)
540 {
541 	obj->mpd = mpd;
542 }
543 
gbemol_app_create_status_icon(GbemolApp * obj)544 void gbemol_app_create_status_icon (GbemolApp* obj)
545 {
546 	if (!obj->priv->status_icon)
547 	{
548 		obj->priv->status_icon = gtk_status_icon_new_from_file (ICON_FILE);
549 		g_signal_connect (G_OBJECT (obj->priv->status_icon), "popup-menu",
550 				G_CALLBACK (on_status_icon_popup_menu), obj);
551 		g_signal_connect (G_OBJECT (obj->priv->status_icon), "activate",
552 				G_CALLBACK (on_status_icon_activate), obj);
553 	}
554 }
555 
gbemol_app_destroy_status_icon(GbemolApp * obj)556 void gbemol_app_destroy_status_icon (GbemolApp* obj)
557 {
558 	g_object_unref (G_OBJECT (obj->priv->status_icon));
559 	obj->priv->status_icon = NULL;
560 }
561 
gbemol_app_connect_mpd(GbemolApp * app)562 void gbemol_app_connect_mpd (GbemolApp* app)
563 {
564 	if (!app->mpd)
565 		return;
566 
567 	if (gbemol_cfg_get_bool("MPD", "use_auth"))
568 		gbemol_mpd_connect_and_authenticate (app->mpd);
569 	else
570 		gbemol_mpd_connect (app->mpd);
571 
572 	gbemol_app_set_connected (app, gbemol_mpd_is_connected (app->mpd));
573 	if (gbemol_mpd_is_connected (app->mpd))
574 	{
575 		gbemol_library_start_constraints (app->lib);
576 		gbemol_playlist_update_songs (app->pls);
577 		gbemol_playlist_populate_playlists (app->pls);
578 	}
579 }
580 
581 
582 static GtkWidget*
gbemol_app_create_about_dialog(GbemolApp * app)583 gbemol_app_create_about_dialog (GbemolApp* app)
584 {
585 	GtkWidget* dlg;
586 
587 	dlg = gtk_about_dialog_new ();
588 
589 	gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (dlg), "gbemol");
590 	gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (dlg), GBEMOL_VERSION);
591 	gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (dlg), authors);
592 	gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (dlg), "http://gbemol.sourceforge.net");
593 	gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (dlg), app->priv->icon);
594 	gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG (dlg), _("translator-credits"));
595 	gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (dlg), _("A GTK+ Interface to MPD"));
596 
597 	return dlg;
598 }
599 
600 void
gbemol_app_destroy(GbemolApp * obj)601 gbemol_app_destroy (GbemolApp* obj)
602 {
603 
604 }
605 
606 void
gbemol_app_dispose(GObject * obj)607 gbemol_app_dispose (GObject* obj)
608 {
609 
610 }
611 
gbemol_app_set_cover_image(GbemolThreadData * data)612 static gpointer gbemol_app_set_cover_image(GbemolThreadData* data)
613 {
614 	GdkPixbuf *pix_img = NULL, *scaled;
615 	static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
616 
617 	gdk_threads_enter();
618     g_static_mutex_lock (&mutex);
619 
620 	pix_img = gbemol_utils_get_song_image(data->song);
621 	if (pix_img)
622 	{
623 		scaled = gdk_pixbuf_scale_simple (pix_img, 70, 70, GDK_INTERP_BILINEAR);
624 		gtk_image_set_from_pixbuf (GTK_IMAGE (data->app->priv->img_cover), scaled);
625 		g_object_unref(pix_img);
626 		g_object_unref(scaled);
627 		gtk_widget_show(data->app->priv->img_cover);
628 	}
629 	else
630 		gtk_widget_hide(data->app->priv->img_cover);
631 
632 	gbemol_mpd_free_song(data->song);
633 	g_free(data);
634 
635 	g_static_mutex_unlock (&mutex);
636 	gdk_threads_leave();
637 
638 	return NULL;
639 }
640 
641 void
gbemol_app_set_song(GbemolApp * app,GbemolMpdSong * song)642 gbemol_app_set_song (GbemolApp* app, GbemolMpdSong* song)
643 {
644 	gchar *str_title, *str_artist = NULL, *str_album = NULL;
645 	GtkWidget *lbl;
646 
647 	if (!song)
648 	{
649 		str_title = g_markup_printf_escaped (
650 				_("<span weight=\"ultrabold\" size=\"large\">Not Playing</span>"));
651 		gtk_window_set_title (GTK_WINDOW (app->priv->win_main), "gbemol");
652 		if (app->priv->status_icon)
653 			gtk_status_icon_set_tooltip (app->priv->status_icon, _("Not Playing"));
654 
655 		gtk_widget_hide (app->priv->btn_artist);
656 		gtk_widget_hide (app->priv->lbl_dash);
657 		gtk_widget_hide (app->priv->lbl_from);
658 		gtk_widget_hide (app->priv->btn_album);
659 	}
660 
661 	else
662 	{
663 		/* Window title */
664 		if (gbemol_mpd_song_is_stream (song))
665 			str_title = g_strdup_printf ("%s - %s", song->name, song->title);
666 		else
667 			str_title = g_strdup_printf ("%s - %s", song->artist, song->title);
668 
669 		gtk_window_set_title (GTK_WINDOW (app->priv->win_main), str_title);
670 
671 		if (app->priv->status_icon)
672 			gtk_status_icon_set_tooltip (app->priv->status_icon, str_title);
673 
674 		g_free (str_title);
675 
676 		/* It's a stream */
677 		if (gbemol_mpd_song_is_stream (song))
678 		{
679 			str_title = g_markup_printf_escaped ("<span weight=\"heavy\" size=\"large\">%s</span>",
680 					song->title);
681 			str_artist = NULL;
682 			str_album = g_markup_printf_escaped ("<span size=\"small\" weight=\"bold\">%s</span>",
683 					song->name);
684 
685 			gtk_widget_hide (app->priv->btn_artist);
686 			gtk_widget_hide (app->priv->lbl_dash);
687 		}
688 		else
689 		{
690 			str_album = g_markup_printf_escaped ("<span size=\"small\" weight=\"bold\">%s</span>",
691 					song->album);
692 			str_title = g_markup_printf_escaped ("<span weight=\"heavy\" size=\"large\">%s</span>",
693 				       song->title);
694 			str_artist = g_markup_printf_escaped ("<span size=\"large\" weight=\"bold\">%s</span>",
695 					song->artist);
696 
697 			gtk_widget_show (app->priv->btn_artist);
698 			gtk_widget_show (app->priv->lbl_dash);
699 			gtk_widget_show (app->priv->lbl_from);
700 			gtk_widget_show (app->priv->btn_album);
701 
702 			GbemolThreadData* data = g_malloc(sizeof(GbemolThreadData));
703 			data->app = app;
704 			data->song = gbemol_mpd_songdup(song);
705 
706 			g_thread_create((GThreadFunc)gbemol_app_set_cover_image, (gpointer) data, FALSE, NULL);
707 
708 		}
709 
710 	}
711 
712 	lbl = gtk_bin_get_child (GTK_BIN (app->priv->btn_title));
713 	gtk_label_set_markup (GTK_LABEL (lbl), str_title);
714 	lbl = gtk_bin_get_child (GTK_BIN (app->priv->btn_artist));
715 	gtk_label_set_markup (GTK_LABEL (lbl), str_artist);
716 	lbl = gtk_bin_get_child (GTK_BIN (app->priv->btn_album));
717 	gtk_label_set_markup (GTK_LABEL (lbl), str_album);
718 
719 	/* Set the info tab */
720 	g_free (str_title);
721 	g_free (str_artist);
722 	g_free (str_album);
723 
724 }
725 
gbemol_app_set_state(GbemolApp * app)726 void gbemol_app_set_state (GbemolApp* app)
727 {
728 	GtkWidget *img;
729 
730 	if (gbemol_mpd_is_connected (app->mpd))
731 	{
732 		switch (gbemol_mpd_get_state(app->mpd))
733 		{
734 			case MPD_STATUS_STATE_PLAY:
735 				img = gtk_image_new_from_stock ("gtk-media-pause", GTK_ICON_SIZE_BUTTON);
736 				gtk_button_set_image (GTK_BUTTON (app->priv->btn_play), img);
737 				gtk_image_set_from_stock (GTK_IMAGE (app->priv->img_item_play), "gtk-media-pause",
738 						GTK_ICON_SIZE_BUTTON);
739 				gtk_tooltips_set_tip (app->priv->tips, app->priv->btn_play, _("Pause"), NULL);
740 				gtk_widget_set_sensitive (app->priv->scl_song, TRUE);
741 				gtk_widget_set_sensitive (app->priv->lbl_time, TRUE);
742 				break;
743 			default:
744 				if (gbemol_mpd_get_state(app->mpd) != MPD_STATUS_STATE_PAUSE)
745 					gtk_range_set_value (GTK_RANGE (app->priv->scl_song), 0.0);
746 				img = gtk_image_new_from_stock ("gtk-media-play", GTK_ICON_SIZE_BUTTON);
747 				gtk_button_set_image (GTK_BUTTON (app->priv->btn_play), img);
748 				gtk_image_set_from_stock (GTK_IMAGE (app->priv->img_item_play),"gtk-media-play", GTK_ICON_SIZE_BUTTON);
749 				gtk_tooltips_set_tip (app->priv->tips, app->priv->btn_play, _("Play"), NULL);
750 				gtk_widget_set_sensitive (app->priv->scl_song, FALSE);
751 				gtk_widget_set_sensitive (app->priv->lbl_time, FALSE);
752 				gtk_label_set_text (GTK_LABEL (app->priv->lbl_time), "00:00");
753 				break;
754 		}
755 	}
756 }
757 
758 void
gbemol_app_set_connected(GbemolApp * app,gboolean connected)759 gbemol_app_set_connected (GbemolApp* app, gboolean connected)
760 {
761 	GbemolMpdSong* song;
762 
763 	gtk_widget_set_sensitive (app->priv->mnu_item_connect, !connected);
764 	gtk_widget_set_sensitive (app->priv->mnu_item_disconnect, connected);
765 
766 	if (connected)
767 	{
768 		song = gbemol_mpd_get_current_song (app->mpd);
769 		gbemol_app_set_song (app, song);
770 		gbemol_info_set_song (app->info, song);
771 		gbemol_mpd_free_song (song);
772 		gbemol_app_set_state (app);
773 	}
774 	else
775 		gbemol_app_set_song (app, NULL);
776 
777 	gbemol_playlist_set_sensitive (app->pls, connected);
778 	gbemol_library_set_sensitive (app->lib, connected);
779 
780 	gtk_widget_set_sensitive (app->priv->btn_previous, connected);
781 	gtk_widget_set_sensitive (app->priv->btn_play, connected);
782 	gtk_widget_set_sensitive (app->priv->btn_next, connected);
783 	gtk_widget_set_sensitive (app->priv->btn_volume, connected);
784 	gtk_widget_set_sensitive (app->priv->btn_artist, connected);
785 	gtk_widget_set_sensitive (app->priv->btn_album, connected);
786 	gtk_widget_set_sensitive (app->priv->btn_title, connected);
787 	gtk_widget_set_sensitive (app->priv->mnu_item_random, connected);
788 	gtk_widget_set_sensitive (app->priv->mnu_item_repeat, connected);
789 	gtk_widget_set_sensitive (app->notebook, connected);
790 }
791 
792 void
gbemol_app_set_time(GbemolApp * app,int elapsed,int total)793 gbemol_app_set_time (GbemolApp* app, int elapsed, int total)
794 {
795 	gchar *str;
796 	double prog;
797 
798 	str = g_markup_printf_escaped ("<span weight=\"ultrabold\">%02d:%02d/%02d:%02d</span>",
799 			elapsed/60, elapsed%60, total / 60, total % 60);
800 	gtk_label_set_markup (GTK_LABEL (app->priv->lbl_time), str);
801 	g_free (str);
802 
803 	prog = ((double) elapsed) / ((double) total);
804 	if (app->priv->update_scl_song)
805 		gtk_range_set_value (GTK_RANGE (app->priv->scl_song), prog);
806 	app->priv->update_scl_song = !app->priv->update_scl_song;
807 
808 }
809 
gbemol_app_set_volume(GbemolApp * app,gint volume)810 void gbemol_app_set_volume (GbemolApp* app, gint volume)
811 {
812 	if ((volume >= 0) && (volume <= 100))
813 		bacon_volume_button_set_value (BACON_VOLUME_BUTTON (app->priv->btn_volume), (float) volume);
814 }
815 
gbemol_app_set_random(GbemolApp * app,gboolean random)816 void gbemol_app_set_random (GbemolApp* app, gboolean random)
817 {
818 	if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (app->priv->mnu_item_random)) != random)
819 		gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (app->priv->mnu_item_random), random);
820 }
821 
gbemol_app_set_repeat(GbemolApp * app,gboolean repeat)822 void gbemol_app_set_repeat (GbemolApp* app, gboolean repeat)
823 {
824 	if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (app->priv->mnu_item_repeat)) != repeat)
825 		gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (app->priv->mnu_item_repeat), repeat);
826 }
827 
gbemol_app_set_stick(GbemolApp * app,gboolean stick)828 void gbemol_app_set_stick (GbemolApp* app, gboolean stick)
829 {
830 	if (stick)
831 		gtk_window_stick (GTK_WINDOW (app->priv->win_main));
832 	else
833 		gtk_window_unstick (GTK_WINDOW (app->priv->win_main));
834 }
835 
gbemol_app_set_top(GbemolApp * app,gboolean top)836 void gbemol_app_set_top (GbemolApp* app, gboolean top)
837 {
838 	gtk_window_set_keep_above (GTK_WINDOW (app->priv->win_main), top);
839 }
840 
gbemol_app_show(GbemolApp * app)841 void gbemol_app_show (GbemolApp* app)
842 {
843 	gtk_window_present(GTK_WINDOW(app->priv->win_main));
844 }
845 
gbemol_app_hide(GbemolApp * app)846 void gbemol_app_hide (GbemolApp* app)
847 {
848 	gtk_widget_hide (app->priv->win_main);
849 }
850 
851 /*
852  * Switches the app to full mode
853  */
gbemol_app_full_mode(GbemolApp * app)854 void gbemol_app_full_mode (GbemolApp* app)
855 {
856 	gtk_expander_set_expanded (GTK_EXPANDER (app->priv->expander), TRUE);
857 }
858 
859 /*
860  * Switch to compact mode
861  */
gbemol_app_compact_mode(GbemolApp * app)862 void gbemol_app_compact_mode (GbemolApp* app)
863 {
864 
865 	gtk_expander_set_expanded (GTK_EXPANDER (app->priv->expander), FALSE);
866 }
867 
868 /* Callbacks */
on_win_main_delete_event(GtkWidget * w,GdkEventButton * event,GbemolApp * data)869 static gboolean on_win_main_delete_event (GtkWidget *w, GdkEventButton *event, GbemolApp* data)
870 {
871 	if (gbemol_cfg_get_bool("app", "close-tray") && gbemol_cfg_get_bool("app", "status-icon"))
872 	{
873 		gtk_widget_hide (data->priv->win_main);
874 		gbemol_cfg_set_bool("win_main", "visible", TRUE);
875 		return TRUE;
876 	}
877 	else
878 	{
879 		g_object_unref (G_OBJECT(data));
880 		gbemol_app_destroy (data);
881 		gtk_main_quit ();
882 		return FALSE;
883 	}
884 }
885 
on_btn_previous_clicked(GtkButton * button,GbemolApp * app)886 static void on_btn_previous_clicked (GtkButton *button, GbemolApp* app)
887 {
888 	gbemol_mpd_player_previous (app->mpd);
889 }
890 
891 
on_btn_play_clicked(GtkButton * button,GbemolApp * app)892 static void on_btn_play_clicked (GtkButton *button, GbemolApp* app)
893 {
894 	gbemol_mpd_player_pause (app->mpd);
895 }
896 
on_btn_next_clicked(GtkButton * button,GbemolApp * app)897 static void on_btn_next_clicked (GtkButton *button, GbemolApp* app)
898 {
899 	gbemol_mpd_player_next (app->mpd);
900 }
901 
on_evt_button_press_event(GtkWidget * w,GdkEventButton * event,GbemolApp * app)902 static gboolean on_evt_button_press_event (GtkWidget *w, GdkEventButton *event, GbemolApp* app)
903 {
904 	if (event->type == GDK_BUTTON_PRESS)
905 		if (event->button == 3)
906 		{
907 			gtk_menu_popup (GTK_MENU (app->priv->mnu_main),
908 					NULL, NULL, NULL, NULL,
909 					event->button, event->time);
910 			return TRUE;
911 		}
912 
913 	return FALSE;
914 }
915 
on_mnu_random_activate(GtkWidget * w,GbemolApp * app)916 static void on_mnu_random_activate (GtkWidget* w, GbemolApp* app)
917 {
918 	gboolean active;
919 
920 	active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM(w));
921 	gbemol_mpd_set_random (app->mpd, active);
922 }
923 
on_mnu_repeat_activate(GtkWidget * w,GbemolApp * app)924 static void on_mnu_repeat_activate (GtkWidget* w, GbemolApp* app)
925 {
926 	gboolean active;
927 
928 	active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM(w));
929 	gbemol_mpd_set_repeat (app->mpd, active);
930 }
931 
on_mnu_about_activate(GtkWidget * w,GbemolApp * app)932 static void on_mnu_about_activate (GtkWidget* w, GbemolApp* app)
933 {
934 	GtkWidget* dlg;
935 	dlg = gbemol_app_create_about_dialog (app);
936 
937 	gtk_widget_show (dlg);
938 	gtk_dialog_run (GTK_DIALOG (dlg));
939 	gtk_widget_destroy (dlg);
940 }
941 
942 static void
on_mnu_connect_activate(GtkWidget * b,GbemolApp * app)943 on_mnu_connect_activate (GtkWidget* b, GbemolApp* app)
944 {
945 	if (gbemol_mpd_is_connected (app->mpd))
946 		gbemol_mpd_disconnect (app->mpd);
947 	else
948 		gbemol_app_connect_mpd (app);
949 
950 	gbemol_app_set_connected (app, gbemol_mpd_is_connected (app->mpd));
951 }
952 
gbemol_app_win_main_resize_idled(GbemolApp * app)953 static gboolean gbemol_app_win_main_resize_idled (GbemolApp* app)
954 {
955 	gint height, width, x, y;
956 
957 	if (gbemol_cfg_get_int ("win_main", "expanded"))
958 	{
959 		height = gbemol_cfg_get_int ("win_main", "height_big");
960 		width = gbemol_cfg_get_int ("win_main", "width_big");
961 		x = gbemol_cfg_get_int ("win_main", "x_big");
962 		y = gbemol_cfg_get_int ("win_main", "y_big");
963 	}
964 	else
965 	{
966 		height = gbemol_cfg_get_int ("win_main", "height_small");
967 		width = gbemol_cfg_get_int ("win_main", "width_small");
968 		x = gbemol_cfg_get_int ("win_main", "x_small");
969 		y = gbemol_cfg_get_int ("win_main", "y_small");
970 		gtk_window_unmaximize (GTK_WINDOW (app->priv->win_main));
971 	}
972 
973 	if (!height)
974 		height = GBEMOL_DEFAULT_HEIGHT;
975 	if (!width)
976 		width = GBEMOL_DEFAULT_WIDTH;
977 
978 
979 	gtk_widget_set_size_request (app->priv->win_main, width, height);
980 	gtk_window_resize (GTK_WINDOW (app->priv->win_main), width, height);
981 	gtk_widget_set_size_request (app->priv->win_main, 0, 0);
982 
983 	gtk_window_move(GTK_WINDOW(app->priv->win_main), x, y);
984 
985 	return FALSE;
986 }
987 
on_expander_activate(GtkExpander * e,GbemolApp * app)988 static void on_expander_activate (GtkExpander* e, GbemolApp* app)
989 {
990 	gint h_s, h_b, width, x, y;
991 
992 	h_s = gbemol_cfg_get_int ("win_main", "height_small");
993 	h_b = gbemol_cfg_get_int ("win_main", "height_big");
994 
995 	gtk_window_get_position(GTK_WINDOW(app->priv->win_main), &x, &y);
996 	if (!gtk_expander_get_expanded (e))
997 	{
998 		gtk_window_get_size (GTK_WINDOW (app->priv->win_main), &width, &h_s);
999 		gbemol_cfg_set_int ("win_main", "height_small", h_s);
1000 		gbemol_cfg_set_int ("win_main", "width_small", width);
1001 		gbemol_cfg_set_int ("win_main", "x_small", x);
1002 		gbemol_cfg_set_int ("win_main", "y_small", y);
1003 		gbemol_cfg_set_int ("win_main", "expanded", 1);
1004 
1005 		if (!h_b)
1006 		{
1007 			h_b = h_s * 4;
1008 			gbemol_cfg_set_int ("win_main", "height_big", h_b);
1009 		}
1010 	}
1011 	else
1012 	{
1013 		/* Save sizes */
1014 		gtk_window_get_size (GTK_WINDOW (app->priv->win_main), &width, &h_b);
1015 		gbemol_cfg_set_int ("win_main", "height_big", h_b);
1016 		gbemol_cfg_set_int ("win_main", "width_big", width);
1017 		gbemol_cfg_set_int ("win_main", "x_big", x);
1018 		gbemol_cfg_set_int ("win_main", "y_big", y);
1019 		gbemol_cfg_set_int ("win_main", "expanded", 0);
1020 	}
1021 
1022 	g_idle_add ((GSourceFunc) gbemol_app_win_main_resize_idled, app);
1023 }
1024 
1025 
on_scl_song_change_value(GtkRange * range,GtkScrollType * scroll,gdouble value,GbemolApp * app)1026 static gboolean on_scl_song_change_value (GtkRange* range, GtkScrollType* scroll, gdouble value, GbemolApp* app)
1027 {
1028 	gchar* str;
1029 	gint t;
1030 
1031 	app->priv->update_scl_song = FALSE;
1032 
1033 	t = (gint) (gbemol_mpd_get_total_time (app->mpd) * value);
1034 	if (t < 0)
1035 		return FALSE;
1036 
1037 	str = g_markup_printf_escaped ("%02d:%02d", t / 60, t % 60);
1038 	gtk_label_set_markup (GTK_LABEL (app->priv->lbl_time), str);
1039 	g_free (str);
1040 
1041 	gbemol_mpd_seek (app->mpd, gbemol_mpd_get_current_id (app->mpd), t);
1042 
1043 	app->priv->update_scl_song = TRUE;
1044 
1045 	return FALSE;
1046 }
1047 
on_mnu_quit_activate(GtkWidget * m,GbemolApp * app)1048 static void on_mnu_quit_activate (GtkWidget* m, GbemolApp* app)
1049 {
1050 	g_object_unref (G_OBJECT (app));
1051 	gtk_main_quit ();
1052 }
1053 
on_mnu_preferences_activate(GtkWidget * m,GbemolApp * data)1054 static void on_mnu_preferences_activate (GtkWidget* m, GbemolApp* data)
1055 {
1056 	gbemol_preferences_new (data);
1057 }
1058 
1059 static void
on_status_icon_popup_menu(GtkStatusIcon * icon,guint button,guint activate_time,GbemolApp * app)1060 on_status_icon_popup_menu (GtkStatusIcon* icon, guint button, guint activate_time, GbemolApp* app)
1061 {
1062 	GtkMenu* mnu = GTK_MENU (app->priv->mnu_status);
1063 
1064 	gtk_menu_popup (mnu, NULL, NULL, gtk_status_icon_position_menu, icon, button, activate_time);
1065 }
1066 
1067 static void
on_status_icon_activate(GtkStatusIcon * icon,GbemolApp * app)1068 on_status_icon_activate (GtkStatusIcon *icon, GbemolApp* app)
1069 {
1070 	if (GTK_WIDGET_VISIBLE (app->priv->win_main))
1071 		gtk_widget_hide (app->priv->win_main);
1072 	else
1073 		gtk_widget_show (app->priv->win_main);
1074 	gbemol_cfg_set_int ("win_main", "visible", !GTK_WIDGET_VISIBLE (app->priv->win_main));
1075 }
on_btn_volume_value_changed(BaconVolumeButton * btn,GbemolApp * app)1076 static void on_btn_volume_value_changed (BaconVolumeButton *btn, GbemolApp* app)
1077 {
1078 	gbemol_mpd_set_volume (app->mpd, (int) bacon_volume_button_get_value (btn));
1079 }
1080 
on_btn_title_clicked(GtkButton * button,GbemolApp * app)1081 static void on_btn_title_clicked (GtkButton *button, GbemolApp* app)
1082 {
1083 	GbemolMpdSong *song = gbemol_mpd_get_current_song (app->mpd);
1084 	/* It's a stream, do nothing */
1085 	if (!song->artist && song->name && (song->time == MPD_SONG_NO_TIME))
1086 		return;
1087 	gtk_notebook_set_current_page (GTK_NOTEBOOK (app->notebook), 2);
1088 	gbemol_info_set_song (app->info, song);
1089 	gbemol_mpd_free_song (song);
1090 }
1091 
on_btn_album_clicked(GtkButton * button,GbemolApp * app)1092 static void on_btn_album_clicked (GtkButton *button, GbemolApp* app)
1093 {
1094 	GbemolMpdSong *song = gbemol_mpd_get_current_song (app->mpd);
1095 
1096 	/* It's a stream, do nothing */
1097 	if (!song->artist && song->name && (song->time == MPD_SONG_NO_TIME))
1098 		return;
1099 
1100 	gtk_notebook_set_current_page (GTK_NOTEBOOK (app->notebook), 2);
1101 	gbemol_info_set_album (app->info, song->album, song->artist);
1102 	gbemol_mpd_free_song (song);
1103 }
1104 
on_btn_artist_clicked(GtkButton * button,GbemolApp * app)1105 static void on_btn_artist_clicked (GtkButton *button, GbemolApp* app)
1106 {
1107 	GbemolMpdSong *song = gbemol_mpd_get_current_song (app->mpd);
1108 	gtk_notebook_set_current_page (GTK_NOTEBOOK (app->notebook), 2);
1109 	gbemol_info_set_artist (app->info, song->artist);
1110 	gbemol_mpd_free_song (song);
1111 
1112 }
1113 
on_notebook_page_switch(GtkNotebook * n,GtkNotebookPage * p,gint page_num,GbemolApp * app)1114 static void on_notebook_page_switch (GtkNotebook* n, GtkNotebookPage* p, gint page_num, GbemolApp* app)
1115 {
1116 }
1117 
gbemol_app_error_dialog_new(GbemolApp * app,gchar * primary_msg,gchar * secondary_msg)1118 void gbemol_app_error_dialog_new (GbemolApp* app, gchar* primary_msg, gchar* secondary_msg)
1119 {
1120 	GtkWidget* dlg;
1121 	gchar *str1 = NULL, *str2 = NULL;
1122 
1123 	if (primary_msg)
1124 		str1 = g_markup_printf_escaped ("<span size=\"large\" weight=\"bold\">%s</span>", primary_msg);
1125 	if(secondary_msg)
1126 		str2 = g_strdup (secondary_msg);
1127 
1128 	dlg = gtk_message_dialog_new (GTK_WINDOW (app->priv->win_main),
1129 			GTK_DIALOG_DESTROY_WITH_PARENT,
1130                         GTK_MESSAGE_ERROR,
1131                         GTK_BUTTONS_CLOSE,
1132                         NULL);
1133 
1134 	if (str1)
1135 		gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dlg), str1);
1136 	if (str2)
1137 		gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dlg), str2);
1138 
1139 	gtk_dialog_run (GTK_DIALOG (dlg));
1140 	gtk_widget_destroy (dlg);
1141 
1142 	g_free (str1);
1143 	g_free (str2);
1144 }
1145 
on_btn_reconnect_activate(GtkButton * button,GtkDialog * dlg)1146 static void on_btn_reconnect_activate (GtkButton *button, GtkDialog* dlg)
1147 {
1148 	gtk_dialog_response (dlg, GTK_RESPONSE_ACCEPT);
1149 }
1150 
1151 
gbemol_app_reconnect_dialog_new(GbemolApp * app,gchar * msg)1152 void gbemol_app_reconnect_dialog_new (GbemolApp* app, gchar* msg)
1153 {
1154 	GtkWidget* dlg, *btn;
1155 	gchar *str1 = NULL, *str2 = NULL;
1156 
1157 	str1 = g_markup_printf_escaped (_("<span size=\"large\" weight=\"bold\">Disconnected</span>"));
1158 	str2 = g_strdup (msg);
1159 
1160 	btn = gbemol_utils_make_button (_("Reconnect"), GTK_STOCK_REFRESH);
1161 	dlg = gtk_message_dialog_new (GTK_WINDOW (app->priv->win_main),
1162 			GTK_DIALOG_DESTROY_WITH_PARENT,
1163                         GTK_MESSAGE_ERROR,
1164                         GTK_BUTTONS_CLOSE,
1165                         NULL);
1166 	gtk_box_pack_end (GTK_BOX (GTK_DIALOG(dlg)->action_area), btn, FALSE, FALSE, 5);
1167 	g_signal_connect (G_OBJECT (btn), "clicked", G_CALLBACK (on_btn_reconnect_activate), dlg);
1168 	g_signal_connect (G_OBJECT (btn), "activate", G_CALLBACK (on_btn_reconnect_activate), dlg);
1169 	gtk_widget_show_all (btn);
1170 
1171 	gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dlg), str1);
1172 	gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dlg), str2);
1173 
1174 	if (gtk_dialog_run (GTK_DIALOG (dlg)) == GTK_RESPONSE_ACCEPT)
1175 		gbemol_app_connect_mpd (app);
1176 
1177 	gtk_widget_destroy (dlg);
1178 	g_free (str1);
1179 	g_free (str2);
1180 }
1181 
1182 
1183 
1184