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